java开发1:用Calender来解决夏令时(daylight saving time )等引起的错误

1. 遇到问题

在解决了由于公司邮件地址变化造成的ad system report发送的bug之后,这两天,组内的daily report系统又出问题了。现象是,邮件发了,可是附件中的文件却是空的。
闲话不说,先看看log。上server上一看,也没有什么exception log,甚是奇怪。仔细研究一下后,发现是由于时间不匹配造成的问题。原来,这个发邮件的cronjob 每天定时的找一个文件,并发送出来。而这个文件是有固定格式的文件名字的:reprot_yyyy-MM-dd1_yyyy-MM-dd2.csv. 正常的情况下,yyyy-MM-dd1是一个比yyyy-MM-dd2早一个月(固定30天)的时间。比如yyyy-MM-dd2是2012-02-14, 那么 yyyy-MM-dd1就是2012-01-14。 正好相差30天。现在发现系统的情况是,如yyyy-MM-dd2是2012-03-14的时候,yyyy-MM-dd1是却变成了2012-03-13, 多了一天。越是问题就这样出现了,存在的文件名字叫:reprot_2012-02-13_2012-03-14.csv, 而发邮件时候需要找的文件名字却叫 reprot_2012-02-14_2012-03-14.csv。
问题是找出来了,原因却还没有。由于系统是刚刚出现问题,之前一直是好好的,怎么突然就出了问题了呢,我和同事怎么也想不明白。突然间想到,前几天US的哥们发过邮件说他那启用夏令时了。当时没怎么在意,心想也就是开会时间稍微调整下,别的跟我无关。现在夏令时的调整就成了最可疑的因素,因为这两天就他发生变化了啊,于是决定彻查之。


2. 夏令时及其操作

什么叫夏令时?下面是从百度百科上抄的一段。
夏时制(Daylight Saving Time:DST),又称“日光节约时制”和“夏令时间”,是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间提前一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。
US的夏令时呢,从每年3月份的第二个礼拜天的2时开始(比如2012-03-11),到到11月第一个星期日的2时结束。而出问题的第一天正好是3月12日,嗯,更加可疑。
那么夏令时是怎么操作的呢,举个例子,夏令时开始的时候,比如2012-03-11 2:00:00的时候,认为的将时间直接变成2012-03-11 3:00:00。没错,直接多加了一个小时。那么造成的后果呢,对,2012-03-11这一天只有23个小时了。类似的,到了夏令时结束的时候,人为的将时间直接往后拨一个小时,同样,那一天有25个小时。总的时间是找补回来了,但是对于计算机来说可就有点麻烦了,尤其在计算时间日期的时候。现在的大多数计算机系统,都可以设置系统是否启用夏令时,从而系统可以自己调配。在程序中涉及到时间的操作,也要小心,如果2011-03-11这一天,你算成24小时的话,时间就错啦。这个也是我们report程序中bug所在。


3. Bug原因以及修复

上面是理论的分析,要找的bug的真正原因,只有一个方法:调试。production上可不是说调试就调试啊,好在jvm有一个绝招,远程调试。有了它,我们就可以再production环境下调试啦。关于远程调试,这里就不做介绍,之前发过一个资料,专门说这个问题。

调试的时候,就发现了,当yyyy-MM-dd2是2012-02-14 00:00:00时候, 那么 yyyy-MM-dd1不是2012-01-14 00:00:00,而是2012-01-13 23:00:00。为什么多了一个小时,夏令时嘛,本来那天只有23个小时,结果算成了24个小时。 再看代码,果如其然,使用的是极其粗暴的方式来求取30天前的时间的。

longearlierDate = curDate.getTime() - (30-1) * 24 * 3600*1000

解决办法呢,也很简单。java.util 提供了以很好的日历类 Calender,封装了关于日期的计算,代码如下:

Calender cal = Calender.getInstance();
cal.clear();
cal.setDate(curDate);
cal.add(Calender.DAY_OF_MONTH, -29);
Date earlierDate = cal.getDate()

4. 小结:

通过这bug,发现了Calender类的巨大作用。Calender是一个日历的概念,相对于Date是一个时间点来说。Calender更加具体的对应到了年月日,而这个对应过程我们知道与时区、闰月、闰年、夏令时等很多细节相关。于是当需要对日期进行操作时,要首先想到一个强大的类Calender。

你可能感兴趣的:(java,exception,Date,report,System,日历)