我有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();
答案 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
来检查该瞬间的偏移量(因为没人知道偏移量是否会在未来发生变化)。