Java 8时区API获取莫斯科1991年的夏令时转换未返回DST更改。

7

java.time.zone.ZoneRules#nextTransition不会返回Europe/Moscow 1991年夏令时更改的信息,因此我无法获取Europe/Moscow 1991年夏令时的边界信息。 Europe/Moscow 于1991年3月31日02:00进入夏令时并改变了标准时间偏移量,所以偏移量(+03:00)保持不变而没有Java API可用于获取夏令时开始的该边界。

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.zone.ZoneOffsetTransition;

public class TimeUtilTest {
    public static void main(String[] args) {
        ZoneId tz = ZoneId.of("Europe/Moscow");
        ZonedDateTime yearBegin = ZonedDateTime.of(1991, 1, 1, 0, 0, 0, 0, tz);
        ZoneOffsetTransition nextTransition = tz.getRules().nextTransition(yearBegin.toInstant());
        System.out.println("year begin isDST=" + tz.getRules().isDaylightSavings(yearBegin.toInstant()));
        System.out.println("next transition before is " + nextTransition.getDateTimeBefore() + " isDST=" + tz.getRules()
                .isDaylightSavings(nextTransition.getInstant().minusNanos(1)));
        System.out.println("next transition after is " + nextTransition.getDateTimeAfter() + " isDST=" + tz.getRules()
                .isDaylightSavings(nextTransition.getInstant().plusNanos(1)));
    }
}

它返回以下内容:
year begin isDST=false
next transition before is 1991-09-29T03:00 isDST=true
next transition after is 1991-09-29T02:00 isDST=false

您可以看到,在转换之前,isDST被意外更改了。


我可以重现你的结果:第一个转换在1991年被发现是在9月份。但Java知道夏令时是从3月开始的。tz.getRules().isDaylightSavings(ZonedDateTime.of(1991, 3, 31, 1, 59, 59, 999_999_999, tz).toInstant()) 返回false,而 tz.getRules().isDaylightSavings(ZonedDateTime.of(1991, 3, 31, 2, 0, 0, 0, tz).toInstant()) 返回true。如果其他方法都失败了,可以使用二分查找来找到时间。 - Ole V.V.
今天也是一个有趣的问题。我想,如果/当欧盟放弃夏令时,可能会有一些国家在夏令时结束的同时改变他们的标准偏移量。还有@ElliottFrisch - Ole V.V.
1个回答

2
你的观察是正确的。
确认1991年3月的更改的一种方法是:在timeanddate.com的时区和时钟更改页面上(请参见底部链接),从下拉菜单中选择1990-1999。我引用:
"1991年3月31日,晚上11点,时间被推迟了1小时,变成了1991年4月1日凌晨12点。这标志着夏令时的开始。"
Year    Date & Time             Abbreviation    Time Change                         Offset After
1991    søn 31. mar, kl. 02.00  MSK → EEST      No offset (DST start, TZ change)    UTC+3h

Java时区规则是用转换模型来表示的,这些转换要么是空隙(指钟表向前转动),要么是重叠(指钟表向后转动)。由于1991年3月莫斯科没有发生任何转换,因此该时区规则无法真正模拟转换,所以显然选择了将其排除在外。也许我们可以想象一个空隙和一个重叠相互平衡,但我认为那也行不通。
不过,Java确实知道这个变化。例如,请尝试:
    ZoneRules moscowRules = tz.getRules();
    Instant justBeforeChange = ZonedDateTime.of(1991, 3, 31, 1, 59, 59, 999_999_999, tz).toInstant();
    System.out.println(moscowRules.getStandardOffset(justBeforeChange));
    System.out.println(moscowRules.isDaylightSavings(justBeforeChange));
    Instant onChange = ZonedDateTime.of(1991, 3, 31, 2, 0, 0, 0, tz).toInstant();
    System.out.println(moscowRules.getStandardOffset(onChange));
    System.out.println(moscowRules.isDaylightSavings(onChange));

这将打印:

+03:00
false
+02:00
true
你说得也对,但是,没有办法直接查询ZoneRules对象关于这个更改发生的时间。如果你需要做到这一点,二分查找可以将其缩小到1991-03-30T23:00:00Z,与1991-03-31T02:00:00+03:00相同。
我在你的问题中没有看到一个清晰的问题,并不确定你更确切地期望从答案中得到什么。
链接
- timeanddate.com上的莫斯科多年来的时间变化

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接