gpt4 book ai didi

Java - 从本地时间转换为 UTC 历史时间

转载 作者:行者123 更新时间:2023-12-02 02:13:08 25 4
gpt4 key购买 nike

除了时钟回滚一小时的情况外,在给定国家代码和时区更改时间列表的情况下,可以通过编程方式确定时区。

例如,如果您知道英国的时钟在每年 3 月的最后一个星期日凌晨 1 点和 10 月的最后一个星期日凌晨 2 点发生变化,那么给定历史或 future 的“本地”时间,您就可以确定 UTC 时间。

我的问题是,Java 中是否有任何内置方法可以确定此信息 - 不仅可以确定当前时间,还可以确定历史时间?

最佳答案

事情没那么简单,因为时区的规则(可能/可以/做)一直在变化。

... if you know that on the last Sunday of every March at 1am and October at 2am the clocks change in the UK

并非所有历史日期都是如此。 In the 70's您会注意到,一些 DST 更改发生在 3 月中旬,而不是最后一个星期日,例如 1974 年和 1975 年,DST 分别于 3 月 17 日和 16 日开始。另请注意,它从凌晨 2 点开始,而不是凌晨 1 点 ( only in 1981 it was changed to start at 1 AM )。

无论如何,Java 包含来自 IANA 的所有时区数据(包括历史数据),因此您只需使用内置类,API 即可完成所有数学运算:

// London timezone
ZoneId londonTimezone = ZoneId.of("Europe/London");

// the historical local date/time I want to check (March 16th 1975, 3 AM)
LocalDateTime localDt = LocalDateTime.of(1975, 3, 16, 3, 0, 0);

// convert to UK timezone (1975-03-16T03:00+01:00)
ZonedDateTime londonDt = localDt.atZone(londonTimezone);

// convert to UTC (1975-03-16T02:00:00Z)
Instant instant = londonDt.toInstant();

在上面的代码中,我创建了本地时间 1975 年 3 月 16 日凌晨 3 点(即 after the DST transition, that occurred at 2 AM)

当我将其转换为伦敦时区时,结果为 1975-03-16T03:00+01:00 - 偏移量为 +01:00(比 UTC 早一小时),因为 DST 是有效。将其转换为 UTC,结果为 1975-03-16T02:00:00Z

With the exception of when clocks roll back an hour...

其实,有一个办法可以解决这个问题。使用London's DST transition in 1975 ,夏令时于 10 月 26 日结束:凌晨 3 点,时钟被调回到凌晨 2 点,因此凌晨 2 点到 2:59 之间的所有本地时间都存在两次。如何解决这种歧义?

// London timezone
ZoneId londonTimezone = ZoneId.of("Europe/London");

// October 26th 1975, 2 AM - the ambiguous local time in London, due to DST end
LocalDateTime localDt = LocalDateTime.of(1975, 10, 26, 2, 0, 0);
// convert to UK timezone (default is the local time in DST: 1975-10-26T02:00+01:00)
ZonedDateTime londonDt = localDt.atZone(londonTimezone);

// get the date in DST (1975-10-26T02:00+01:00)
System.out.println(londonDt.withEarlierOffsetAtOverlap());
// get the date after DST ends (1975-10-26T02:00Z)
System.out.println(londonDt.withLaterOffsetAtOverlap());

方法withEarlierOffsetAtOverlap()withLaterOffsetAtOverlap()分别返回DST结束之前和之后对应的日期/时间,解决了歧义。

这些方法中的每一个都会返回一个新的 ZonedDateTime 实例(每个实例对应于不同的 UTC 时刻),您可以对它们调用 toInstant() 来获取对应的UTC 即时。

始终使用这两种方法来获取转换之前和之后的日期/时间。不要尝试增加或减少一小时,因为并非所有转换都会将时钟更改 1 小时:

It is possible to programmatically determine the timezone, given a country-code and a list of times at which the timezone changes

这是可能的,但请注意,同一个国家可以有多个时区,特别是像美国(非洲大陆有 4 个时区,加上阿拉斯加和夏威夷)、俄罗斯(超过 10 个)、巴西(4 - 实际上是有更多,因为有些州有夏令时,但其他州没有),等等。

无论如何,给定国家代码,您可以检查 this file并获取该国家/地区的所有时区。然后,对于每个时区,您运行与此类似的代码来比较发生转换时的所有日期:

ZoneId londonTimezone = ZoneId.of("Europe/London");
ZoneRules rules = londonTimezone.getRules();

// get all the transitions (dates when the offset changes)
rules.getTransitions().forEach(t -> {
// UTC instant when the change occurs
Instant instant = t.getInstant();

// local date/time before the transition
LocalDateTime before = t.getDateTimeBefore();
// UTC offset before the transition
ZoneOffset offsetBefore = t.getOffsetBefore();

// local date/time after the transition
LocalDateTime after = t.getDateTimeAfter();
// UTC offset afger the transition
ZoneOffset offsetAfter = t.getOffsetAfter();

// is GAP (clock shifts forward - local times are skipped)
boolean gap = t.isGap();
// is overlap (clock shifts backwards - local times can happen twice)
boolean overlap = t.isOverlap();

// *** You can use the data above to check if the transition date matches your list***
});

有些区域有转换规则而不仅仅是转换,因此您还必须检查转换规则列表:

rules.getTransitionRules().forEach(rule -> {
// get a transition for specific year
ZoneOffsetTransition transition = rule.createTransition(2018);

// use the transition the same as above (getInstant(), getDateTimeBefore(), etc)
});

关于Java - 从本地时间转换为 UTC 历史时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49671454/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com