如何在Java 8中从时区值获取时区偏移量ID?



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

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

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

我也尝试了Asia/Calcutta我从

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

这能得到你想要的:

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

不确定这是否是最短/最整洁/首选的方式,但它有效。

正如许多人在评论中已经告诉的那样,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
]



让我们看一下最后一行。它说在1945年10月1500h00,偏移量从+06:30变为+05:30。由于该时区夏令时结束,时钟向后移动了 1 小时(请参阅@MattJohnson在他的评论中提供的链接)

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

// 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[亚洲/加尔各答]

非夏令时:1945-10-14T23:00+05:30[亚洲/加尔各答]

请注意,在 10 月 14 日 23:59 中,偏移量为+06:30

(采用 DST),但 1 分钟后(即 10 月 15 日 00:00),DST 结束,时钟向后移动 1 小时,因此它变为10月 14 日 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 的答案)。

但不要忘记,政府可以随时更改时区,因此不能保证始终相同。某些政府可能会决定更改国家/地区的时区,或者说"今年我们将从明天开始使用夏令时",或类似的话。仅仅因为今天的时区没有 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来检查那个时刻的偏移量(因为没有人知道偏移量将来是否会改变)。

相关内容

  • 没有找到相关文章

最新更新