Search code examples
javaspring-boot

Consistent time zone for date comparison


I am looking to pass in a date String and check if this date is before the current MST time.

I want to be able to reliably test this locally and when I deploy it.

Locally I am based in the UK. And when I deploy it, server is in Phoenix.

The time now in UK is 2024-06-28 15.45.00 and this logic produces true for isValidDate at present when I pass in 2024-06-28 15.00.00.

But I am setting the zone to MST. I was expecting this to be false.
MST time is like 8am now. So it's not before. It seems to continue to work against UK time.

How can I update this so that when I deploy it, it will check the date string against MST time. And locally continue to run for MST too? Essentially if I end up in another server in Australia, logic should continue to work against MST time.

private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH.mm.ss");
private static final ZoneId MST_TIMEZONE = ZoneId.of("America/Phoenix");

// Spring bean set to Clock.systemDefaultZone(); Can't change this.
// using a clock for unit testing purposes.
private final Clock clock;

private ZonedDateTime parseDate(String dateStr) {
    try {
        return LocalDateTime
                .parse(dateStr, DATE_FORMATTER)
                .atZone(MST_TIMEZONE);
    } catch (DateTimeParseException e) {
        return null;
    }
}

private boolean isValidDate(String startDateTime) {
    ZonedDateTime start = parseDate(startDateTime);        
    return start != null
            && start.isBefore(LocalDateTime.now(clock).atZone(MST_TIMEZONE));
}

Solution

  • I think the problem you've got here is with this:

    LocalDateTime.now(clock).atZone(MST_TIMEZONE)
    

    This will do different things depending on the time zone of the JVM you are running it in.

    LocalDateTime.now(clock) will give you the local time in the JVM's timezone - since we're both in London, let's say that 2024-06-28 16:46:23. Invoking atZone(MST) on that gives you a ZonedDateTime which is 2024-06-28 16:46:23 -08:00.

    If you had run that on a server in Phoenix, LocalDateTime.now(clock) would have got 2024-06-28 08:46:23; invoking atZone(MST) on that gives you 2024-06-28 08:46:23 -08:00.

    If your intention is to get the current time in MST_TIMEZONE, change it to:

    clock.now().atZone(MST_TIMEZONE)
    

    clock.now() gives you an Instant, which is time zone-agnostic type. The Instant corresponding to the time I wrote above is Instant.ofSeconds(1719593183L). Converting that to a ZonedDateTime gives the LocalDateTime in that zone, plus the zone.