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/

 

 

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页