tl;dr
LocalDateTime // Represent a date with time-of-day but lacking the context of an offset-from-UTC or a time zone. Does *not* represent a moment, is *not* a point on the timeline.
.parse(
"2024-06-28 15.00.00" , // Best to *not* invent custom formats for such textual inputs. Better to exchange date-time values textually using only ISO 8601 standard formats.
DateTimeFormatter.ofPattern( "uuuu-MM-dd HH.mm.ss" )
) // Returns a `LocalDateTime` object.
.atZone( ZoneId.of( "America/Phoenix" ) ) // Returns a `ZonedDateTime` object. Determines a moment, a point on the timeline, by applying the context of a time zone.
.toInstant() // Returns a `Instant` object. Same point on the timeline, but seen through an offset-from-UTC of zero hours-minutes-seconds.
.isBefore( Instant.now() ) // Compares to the current moment as seen in UTC (an offset of zero).
UTC is your friend
Programmers and sysadmins should learn to think and work in UTC, date-time moments as seen with an offset of zero hours-minutes-seconds from the temporal meridian of UTC. Regard UTC as the One True Time. All other time zones are but mere variations.
So we redefine your problem as two phases:
- We receive a text input of a date with time-of-day. Unfortunately,this input has two flaws. (A) The text is not in standard ISO 8601 format. (B) The text represents a moment as seen in the wall-clock/calendar of a particular time zone (
America/Phoenix
) but that crucial fact is not included within the input text.
- We must compare the moment represented by this text input to the current moment. We want to know if the intended moment is past or future.
ISO 8601
The ideal solution to the flawed input would educating the publisher of that data about the ISO 8601 standard. The input 2024-06-28 15.00.00
shared instead be 2024-06-28T15:00:00-07:00
.
OffsetDateTime
The java.time classes use ISO 8601 formats by default. So such a standard string can be directly parsed without needing to define any formatting pattern. We get an OffsetDateTime
object.
OffsetDateTime odt = OffsetDateTime.parse( "2024-06-28T15:00:00-07:00" ) ;
Correcting the data published to use ISO 8601 standard formats really is the ideal solution. ISO 8601 was invented expressly for exchanging date-time values textually in way that works well for machines, and works well for humans across cultures.
LocalDateTime
If fixing the inputs is not possible, then we must parse the input using a class that represents a date with time-of-day but lacks the context of an offset or time zone. That class would be LocalDateTime
.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH.mm.ss" ) ;
LocalDateTime ldt = LocalDateTime.parse( "2024-06-28 15.00.00" , f ) ;
Be aware that `LocalDateTime does not represent a moment, is not a point on the timeline.
ZonedDateTime
We have been assured that our text input for date and time is meant to be seen though the time zone of America/Phoenix
. So assign that zone to create a ZonedDateTime
object.
ZoneId z = ZoneId.of( "America/Phoenix" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Instant
Now we have a moment, a point on the timeline. Adjust from that zone to UTC, our One True Time.
The easiest way to adjust to UTC is to extract an Instant
object. The Instant
class is the building block of the java.time framework. It represents a moment as seen in UTC, always in UTC.
Instant instant = zdt.toInstant() ;
Capture the current moment.
Instant now = Instant.now() ;
Compare.
Boolean isPast = instant.isBefore( now ) ;
Focus on UTC
check if this date is before the current MST time.
No. Change your thinking to focus on UTC.
So, we need to check if the passed moment is before the current moment.
Pseudo time zones
MST
“MST” is not a real time zone. That text is a pseudo zone which merely hints at a real zone, and indicates whether Daylight Saving Time (DST) is observed on that date and time. Such pseudo zones are not standardized; they are not even unique!
Use only real time zones in your discussion and your logic. The pseudo zones should only be used in generated localized text for display to the user.
Real time zones have names in the format of Continent/Region
.
Never call LocalDateTime.now
LocalDateTime.now(
I cannot imagine a scenario where calling LocalDateTime.now
is the correct or optimal thing to do. "now" means you intend a specific point on the timeline. The LocalDateTime
class cannot represent a specific point on the timeline.
Set servers to UTC
Essentially if I end up in another server in Australia
Servers should have their default time zone set the UTC.
Also, keep mind that a server can have multiple default time zones. These include a default in the OS, a default in any database server, and a default within the JVM.
You should always write your code in such a way as to avoid depending on external factors such as the host OS’ current default time zone. You do not want your code to break just because of some sys-admin changing a time zone setting. The key is to always specify explicitly a desired/expected time zone; always pass an optional time zone or offset argument rather than rely implicitly on default.
Notice how the example code in this Answer is impervious to changes in the OS’ default zone.