Pp88
Pp88

Reputation: 1082

Compare ZoneDateTime with different time zones

Hi I've already search for similar questions but without luck. I'm calling a ws that sends me back a token and when it's valid example:

{
   "token": ...,
   "notBefore":"Thu 21 Jul 2022 at 10:50:43",
   "notOnOrAfter":"Thu 21 Jul 2022 at 12:50:43"
}

I know that this dates are GMT+2 (Rome), now I'm taking the current time and convert the two strings:

ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(token.getTimePattern(), Locale.ENGLISH);
ZonedDateTime tokenNotValidAfter = LocalDateTime.parse(token.getNotOnOrAfter(), dateTimeFormatter).atZone(ZoneId.of("GMT+2"));
ZonedDateTime tokenNotValidBefore = LocalDateTime.parse(token.getNotBefore(), dateTimeFormatter).atZone(ZoneId.of("GMT+2"));
if (!currentTime.isAfter(tokenNotValidBefore) || !currentTime.isBefore(tokenNotValidAfter)) {
    throw new CifTokenExpiredException(ExceptionHandlerConfig.CIF_TOKEN_EXPIRED);
}

Now locally everthing is working fine, when i deploy on cloud i get:

ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));

two hours behind.

How can i solve this without adding two hours to currentTime? (doing like this locally will not work)

Regards

Upvotes: 2

Views: 1495

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 340070

The answer by Joop Eggen is correct. I'll add some more complete code example.

I suggest you educate the publisher of your data on two points:

  • Date-time values being exchanged textually should use standard ISO 8601 format rather than inventing a localized format as seen in your case.
  • Moments (specific points on the timeline) should always be communicated in the context of a time zone or offset. Preferably with an offset of zero hours-minutes-seconds. This implied time zone of Rome is just asking for trouble. Or, if not a moment but a time-of-day that should remain the same even if politicians change the time zone rules, then communicate the intended time zone as another field in the date stream, in Continent/Region format such as Europe/Rome.

I suggest adding the ThreeTen-Extra library to your project. Doing so gives you the Interval class that represents a span of time attached to the timeline as a pair of Instant objects. Handy methods include contains, abuts, overlaps, and more.

String inputBegin = "Thu 21 Jul 2022 at 10:50:43";
String inputEnd = "Thu 21 Jul 2022 at 12:50:43";

Locale locale = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE d MMM uuuu 'at' HH:mm:ss" ).withLocale( locale );

ZoneId zoneId = ZoneId.of( "Europe/Rome" ); // Assumed to be the intended time zone.
LocalDateTime beginLdt = LocalDateTime.parse( inputBegin , f );
LocalDateTime endLdt = LocalDateTime.parse( inputEnd , f );

ZonedDateTime begin = beginLdt.atZone( zoneId );
ZonedDateTime end = endLdt.atZone( zoneId );

Interval whenValid = Interval.of( begin.toInstant() , end.toInstant() );
Instant now = Instant.now();
boolean isValidNow = whenValid.contains( now );

System.out.println( begin + "/" + end );
String message = "Interval: " + whenValid + " contains now: " + now + " = " + isValidNow;
System.out.println( message );

2022-07-21T10:50:43+02:00[Europe/Rome]/2022-07-21T12:50:43+02:00[Europe/Rome]

Interval: 2022-07-21T08:50:43Z/2022-07-21T10:50:43Z contains now: 2022-07-21T21:17:54.458095Z = false

Upvotes: 3

Joop Eggen
Joop Eggen

Reputation: 109613

GMT+2 is an offset, Middle Europe +1 hour plus 1 hour summer time. That would go wrong in the coming winter. In fact you are using the incomplete OffsetDateTime, which without Locale is inconclusive for the real Zone.

ZonedDateTime currentTime = ZonedDateTime.now(ZoneId.of("Europe/Rome"));

As you see, no need to revert to LocalDateTime.

Now you can get currentTime.toInstant() for an absolute UTC number.

An Instant is even Comparable, but Before/After is fine.

You assume that before and after limits are also in the Italian time zone, but that may be as it is.

There are some things to consider, because of DST (summer time, daylight savings time):

  • With a count down ("Still 243 hours till the end") you can get awkward jumps of 1 hour per day.
  • Twice a year there is the 02:00-03:00 gap or repetition (Western Europe). These stati can be queried.

Upvotes: 3

Michael Gantman
Michael Gantman

Reputation: 7808

In the cloud time is always considered to be GMT. So the best action is to change
ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));
to

ZonedDateTime currentTime = ZonedDateTime.now()

Upvotes: 1

Related Questions