Java日期計算天數差需要注意的問題

最近在用Java實現公曆轉農曆,當我在網上查找農曆轉換算法的時候,發現很多都是這樣做的:

使用歷年觀測的農曆數據集,以1900-2099年之間爲例,數據集包含每年農曆的大小月定義,以及閏月是哪一個月。這樣我們就可以用1900年到今天的天數,減去農曆從1900年以來N年的總天數,就可以得到今年農曆已經過去的天數,同樣也可以算出今年農曆這個農曆月已經過去的天數,就可以得到幾月初幾。

但是其中,我們需要計算天數之差,很多算法都是這麼計算的:

比如我們要計算2014年12月16日(後面用日期A代替)與1900年1月31日(用日期B代替)之間的天數差,先將A和B分別轉化爲時間紀元起點(1970年1月1日 0 時)的時間戳毫秒數,然後計算毫秒數只差,再轉化爲天數只差,公式:

天數 = 毫秒數/1000/3600/24

long between_days = (long)(time2-time1)/(1000*3600*24);

乍看上去,沒有什麼異常,但是我在單元測試的時候發現,某些數據會出現異常。

異常數據舉例:1990.04.15,1990.04.16分別與1900.01.31之間的天數差,結果都是32946天。

究其原因,這樣算出來的天數只差是小數,取整的時候會產生舍入誤差。

如果將long換成double,我們可以看到結果分別是32946.00413194444和32946.96246527778,由於取整的直接截斷效果,都變成了32946,這樣後面計算農曆的時候,就變成了同一天。

因爲網絡上有很多地方都是使用這種算法計算,比如某些Android日曆控件,仔細檢查就會發現轉換錯誤的問題。

Java中目前日期和時間主要是Date和Calender兩個類,而且官方推薦用Calender類,但是實際上,這個類用法比較反人類,至於爲什麼反人類大家用過應該比較清楚。

關於日期,推薦使用Joda-Time庫,開源的,比起Calender來說,方便很多,計算天數差只需要下面這樣就可以了:

  DateTimeZone zone = DateTimeZone.forID("Asia/Shanghai");
  DateTime nowTime = new DateTime(1900, 1, 31, 0, 0, 0,zone);
  DateTime futureTime = new DateTime(1990, 4, 16, 0, 0, 0,zone);
  int days = Days.daysBetween(nowTime, futureTime).getDays();
  System.out.println("天數:"+String.valueOf(days));

查看源碼可知,Joda-time同樣是計算毫秒數只差,但是測試結果比最開始算法要精確,具體是如果取整,讀者可以去研究它的源碼。至於其他優勢,我就不說了,附上官網地址:http://www.joda.org/joda-time/

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章