0

to summarize my question, I have 2 different ZonedDateTime objects with GMT and BST but same local time. They become the same Instant values after toInstant conversion. I am expecting after conversion, they should be different values because although they are both 'Tue Feb 23 18:00:46 2021', the strings are representing time for different time zones. I am not sure whether this is a bug of library itself or I am doing something wrong.

I have 2 different ZonedDateTime generated from this piece of Scala code:

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)

This prints out:

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

However when I convert them to instant:

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

I got this printed out:

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

My questions are

  1. Why do the 2 values become the same after toInstant conversion?
  2. Are the 2 values representing same time even before toInstant, i.e. , are parsedZdt1 and parsedZdt2 representing the same moment?

Thank you!

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • BST -- British Summer TIme -- does not exist in February. In February London and the UK are on GMT. – Ole V.V. Aug 04 '22 at 11:17
  • Where have you got those strings from? Could it be that by BST they intended one of Brazil/ian Summer Time, Bangladesh Standard Time, Bougainville Standard Time? All of these are taken from [Time Zone Abbreviations – Worldwide List](https://www.timeanddate.com/time/zones/). BTW a nice illustration why you should never use time zone abbreviations for transferring time zone information. They are so often ambiguous. – Ole V.V. Aug 04 '22 at 11:58
  • Thanks Ole! I was using an arbitrary string as input and I was not aware that BST and GMT can be the same sometimes as Basil and Alin pointed out in the answers. The problem I was trying to resolve was to interpret BST as British Summer Time rather than Bougainville Standard Time. I saw a similar question and was testing this appendZoneText method you put forward in that question. I agree zone name abbreviation should not be used. In my case, this is from upstream systems so unfortunately, I cannot use ZoneId in the original string. – Adrian Qin Aug 04 '22 at 14:23

2 Answers2

1

BST begins at 01:00 GMT every year on the last Sunday of March and ends at 01:00 GMT (02:00 BST) on the last Sunday of October.

In your example - 23rd of Feb represent the same time line even before the conversion. For the 2021 year, to see the 1 hour gap difference, you have to use a date between 28 March - 31 October inclusive, but with the appropriate hour.

E.g.:

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

yields:

parsedZdt1.toString: 2021-03-30T18:00:46Z[GMT]
parsedZdt2.toString: 2021-03-30T18:00:46+01:00[Europe/London]
Alin Gabriel Arhip
  • 2,568
  • 1
  • 14
  • 24
1

tl;dr

You said:

the strings are representing time for different time zones

Different time zones, yes, but the time zones happen to share the same offset on that particular date. Many time zones share the same offset, coincidentally, on particular dates.

London time is GMT/UTC time, sometimes, when not observing Daylight Saving Time (DST).

BST = GMT (sometimes)

If by BST, you mean the time zone Europe/London, that zone had an offset of zero hours from UTC/GMT on that date of 2021-02-23.

So 6 PM on February 23rd in London time was also 6 PM in GMT.

Later in the year, from March 28, 2021 to October 31, 2021, the UK observes DST. During those months their offset is one hour ahead of UTC.

See Time Change 2021 in England, United Kingdom on TimeAndDate.com.

Example code

Let’s compare two moments using 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()
    ) ;

See this code run live at Ideone.com.

true

Change the month to June, during Daylight Saving Time observance.

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()
    ) ;

false

ZoneOffset

Also, you can directly interrogate for the offset of a moment, in both ZonedDateTime and OffsetDateTime objects. Call getOffset to get a ZoneOffset object.

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 );

We see both have an offset of zero hours-minutes-seconds from UTC, indicated by a Z, pronounced “Zulu”.

2021-02-23T18:00Z[Europe/London] has an offset of: Z

2021-02-23T18:00Z has an offset of: Z

Change the month to June, and we get different offsets. London time shows an hour ahead of UTC.

2021-06-23T18:00+01:00[Europe/London] has an offset of: +01:00

2021-06-23T18:00Z has an offset of: Z

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154