我写了一个Java应用程序,在其中我将日期从特定年份的1月1日00:00开始。然后,我将一天的时间增加355次,并打印出一路上的结果。我试图了解时区是如何在夏令时周围工作的,以及在进入夏令时时,增加1天是否会将时间从午夜转移到凌晨1点。我的代码看起来像:
TimeZone tz = TimeZone.getDefault();
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss z");
sdf.setTimeZone(tz);
Calendar cal = Calendar.getInstance(tz);
cal.set(2008, 0, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
for ( int i = 0; i < 355; i++ ) {
System.out.println(sdf.format(cal.getTime()));
cal.add(Calendar.DAY_OF_MONTH, 1);
}
当在我的默认时区(美国东部)运行时,输出看起来就像我所期望的那样:
01/01/2008 00:00:00 EST
01/02/2008 00:00:00 EST
01/03/2008 00:00:00 EST
01/04/2008 00:00:00 EST
...
当我进入夏令时时,我会得到
03/10/2008 00:00:00 EDT
03/11/2008 00:00:00 EDT
03/12/2008 00:00:00 EDT
当我使用一个观测东欧夏令时间的时区时(在这种情况下,我选择了非洲/开罗时区),我得到的输出是:
01/01/2008 00:00:00 EET
01/02/2008 00:00:00 EET
01/03/2008 00:00:00 EET
01/04/2008 00:00:00 EET
01/05/2008 00:00:00 EET
但当我进入东欧夏季时,我会得到:
04/25/2008 01:00:00 EEST
04/26/2008 01:00:00 EEST
04/27/2008 01:00:00 EEST
奇怪的是,当EEST结束时,我仍然得到
08/29/2008 01:00:00 EET
08/30/2008 01:00:00 EET
我很困惑为什么这些时区的行为不同,如果这是非洲/开罗时区的错误,或者我误解了时区的工作方式。。。
如对此有任何见解,我们将不胜感激。
开罗时区在午夜变为夏令时,因此跳过了2008年4月25日午夜之间的一小时。。。挂钟响了:
04/24/2008 23:59:58
04/24/2008 23:59:59
04/25/2008 01:00:00
04/25/2008 01:00:01
试着在美东时区从凌晨2点开始一次增加一天,你会看到同样的情况——在某个时候会变到03:00。
目前尚不清楚你到底想实现什么——我倾向于认为,最好在特定时区的日期/时间中添加"经验毫秒数",或者在本地日期/时间上添加"逻辑毫秒数"(不考虑时区)。当您从本地时间转换到特定区域的时间时,您需要考虑歧义(一个本地时间发生两次)或跳过(一个当地时间根本不发生)的可能性。
为了增加乐趣,去年萨摩亚完全跳过了12月30日,因为它的时区从-14改为+10…
编辑:哦,我的标准建议适用:放弃java.util.Calendar/Date,使用Joda Time