我遇到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时间工作正常。
谢谢。
答案 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,其他答案是正确的。
此外,您所使用的日期时间类现在已经过时,被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不是真的没有你可以做急救:
将您的JVM更新到最新版本(也是:最新的次要版本,实际上是Java 8u45)。
如果这没有用,那么请使用最新版本的TZUpdater-Tool来更新JVM的时区数据 - 使用预建数据。
如果这仍然无效,那么您可以 - 从TZUpdater-Tool 2.0版开始 - 使用该工具根据对最新版本的原始IANA / TZDB版本的直接利用来更改您的时区数据(感谢Matt Johnson评论中的信息。请记住,在IANA上托管的新TZDB版本与Oracle-Java-release-schedules之间总是存在时间差。
如果您不想依赖Oracles发布计划或TZUpdater工具,那么您可以使用具有内置时区存储库的外部库,并为您提供机会尽快更新(我知道至少2-3个这样的库,但不会在这里给出任何具体的建议。但是很容易做适当的研究)。