我正致力于关注夏令时变化的关键应用程序
我试图通过比较跨越夏令时变化的thow日期来手动模拟运行时会发生什么,所以我进行了以下测试。
我目前的位置是意大利,所以今年CEST(中欧夏令时间)到CET(中欧时间)的变化发生在25/10。
我使用了full time zone names,我的时区为Europe/Rome
。
这是我做的测试:
Calendar before = Calendar.getInstance(TimeZone.getTimeZone("Europe/Rome DST")); //CEST
before.set(Calendar.DAY_OF_MONTH, 25);
before.set(Calendar.MONTH, Calendar.OCTOBER);
before.set(Calendar.HOUR_OF_DAY, 2);
before.set(Calendar.MINUTE, 30);
before.set(Calendar.SECOND, 0);
before.set(Calendar.MILLISECOND, 0);
System.out.println(before.getTime());
Calendar after = Calendar.getInstance(TimeZone.getTimeZone("Europe/Rome")); //CET
after.set(Calendar.DAY_OF_MONTH, 25);
after.set(Calendar.MONTH, Calendar.OCTOBER);
after.set(Calendar.HOUR_OF_DAY, 2);
after.set(Calendar.MINUTE, 30);
after.set(Calendar.SECOND, 0);
after.set(Calendar.MILLISECOND, 0);
System.out.println(after.getTime());
System.out.println(before.compareTo(after));
输出结果为:
BEFORE DST CHANGE: Sun Oct 25 03:30:00 CET 2015
AFTER DST CHANGE: Sun Oct 25 02:30:00 CET 2015
before.compareTo(after): 1
比较结果是错误的,即2:30 CEST是在欧洲中部时间2:30之后,但恰恰相反。
我不知道这是不是真正的考验
有没有办法解决这个问题?
我也尝试过joda时间,但结果是一样的。
提前谢谢。
答案 0 :(得分:3)
您的问题是"Europe/Rome DST"
无法识别getTimeZone(timeZoneId)
如果它不理解您的输入,it returns the GMT timezone by default。您可以使用getAvailableIDs
(上面链接中的getTimeZone
下面的方法)查看可用的TimeZone ID列表。
应该注意的是CEST
也不在列表中。要模拟CEST
时区,您可以选择以下解决方案之一:
TimeZone.setRawOffset(int offsetInMs)
自行设置CET和CEST的费用。"Etc/GMT+1"
)。这将确保您使用TimeZone api将理解的有效时区偏移。Calendar.DST_OFFSET
上设置DST偏移量。通过使用最后一个解决方案,正确的测试代码是:
Calendar before = Calendar.getInstance(TimeZone.getTimeZone("Europe/Rome"));
before.set(Calendar.DST_OFFSET, 3600000);
before.set(Calendar.DAY_OF_MONTH, 25);
before.set(Calendar.MONTH, Calendar.OCTOBER);
before.set(Calendar.HOUR_OF_DAY, 2);
before.set(Calendar.MINUTE, 30);
before.set(Calendar.SECOND, 0);
before.set(Calendar.MILLISECOND, 0);
System.out.println("BEFORE DST CHANGE: " + before.getTime());
Calendar after = Calendar.getInstance(TimeZone.getTimeZone("Europe/Rome"));
after.set(Calendar.DAY_OF_MONTH, 25);
after.set(Calendar.MONTH, Calendar.OCTOBER);
after.set(Calendar.HOUR_OF_DAY, 2);
after.set(Calendar.MINUTE, 30);
after.set(Calendar.SECOND, 0);
after.set(Calendar.MILLISECOND, 0);
System.out.println("AFTER DST CHANGE: " + after.getTime());
System.out.println("before.compareTo(after): " + before.compareTo(after));
输出:
BEFORE DST CHANGE: Sun Oct 25 02:30:00 CEST 2015
AFTER DST CHANGE: Sun Oct 25 02:30:00 CET 2015
before.compareTo(after): -1
答案 1 :(得分:2)
answer augray是正确的,应该被接受(点击那个大的空复选标记图标使其变为绿色)。我会添加一些想法和代码。
避免乱七八糟的java.util.Date/.Calendard类。众所周知,它们在设计和实施方面都很麻烦。
这些类已被java.time package及更晚(Java 8)中的新Tutorial取代。该软件包的灵感来自Joda-Time库。虽然类似,但java.time和Joda-Time并不完全相同。每个都有其他缺乏的功能。您可以使用其中之一或两者。
CET
&等代码CEST
既不是标准化也不是唯一的。避免他们。
使用full time zone names。其中大多数是“大陆/城市”或“大陆/地区”。
您似乎正在使用此代码来管理DST, Daylight Saving Time的问题。将这种繁重的工作留给日期时间库,例如java.time或Joda-Time。时区将UTC的偏移量与DST和其他异常的过去,现在和将来的规则组合在一起。因此,您指定时区名称,让库完成DST生效时的工作。
Daylight Saving Time (DST) for Rome今年将于2015年10月25日凌晨3点结束。时钟回滚以重复凌晨2点。所以当天有两次2:30次。您可以在下面的示例代码中看到这两次。
2015-10-25T02:30+02:00[Europe/Rome]
2015-10-25T02:30+01:00[Europe/Rome]
以下是Java 8的java.time中的一些示例代码,以了解如何处理DST。首先,我们采用一些“本地”日期时间,其中“本地”表示没有附加任何特定时区。然后我们分配罗马时区。之后我们采用分区值(罗马值)并加上或减去小时数。
注意10月25日“罗马凌晨2点30分”的概念是如何毫无意义的。您必须知道01:00
或02:00
的偏移量才能正确解释。
ZoneId zone = ZoneId.of( "Europe/Rome" );
System.out.println( "-----| Local |-----------------------------------------\n" );
LocalDateTime local_0130 = LocalDateTime.of( 2015 , Month.OCTOBER , 25 , 1 , 30 );
ZonedDateTime zoned_0130 = ZonedDateTime.of( local_0130 , zone );
LocalDateTime local_0230 = LocalDateTime.of( 2015 , Month.OCTOBER , 25 , 2 , 30 );
ZonedDateTime zoned_0230 = ZonedDateTime.of( local_0230 , zone );
LocalDateTime local_0330 = LocalDateTime.of( 2015 , Month.OCTOBER , 25 , 3 , 30 );
ZonedDateTime zoned_0330 = ZonedDateTime.of( local_0330 , zone );
System.out.println( "local_0130: " + local_0130 + " in zone: " + zone + " is " + zoned_0130 );
System.out.println( "local_0230: " + local_0230 + " in zone: " + zone + " is " + zoned_0230 );
System.out.println( "local_0330: " + local_0330 + " in zone: " + zone + " is " + zoned_0330 + "\n" );
System.out.println( "-----| Add Hours |-----------------------------------------\n" );
ZonedDateTime zoned_0130_plus_1H = zoned_0130.plusHours( 1 );
ZonedDateTime zoned_0130_plus_2H = zoned_0130.plusHours( 2 );
System.out.println( "zoned_0130_plus_1H: " + zoned_0130_plus_1H );
System.out.println( "zoned_0130_plus_2H: " + zoned_0130_plus_2H + "\n" );
System.out.println( "-----| Subtract Hours |-----------------------------------------\n" );
ZonedDateTime zoned_0330_minus_1H = zoned_0330.minusHours( 1 );
ZonedDateTime zoned_0330_minus_2H = zoned_0330.minusHours( 2 );
System.out.println( "zoned_0330_minus_1H: " + zoned_0330_minus_1H );
System.out.println( "zoned_0330_minus_2H: " + zoned_0330_minus_2H + "\n" );
跑步时。
-----| Local |-----------------------------------------
local_0130: 2015-10-25T01:30 in zone: Europe/Rome is 2015-10-25T01:30+02:00[Europe/Rome]
local_0230: 2015-10-25T02:30 in zone: Europe/Rome is 2015-10-25T02:30+02:00[Europe/Rome]
local_0330: 2015-10-25T03:30 in zone: Europe/Rome is 2015-10-25T03:30+01:00[Europe/Rome]
-----| Add Hours |-----------------------------------------
zoned_0130_plus_1H: 2015-10-25T02:30+02:00[Europe/Rome]
zoned_0130_plus_2H: 2015-10-25T02:30+01:00[Europe/Rome]
-----| Subtract Hours |-----------------------------------------
zoned_0330_minus_1H: 2015-10-25T02:30+01:00[Europe/Rome]
zoned_0330_minus_2H: 2015-10-25T02:30+02:00[Europe/Rome]
答案 2 :(得分:0)
我的建议是使用IANA time zone database中的完整标识符。在您的情况下,您应该使用"Europe/Rome":
before.setTimeZone(TimeZone.getTimeZone("Europe/Rome"));
这将确保为该区域使用适当的时区信息,包括何时需要触发夏令时模式以及可能的区域异常。
不要添加DST
。
答案 3 :(得分:0)
“欧洲/罗马”不是CET,“欧洲/罗马DST”不是CEST。
“欧洲/罗马”是意大利的时区。它不仅包括夏令时的变化,还包括罗马/意大利的偏移的任何其他变化。因此,当罗马在CET时,“欧洲/罗马”是CET,当罗马参加CET时,它就是CEST。像“欧洲/罗马”这样的时区的全部意义在于你不必关心夏令时,时区会为你处理它。