useDaylightTime() TimeZone.java 中的这个方法返回错误答案

问题描述 投票:0回答:2

Casablanca是摩洛哥的一个城市,实际上摩洛哥使用夏令时,但是方法useDaylight()返回false,另一方面,罗马也使用夏令时,useDaylight()返回true 我的jdk是8u362,我的代码是这样的:

public static void main(String[] args) {
        TimeZone Rome = TimeZone.getTimeZone("Europe/Rome");
        System.out.println(Rome.useDaylightTime());

        TimeZone Casablanca = TimeZone.getTimeZone("Africa/Casablanca");
        System.out.println(Casablanca.useDaylightTime());

    }

结果是

true
false

查过卡萨布兰卡和罗马都是夏令时,为什么卡萨布兰卡的timezone返回false

我试过其他城市作为时区,发现有些时区使用DST但返回false,而其他城市正常,谁能告诉我为什么并解释方法useDaylight()的真正含义?

java timezone dst
2个回答
0
投票

查看 TimeZone 的源代码。

TimeZone
对应的
Europe/Rome
定义如下(第539行):

new SimpleTimeZone(1000 * 3600, "CET", Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);

第 4 到第 10 个参数 与夏令时有关并导致 useDaylightTime()

 返回 true。

TimeZone

(第486行)对应的
Africa/Casablanca
是:

new SimpleTimeZone(0 * 3600, "GMT")
并导致 

useDaylightTime()

 返回 true

因此 Java 将 Europe/Rome 定义为有夏令时,将 Africa/Casablanca 定义为没有夏令时。

下一个问题是:这是否反映了现实?

Java 使用来自全球权威机构

Internet Corporation for Assigned Names and Numbers 的时区“历史”定义改变以反映不同版本的现实.

根据以上页面

摩洛哥在 2018 年 10 月放弃了夏令时,这一变化反映在以下版本 11.0.2、8u201 和 7u211 中。


0
投票
摩洛哥

参见维基百科文章,

摩洛哥的夏令时

从 2008 年开始,摩洛哥每年都会观察到

夏令时 (DST) (+01:00),直到 2018 年 10 月。在那个月,政客们没有“回落”到他们的标准时间 (+00:00),而是决定全年保持夏令时 (+01:00)(世界各地政治家的最新时尚)。

最重要的是,摩洛哥的政客们一直决定在

斋月 月份后退一个小时 (+00:00)。

避免遗留日期时间类

TimeZone

 类是存在严重缺陷的日期时间类的一部分,这些类在多年前被 JSR 310 中定义的现代 
java.time 类所取代。

ZoneId

而不是

TimeZone

,你应该使用
ZoneId
 & 
ZoneOffset
.

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;

ZoneRules

从一个

ZoneId

,得到它的一套
规则

ZoneId z = ZoneId.of( "Africa/Casablanca" ); Instant pointInTime = LocalDate.of( 2021 , Month.JANUARY , 1 ).atStartOfDay( z ).toInstant(); Instant now = Instant.now(); ZoneRules rules = z.getRules();

ZoneOffsetTransition

询问最近偏移量的规则

transitions.

List < ZoneOffsetTransition > transitions = rules .getTransitions() .stream() .filter( transition -> transition.getInstant().isAfter( pointInTime ) && transition.getInstant().isBefore( now ) ) .toList(); for ( ZoneOffsetTransition transition : transitions ) { System.out.println( "transition = " + transition ); }
运行时:

transition = Transition[Overlap at 2021-04-11T03:00+01:00 to Z] transition = Transition[Gap at 2021-05-16T02:00Z to +01:00] transition = Transition[Overlap at 2022-03-27T03:00+01:00 to Z] transition = Transition[Gap at 2022-05-08T02:00Z to +01:00] transition = Transition[Overlap at 2023-03-19T03:00+01:00 to Z]
我们可以看到 DST (+01:00) 和标准时间之间的来回变化,从 UTC 偏移零时分秒,这里用字母

Z

(发音为“Zulu”)表示。

List < ZonedDateTime > zdts = List.of( LocalDate.of( 2023 , Month.JANUARY , 1 ).atStartOfDay( z ) , LocalDate.of( 2023 , Month.MARCH , 30 ).atStartOfDay( z ) , ZonedDateTime.now( z ) ); for ( ZonedDateTime zdt : zdts ) { System.out.println( zdt + " is in DST: " + rules.isDaylightSavings( zdt.toInstant() ) ); }

isDaylightSavings

对于几个任意时间点,让我们问一下那个时刻是否在夏令时。

List < ZonedDateTime > zdts = List.of( LocalDate.of( 2023 , Month.JANUARY , 1 ).atStartOfDay( z ) , LocalDate.of( 2023 , Month.MARCH , 30 ).atStartOfDay( z ) , ZonedDateTime.now( z ) ); for ( ZonedDateTime zdt : zdts ) { System.out.println( zdt + " is in DST: " + rules.isDaylightSavings( zdt.toInstant() ) ); }
运行时:

2023-01-01T00:00+01:00[Africa/Casablanca] is in DST: true 2023-03-30T00:00Z[Africa/Casablanca] is in DST: false 2023-04-19T03:42:56.153413Z[Africa/Casablanca] is in DST: false
网络上的几个消息来源称,摩洛哥的斋月 2023 年从 2023 年 3 月 23 日星期四到 2023 年 4 月 21 日星期五。请注意我上面显示的过渡是不同的,回退时间是 3 月 19 日而不是 23 日.我不知道有什么解释。也许政客们并没有严格使用斋月日期来改变偏移量。这个回退是根据我的

Java 20实现中的tzdata,它应该是相当新鲜的。

所以如上所述,我们可以看到 DST 在一年中的大部分时间使用,例如上面列表中的 2023 年 1 月 1 日。然后对于我们三月和四月的两个日期,根据斋月回滚到标准时间 (+00:00),

not 使用夏令时。


你问:

解释方法 useDaylight() 的真正含义?

现代替代品是

ZoneRules#isDaylightSavings( Instant instant )

.

引用 Javadoc:

检查指定的时刻是否在夏令时。

这将检查指定时刻的标准偏移量和实际偏移量是否相同。如果不是,则假定正在运行夏令时。

此默认实现比较实际和标准偏移量。

© www.soinside.com 2019 - 2024. All rights reserved.