TimeZone.setDefault(TimeZone.getTimeZone("BET"));
Locale.setDefault(Locale.ENGLISH);
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzzz");
Date d0 = sdf1.parse("2037-10-17 23:00:00.000");
Date d1 = sdf1.parse("2037-10-17 23:00:00.001");
Date d2 = sdf1.parse("2037-10-17 23:59:59.999");
Date d3 = sdf1.parse("2037-10-18 00:00:00.000");
Date d4 = sdf1.parse("2037-10-18 00:00:00.001");
Date d5 = sdf1.parse("2037-10-18 00:59:59.999");
Date d6 = sdf1.parse("2037-10-18 01:00:00.000");
Date d7 = sdf1.parse("2037-10-18 01:00:00.001");
Date d8 = sdf1.parse("2037-10-18 01:59:59.999");
Date d9 = sdf1.parse("2037-10-18 02:00:00.000");
System.out.println(sdf2.format(d0) + "(" + d0.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d0) + ", offset: " + TimeZone.getDefault().getOffset(d0.getTime()));
System.out.println(sdf2.format(d1) + "(" + d1.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d1) + ", offset: " + TimeZone.getDefault().getOffset(d1.getTime()));
System.out.println(sdf2.format(d2) + "(" + d2.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d2) + ", offset: " + TimeZone.getDefault().getOffset(d2.getTime()));
System.out.println(sdf2.format(d3) + "(" + d3.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d3) + ", offset: " + TimeZone.getDefault().getOffset(d3.getTime()));
System.out.println(sdf2.format(d4) + "(" + d4.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d4) + ", offset: " + TimeZone.getDefault().getOffset(d4.getTime()));
System.out.println(sdf2.format(d5) + "(" + d5.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d5) + ", offset: " + TimeZone.getDefault().getOffset(d5.getTime()));
System.out.println(sdf2.format(d6) + "(" + d6.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d6) + ", offset: " + TimeZone.getDefault().getOffset(d6.getTime()));
System.out.println(sdf2.format(d7) + "(" + d7.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d7) + ", offset: " + TimeZone.getDefault().getOffset(d7.getTime()));
System.out.println(sdf2.format(d8) + "(" + d8.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d8) + ", offset: " + TimeZone.getDefault().getOffset(d8.getTime()));
System.out.println(sdf2.format(d9) + "(" + d9.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d9) + ", offset: " + TimeZone.getDefault().getOffset(d9.getTime()));
输出
2037-10-17 23:00:00.000 Brasilia Time(2139444000000), dst: false, offset: -10800000
2037-10-17 23:00:00.001 Brasilia Time(2139444000001), dst: false, offset: -10800000
2037-10-17 23:59:59.999 Brasilia Time(2139447599999), dst: false, offset: -10800000
2037-10-18 01:00:00.000 Brasilia Summer Time(2139447600000), dst: true, offset: -7200000
2037-10-18 00:00:00.001 Brasilia Time(2139447600001), dst: true, offset: -10800000
2037-10-18 00:59:59.999 Brasilia Time(2139451199999), dst: true, offset: -10800000
2037-10-18 01:00:00.000 Brasilia Summer Time(2139447600000), dst: true, offset: -7200000
2037-10-18 00:00:00.001 Brasilia Time(2139447600001), dst: true, offset: -10800000
2037-10-18 00:59:59.999 Brasilia Time(2139451199999), dst: true, offset: -10800000
2037-10-18 02:00:00.000 Brasilia Summer Time(2139451200000), dst: true, offset: -7200000
这段代码打印出“2037-10-18 00:00:000 Brasilia Time”左右的日期时间,结果显示“2037-10-18 00:00:000 Brasilia Time”应该是“2037 -10-18 01:00:00.000 Brasilia Summer Time”表示巴西利亚在那一刻进入夏令时。
我的问题是为什么在“2037-10-18 00:00:00.001 巴西利亚时间”和“2037-10-18 00:59:59.999 巴西利亚时间”之间时区偏移仍然使用标准时间偏移。这是 JDK 时区数据的错误还是这个时区实际上是这样工作的。
我的代码使用偏移量来决定两个日期之间是否存在夏令时转换。显然“2037-10-18 01:00:00.000 巴西利亚夏令时”和“2037-10-18 00:59:59.999 巴西利亚时间”这两个日期在这里不起作用。
我可以更改为使用“TimeZone.getDefault().inDaylightTime(Date date)”来决定是否有转换,但我仍然想知道这是否是 JDK 的错误。
最佳答案
我尝试使用调试器单步执行代码,这似乎是时区和开关本身的问题:BRT 到 BRST 在午夜从 00:00:00 切换到 01:00:00,这意味着那个小时两者之间实际上并不存在。
从我的调试来看,问题似乎出在 GregorianCalendar#computeTime()
中,尤其是在以下行中:
millis -= zoneOffsets[0] + zoneOffsets[1];
在那行之前 millis
是从纪元开始的时间,它是根据解析的日期计算出来的,对于 00:00:00
(213946800000) 和 01:00:00
(2139440400000)。在这两种情况下,zoneOffsets[0]
都是 -10800000,这是 UTC 的原始偏移量。
区别在于 zoneOffsets[1]
:00:00:00
为 0,01:00:00
为是 3600000,即 1 小时。原因似乎是对 inDaylightTime( new Date(millis) )
的内部调用,它对 00:00:00
(夏令时之前)返回 false,但对01:00:00
(夏令时的第一个小时)。因此,最终时间将是相同的,因为您总是添加 10800000 毫秒,但从更高的值中减去 3600000 毫秒,后者高出 3600000 毫秒:)
最后你得到一个具有相同毫秒时间的Date
。
当再次格式化日期时,格式化程序似乎会根据时区检查毫秒时间,并且每次对应于 00:00:00,000 - 59:59:59,999
,即这可能处于两个时区的 dstOffset
将被假定为 0 而不是 3600000,因此会打印不同的时区。
编辑:当比较 01:00:00.000
和 01:00:00.001
时,似乎 中可能存在错误code>ZoneInfo.getOffsets(time, offsets, type)
前者返回 360000 的 dst 偏移量,后者返回 0,而在格式化程序中填充日历字段时,两者都将采用 dst。
编辑 2:当更改解析器格式以接受时区快捷方式时,您可以观察到相同的行为,即 00:00:00.000 BRT
和 01:00 :00.000 BRST
被解析为 2139447600000 并再次格式化为 01:00:00.000 BRST
而 00:00:00.001 BRT
和 01:00: 00.001 BRST
被解析为 2139447600001 并被格式化为 00:00:00.001 BRT
- 这本身是正确的。
关于java - 2037-10-18 巴西利亚夏令时过渡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38095468/