Java上的日历并没有与" America / Santiago" DST时区

时间:2015-05-11 07:27:30

标签: java calendar timezone dst

我遇到Calendar对象的问题,它没有在America / Santiago时区的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));

输出为:offset:-4 在2015年3月31日的美国/圣地亚哥时区,偏移量应为-3。 (参考:http://www.timeanddate.com/worldclock/converted.html?iso=20150331T00&p1=218&p2=232

为什么日历会在这种情况下得到正确的偏移量?我用其他时区测试过,它在DST时间工作正常。

谢谢。

3 个答案:

答案 0 :(得分:1)

智利通常在3月份从DST转为STD,因此您的日期通常是标准时间。然而,自2010年以来,转换已经在4月(2011年5月除外)和in 2015 Chile announced,它将停止改变并永久保持夏令时。 (编辑:Chile has reversed its 2015 decision,那一年是智利唯一一个没有回到标准时间的年份。)

因此我认为问题很可能是您的zoneinfo数据库已经过时了。如果您运行的是不是最新的JVM副本,或者您正在运行从操作系统获取它的zoneinfo数据的JVM副本(这在某些Linux发行版上会发生),并且您无法保持您的操作系统最新,或者您运行的操作系统不再接收更新。

在任何情况下,Java的解决方案通常都是更新到最后一个JVM。

答案 1 :(得分:1)

关于您需要使tzdata保持最新的JVM,其他答案是正确的。

java.time

此外,您所使用的日期时间类现在已经过时,被JSR 310中定义的现代 java.time 类所取代。

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() ;

询问规则。当时正在使用的Get the offset-from-UTC,由ZoneOffset类表示。

ZoneOffset offset = rules.getOffset( instant ) ;

询问当时该区域中的Daylight Saving Time (DST)是否有效。请注意,Java团队在命名此方法时经常使用拼写错误(“ Saving”应为单数)。

boolean isDst = rules.isDaylightSavings( instant ) ;

如果在DST中,则将DST调整量作为Duration对象。 Duration::toString方法以标准ISO 8601格式报告其值(小时,分钟和秒数)。例如,PT1H表示1小时。

if( isDst ) {
    Duration d = getDaylightSavings​( instant ) ;
}

请参见this code run live at IdeOne.com

zdt = 2015-03-31T07:45-03:00[America/Santiago]
instant = 2015-03-31T10:45:00Z
offset = -03:00
isDst = true
d = PT1H

答案 2 :(得分:0)

如果没有关于时区数据的基础版本的额外信息,很难说明究竟是什么原因。但是,你的上次评论

  

根本原因是:我的系统上的JDK是1.7版本所以   在这种情况下,日历没有得到正确的时间。我试过jdk 1.8   然后得到预期的输出

告诉我你显然对任何分析都不感兴趣。所以我为那些只想要解决方案的用户更新了这个答案,而不需要知道解决方案的工作原理。

如果用户在获取正确的时区偏移时遇到问题,那么原因通常是使用过时的数据。由于时区数据内置于底层JDK(如果Java-8不是真的没有你可以做急救:

  1. 将您的JVM更新到最新版本(也是:最新的次要版本,实际上是Java 8u45)。

  2. 如果这没有用,那么请使用最新版本的TZUpdater-Tool来更新JVM的时区数据 - 使用预建数据。

  3. 如果这仍然无效,那么您可以 - 从TZUpdater-Tool 2.0版开始 - 使用该工具根据对最新版本的原始IANA / TZDB版本的直接利用来更改您的时区数据(感谢Matt Johnson评论中的信息。请记住,在IANA上托管的新TZDB版本与Oracle-Java-release-schedules之间总是存在时间差。

  4. 如果您不想依赖Oracles发布计划或TZUpdater工具,那么您可以使用具有内置时区存储库的外部库,并为您提供机会尽快更新(我知道至少2-3个这样的库,但不会在这里给出任何具体的建议。但是很容易做适当的研究)。