Java里头的夏令时(转载自http://hi.baidu.com/jiyangguang666/blog/item/c9ada1cfb124f034f9dc)

Java里面的夏令时(转载自http://hi.baidu.com/jiyangguang666/blog/item/c9ada1cfb124f034f9dc)
如下的java代码

1. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:SS");
2. String sTime = "1991-04-07 00:00:00";
3. Date time = sdf.parse(sTime);
4. Calendar cd = Calendar.getInstance();
5. cd.setTime(time);
6. cd.add(Calendar.DATE, 7);
7. time = cd.getTime();
8. System.out.println(sdf.format(time));

在运行后,没有得到预期的

1991-04-14 00:00:00

而是

1991-04-14 01:00:00

凭空多出来了1小时


根据火龙果的研究成果,这个是夏令时哦,使用 Calendar.DST_OFFSET 可以获得偏移量。

夏令时是通过 TimeZone 的子类 sun.util.calendar.ZoneInfo 实现的。

ZoneInfo 中的数据存放于 %JRE_HOME%/lib/zi 目录中。

我们机器一般采用的时区名称为 Asia/Shanghai,相对应的时区信息文件位于:

%JRE_HOME%/lib/zi/Asia/Shanghai 中,这是一个二进制文件。

通过 sun.util.calendar.ZoneInfoFile 的解析,可以获得需要采用夏令时的时间为:

Java code

1940 - 06 - 03 01 : 00 : 00 ~ 1940 - 09 - 30 23 : 00 : 00
1941 - 03 - 16 01 : 00 : 00 ~ 1941 - 09 - 30 23 : 00 : 00
1986 - 05 - 04 01 : 00 : 00 ~ 1986 - 09 - 13 23 : 00 : 00
1987 - 04 - 12 01 : 00 : 00 ~ 1987 - 09 - 12 23 : 00 : 00
1988 - 04 - 10 01 : 00 : 00 ~ 1988 - 09 - 10 23 : 00 : 00
1989 - 04 - 16 01 : 00 : 00 ~ 1989 - 09 - 16 23 : 00 : 00
1990 - 04 - 15 01 : 00 : 00 ~ 1990 - 09 - 15 23 : 00 : 00
1991 - 04 - 14 01 : 00 : 00 ~ 1991 - 09 - 14 23 : 00 : 00


前段表示那一天开始的时间,也就是说那一天的 0 点在该时区中是不存在。

后段表示那一天结束的时间,这个时间计算很复杂:

如果当前时间为:1986-09-13 23:00:00,增加 1 小时后为 1986-09-14 00:00:00
如果当前时间为:1986-09-13 22:00:00,增加 2 小时后为 1986-09-13 23:00:00,因为 1986-09-13 23:00:00 是夏令时结束时间,时钟需要回拨。

由于每个时区的夏令时都不一样,编程语言中的夏令时算法非常复杂。

幸好中国从 1992 年开始停止使用夏令时。

这里是夏令时时区数据页面:http://www.twinsun.com/tz/tz-link.htm
这里可以找到各时区最新的夏令时数据:ftp://elsie.nci.nih.gov/pub/