在Scala中进行toInstant转换后,GMT和BST的不同ZonedDateTime变成相同的Instant



为了总结我的问题,我有两个不同的ZonedDateTime对象,它们具有GMT和BST,但本地时间相同。在toInstant转换后,它们将变为相同的Instant值。我希望在转换后,它们应该是不同的值,因为尽管它们都是"2021年2月23日星期二18:00:46",但字符串代表不同时区的时间。我不确定这是图书馆本身的错误还是我做错了什么。

我从这段Scala代码中生成了两个不同的ZonedDateTime:

import ...
import java.util.{Set => JavaSet}
val string2 = "Tue Feb 23 18:00:46 BST 2021" 
val string1 = "Tue Feb 23 18:00:46 GMT 2021" 
val timestampFormat: DateTimeFormatter = new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ISO_DATE_TIME)
.appendOptional(DateTimeFormatter.ISO_INSTANT)
.appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
.appendOptional(DateTimeFormatter.ISO_ZONED_DATE_TIME)
.appendOptional(DateTimeFormatter.RFC_1123_DATE_TIME)
.appendPattern("EEE MMM ppd HH:mm:ss ")
.appendZoneText(TextStyle.SHORT, JavaSet.of(ZoneId.of("Europe/London")))
.appendPattern(" yyyy")
.toFormatter(Locale.US)
val parsedZdt2: ZonedDateTime = ZonedDateTime.parse(string2, timestampFormat)
val parsedZdt1: ZonedDateTime = ZonedDateTime.parse(string1, timestampFormat)
println(parsedZdt1 == parsedZdt2)
println("parsedZdt1.toString: " + parsedZdt1.toString)
println("parsedZdt2.toString: " + parsedZdt2.toString)

打印出来:

false
parsedZdt1.toString: 2021-02-23T18:00:46Z[GMT]
parsedZdt2.toString: 2021-02-23T18:00:46Z[Europe/London]

然而,当我将它们转换为即时:

println(parsedZdt1.toInstant == parsedZdt2.toInstant)
println("parsedZdt1.toInstant.toString: " + parsedZdt1.toInstant.toString)
println("parsedZdt2.toInstant.toString: " + parsedZdt2.toInstant.toString)

我把这个打印出来了:

true
parsedZdt1.toInstant.toString: 2021-02-23T18:00:46Z
parsedZdt2.toInstant.toString: 2021-02-23T18:00:46Z

我的问题是

  1. 为什么toInstant转换后这两个值会相同
  2. 即使在toInstant之前,这两个值是否表示相同的时间,即parsedZdt1和parsedZdt2表示相同的时刻

谢谢!

tl;dr

你说:

字符串代表不同时区的时间

是的,不同的时区,但这些时区恰好在特定日期共享相同的偏移量。巧合的是,许多时区在特定日期共享相同的偏移量。

伦敦时间是GMT/UTC时间,有时不遵守夏令时(DST(。

BST=GMT(有时(

如果您所说的BST是指时区Europe/London,则该时区与2021-02-23日的UTC/GMT之间的偏移量为零小时。

👉因此,伦敦时间2月23日下午6点也是格林尼治标准时间下午6点。

今年晚些时候,从2021年3月28日到2021年10月31日,英国实行夏令时。在这几个月里,它们的偏移量比UTC提前一小时

请参阅TimeAndDate.com上的英国2021年时间变化

示例代码

让我们用Instant#equals来比较两个矩。

LocalDate ld = LocalDate.of( 2021 , Month.FEBRUARY , 23 ) ;
LocalTime lt = LocalTime.of( 18 , 0 , 0 ) ;
boolean sameMoment = 
ZonedDateTime.of( ld , lt , ZoneId.of( "Europe/London" ) ).toInstant()
.equals(
OffsetDateTime.of( ld , lt , ZoneOffset.UTC ).toInstant()
) ;

请在Ideone.com.上实时查看此代码

真实

在遵守夏令时期间,将月份更改为六月。

LocalDate ld = LocalDate.of( 2021 , Month.JUNE , 23 ) ;
LocalTime lt = LocalTime.of( 18 , 0 , 0 ) ;
boolean sameMoment = 
ZonedDateTime.of( ld , lt , ZoneId.of( "Europe/London" ) ).toInstant()
.equals(
OffsetDateTime.of( ld , lt , ZoneOffset.UTC ).toInstant()
) ;

错误

ZoneOffset

此外,您可以直接询问ZonedDateTimeOffsetDateTime对象中的力矩偏移。调用getOffset以获取ZoneOffset对象。

LocalDate ld = LocalDate.of( 2021 , Month.FEBRUARY , 23 );
LocalTime lt = LocalTime.of( 18 , 0 , 0 );
ZonedDateTime zdtLondon = ZonedDateTime.of( ld , lt , ZoneId.of( "Europe/London" ) );
OffsetDateTime odtUtc = OffsetDateTime.of( ld , lt , ZoneOffset.UTC );
ZoneOffset offsetLondon = zdtLondon.getOffset();
ZoneOffset offsetUtc = odtUtc.getOffset();
System.out.println( zdtLondon + " has an offset of: " + offsetLondon );
System.out.println( odtUtc + " has an offset of: " + offsetUtc );

我们看到两者与UTC的偏移量都为0小时-分-秒,用Z表示,发音为"Zulu"。

2021-02-23T18:00Z[欧洲/伦敦]的偏移量为:Z

2021-02-23T18:00Z的偏移量为:Z

将月份更改为六月,我们会得到不同的偏移量。伦敦时间显示比UTC提前一小时。

2021-06-23T18:00+01:00[欧洲/伦敦]的偏移量为:+01:00

2021-06-23T18:00Z的偏移量为:Z

英国夏令时从每年3月最后一个星期日的格林尼治标准时间01:00开始,到10月最后一天的格林尼治时间01:00(英国夏令时02:00(结束。

在您的示例中,2月23日表示相同的时间线,甚至在转换之前。对于2021年,要想看到1小时的差距,你必须使用3月28日至10月31日(含(之间的日期,但要有适当的时间。

例如:

val string2 = "Tue Mar 30 18:00:46 BST 2021"
val string1 = "Tue Mar 30 18:00:46 GMT 2021"

收益率:

parsedZdt1.toString: 2021-03-30T18:00:46Z[GMT]
parsedZdt2.toString: 2021-03-30T18:00:46+01:00[Europe/London]

最新更新