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()的真正含义?
查看 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 中。
夏令时 (DST) (+01:00),直到 2018 年 10 月。在那个月,政客们没有“回落”到他们的标准时间 (+00:00),而是决定全年保持夏令时 (+01: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 )
检查指定的时刻是否在夏令时。这将检查指定时刻的标准偏移量和实际偏移量是否相同。如果不是,则假定正在运行夏令时。
此默认实现比较实际和标准偏移量。