我对日历对象有问题,它在美国/圣地亚哥时区的DST(每日节省时间)上没有正确的偏移:我的示例代码: TimeZone fromTimeZone = TimeZone.getTimeZone(" America/Santiago");
// Get a Calendar instance using the default time zone and locale.
Calendar calendar = Calendar.getInstance();
// Set the calendar’s time with the given date
calendar.setTimeZone(fromTimeZone);
calendar.set(Calendar.YEAR, 2015); // 2015
calendar.set(Calendar.MONTH, 2); // Mar
calendar.set(Calendar.DATE, 31); // 31
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 45);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
System.out.println("offset: " + fromTimeZone.getOffset(calendar.getTimeInMillis())/(TimeUnit.MINUTES.toMillis(1)*60));
输出为:偏移:-4在2015年3月31日的美国/圣地亚哥时区,偏移应为-3。(参考:http://www.timeanddate.com/worldclock/converted.html?iso=20150331T00&p1 = 218& amp; p2 = 232)
)为什么日历在这种情况下获得正确的偏移?我与其他时区进行了测试,在DST时正常工作。
谢谢。
智利通常在3月从DST切换到STD,因此您的日期通常是在标准时间中。但是,自2010年以来,转换已在4月(2011年5月除外),2015年智利宣布将停止更改并永久保留日光节省。(编辑:智利扭转了2015年的决定,那年是智利唯一一份智利没有回到标准时间的决定。)
因此,我认为问题很可能是您的ZoneInfo数据库已经过时了。如果您正在运行不是最新的JVM的副本,或者您正在运行从OS中获取其ZoneInfo数据的JVM的副本(这在某些Linux发行版中发生),而您尚未保留您的操作系统是最新的,或者如果您正在运行不再收到更新的操作系统。
无论如何,Java的解决方案通常要更新到最后一个JVM。
没有有关时区数据基础版本的额外信息,很难确切地说明原因。但是,您的最后评论
根本原因是:我的系统上的JDK是1.7版本,所以 日历在这种情况下没有正确的时间。我尝试了JDK 1.8 然后获取预期的输出
告诉我,您显然对任何分析都不感兴趣。因此,我为只需要解决方案的用户更新了此答案,而无需知道该解决方案为什么有效。
如果用户遇到获得正确的时区偏移的问题,则原因通常是使用过时的数据。,因为时区数据已内置在基础JDK中(如果Java-8或没有真正的工作物质)您可以作为急救:
-
将您的JVM更新为最新版本(也是最新的次要版本,实际上是Java 8U45)。
-
如果这没有帮助,请使用最新版本的tzupdater -tool,以更新JVM的时区数据 - 使用预构建的数据。
-
如果仍然没有帮助,那么您可以 - 从Tzupdater -Tool的2.0版开始 - 使用该工具基于直接利用原始IANA/TZDB -Version的最新版本来更改时区数据(多亏了马特·约翰逊(Matt Johnson)评论中的信息)。请记住,在IANA和Oracle-Java-Release-schedules上托管的新TZDB-version的发布之间总是存在时间差距。
-
如果您不想依赖Oracles发布计划或tzupdater-tool,则可以使用具有内置的时区固定物的外部库,并为您提供更新它的机会您自己尽快(我知道至少有2-3个这样的图书馆,但不会在这里提供任何具体建议。但是,进行适当的研究很容易)。
其他答案是正确的,您需要在JVM中保留您的 tzdata 。
java.Time
另外,您正在使用现在已过时的日期时间类,由现代 java.Time 类取代JSR 310中的类别。
ZoneId z = ZoneId.of( "America/Santiago" ) ;
LocalDate ld = LocalDate.of( 2015 , Month.MARCH , 31 ) ;
LocalTime lt = LocalTime.of( 7 , 45 , 0 , 0 ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
将该时刻调整为UTC。时间轴上的相同点,不同的墙壁时间。
Instant instant = zdt.toInstant() ;
获取该时区的规则,一个ZoneRules
对象。
ZoneRules rules = z.getRules() ;
审问规则。当时使用ZoneOffset
类代表。
ZoneOffset offset = rules.getOffset( instant ) ;
询问那一刻在该区域的日光节省时间(DST)是否有效。请注意,Java团队在命名此方法中使用的常见拼写("保存"应该是单数)。
boolean isDst = rules.isDaylightSavings( instant ) ;
如果在DST中,将DST调整的量作为Duration
对象。Duration::toString
方法以标准ISO 8601格式报告其值(数量,分钟和秒数)。例如, PT1H
表示1小时。
if( isDst ) {
Duration d = getDaylightSavings( instant ) ;
}
请参阅此代码在IDEONE.com上进行直播。
zdt = 2015-03-31T07:45-03:00[America/Santiago]
instant = 2015-03-31T10:45:00Z
offset = -03:00
isDst = true
d = PT1H