如何从Java 8中的TimeZone值获取TimeZoneOffset ID?

时间:2017-05-01 08:25:30

标签: java timezone timezone-offset

我有TimeZone,比方说Asia/Kolkata,如何在Java中获取相应的ZoneOffset ID,即。+05:30

我一直在尝试以下,但没有获胜:

String zoneOffsetID = ZoneId.of("Asia/Kolkata").getId();
ZoneOffset zoneOffset = ZoneOffset.of(zoneOffsetID);

我也尝试了Asia/Calcutta来自:

Set<String> allZones = ZoneId.getAvailableZoneIds();

2 个答案:

答案 0 :(得分:3)

这可以满足您的需求:

String zoneOffsetID = ZoneId.of("Asia/Kolkata").getId();
System.out.println(zoneOffsetID);
ZoneOffset zoneOffset = ZoneId.of("Asia/Kolkata").getRules().getOffset(Instant.now());
System.out.println(zoneOffset);

...并打印:

Asia/Kolkata
+05:30

不确定这是否是最短/最佳/首选方式,但它确实有效。

答案 1 :(得分:2)

正如许多人在评论中已经说过的那样,API没有参数的getOffset()方法。那是因为时区不能保证只有一个偏移量。它们在历史上可以有不止一个(并且大多数 - 如果不是全部的话 - 都有它)。

API提供了一种检查所有这些更改的方法。

ZoneId类有一个getRules()方法,它返回一个java.time.zone.ZoneRules实例,其中包含定义相应时区的偏移量随时间变化的所有规则。

让我们看一下您在示例中使用的时区并获取其规则:

// get timezone
ZoneId zone = ZoneId.of("Asia/Kolkata");
// get rules
ZoneRules rules = zone.getRules();
// get list of transitions (date/times when the offset changes)
List<ZoneOffsetTransition> transitions = rules.getTransitions();
for (ZoneOffsetTransition zt : transitions) {
    System.out.println(zt);
}

这将打印所有转换:偏移量发生变化时的所有日期/时间。输出将是:

  

转换[重叠于1880-01-01T00:00 + 05:53:28至+05:53:20]
    过渡[1941-10-01T00:00 + 05:53:20至+06:30]的差距     过渡[重叠于1942-05-15T00:00 + 06:30至+05:30]     过渡[1942-09-01T00:00 + 05:30至+06:30的差距]     过渡[重叠于1945-10-15T00:00 + 06:30至+05:30]

让我们来看看最后一行。它表示在 10月,15 th 1945 00h00 时,偏移量从+06:30变为+05:30。由于此时区的夏令时结束,时钟将在1小时后移动(请参阅link provided by @MattJohnson in his comment

我们可以使用以下代码测试此行为:

// DST ends at 1945-10-15T00:00, setting date 1 minute before
ZonedDateTime dt = ZonedDateTime.of(1945, 10, 14, 23, 59, 0, 0, ZoneId.of("Asia/Kolkata"));

// in DST, offset is +06:30
System.out.println("in DST:  " + dt);

// plus 1 minute, DST ends (offset changes to +05:30)
System.out.println("not DST: " + dt.plusMinutes(1));

输出结果为:

  在夏令时:1945-10-14T23:59 + 06:30 [亚洲/加尔各答]
    不是DST:1945-10-14T23:00 + 05:30 [亚洲/加尔各答]

请注意,在 Oct,14 th 23:59 中,偏移量为+06:30(它在DST中),但是1分钟后(这将是< strong> 10月15日 th 00:00 ),DST结束,时钟向后移动1小时,因此它变为 10月14日 th 23:00 +05:30偏移。

这就是getOffset()方法必须具有Instant参数的原因:每个时刻都有不同的偏移量。

使用上述日期,您可以使用ZoneRules.getOffset方法检查偏移量,并使用ZonedDateTime.toInstant()方法将日期转换为Instant

ZoneId zone = ZoneId.of("Asia/Kolkata");
ZoneRules rules = zone.getRules();
ZonedDateTime dt = ZonedDateTime.of(1945, 10, 14, 23, 59, 0, 0, zone);

// in DST, offset is +06:30
System.out.println(rules.getOffset(dt.toInstant()));

// plus 1 minute, DST ends (offset changes to +05:30)
System.out.println(rules.getOffset(dt.plusMinutes(1).toInstant()));

输出结果为:

  

+06:30
  05:30

让我们再看一下这个时区的转换列表:

  

转换[重叠于1880-01-01T00:00 + 05:53:28至+05:53:20]
    过渡[1941-10-01T00:00 + 05:53:20至+06:30]的差距     过渡[重叠于1942-05-15T00:00 + 06:30至+05:30]     过渡[1942-09-01T00:00 + 05:30至+06:30的差距]     过渡[重叠于1945-10-15T00:00 + 06:30至+05:30]

前2行意味着加尔各答的时区在1880年之前使用+05:53:28,然后使用+05:53:20直到1941年+06:30偏移开始。然后有一些DST过渡,现在它没有DST,偏移量是+05:30

因此,加尔各答的时区可以有四个不同的偏移量,具体取决于您查找的日期和时间。如果您想知道时区的偏移量,必须提供Instant,因为API无法在所有选项之间进行选择。要获得当前偏移量(此时正在使用的 ),您可以使用Instant.now()(如Robin's answer中所示)。< / p>

但不要忘记,政府可以随时更改时区,因此不能保证始终保持不变。有些政府可能决定改变一个国家/地区的时区,或者说“今年我们将从明天开始使用DST”,或类似的东西。仅仅因为今天时区没有DST变化,这并不意味着它总是那样。

这就是为什么我们不能使用无参数getOffset()方法。

还有一件事:您可以检查时区是否有偏移变化:

ZoneId zone = ZoneId.of("Asia/Kolkata");
ZoneRules rules = zone.getRules();
System.out.println(rules.isFixedOffset()); // false (not fixed = offset varies)

如果时区的偏移量永远不会改变,则isFixedOffset()方法返回true。 但即使它是true,API的设计者也决定getOffset总是需要一个Instant来检查该瞬间的偏移量(因为没人知道偏移量是否会在未来发生变化)。