1

I am very new to OffsetDateTime usage and I am trying to compare OffsetDateTime strings with OffsetDateTime.now() in java this way,

import java.time.OffsetDateTime;

public class OffsetDateTimeDemo {
   public static void main(String[] args) {

      OffsetDateTime one = OffsetDateTime.parse("2017-02-03T12:30:30+01:00");
      System.out.println("First ::" + OffsetDateTime.now().compareTo(one));

      OffsetDateTime date1 = OffsetDateTime.parse("2019-02-14T00:00:00");
      System.out.println("Second ::" +  OffsetDateTime.now().compareTo(date1));

      OffsetDateTime date3 = OffsetDateTime.parse("Mon Jun 18 00:00:00 IST 2012");
      System.out.println(" Third :: " +OffsetDateTime.now().compareTo(date3));


   }
}   

But I am getting java.time.format.DateTimeParseException in all the 3 cases.

However if i compare 2 OffsetDateTime Strings with CompareTo method its working fine.

Can someone shed some light to me in this regard and kindly guide me through my mistake.

Thanks in Advance.

user1660325
  • 747
  • 4
  • 20
  • 35
  • 1
    Your second date-string has no offset – Lino Feb 20 '19 at 16:22
  • 1
    And the third input cannot be parsed to `OffsetDateTime` but to `ZonedDateTime`. – Meno Hochschild Feb 20 '19 at 17:37
  • @Meno Hochschild tried as you suggested. Is this is right? String date3 = "Mon Jun 18 00:00:00 IST 2012"; DateTimeFormatter format = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); OffsetDateTime offsetDateTime = ZonedDateTime.parse(date3, format).toOffsetDateTime(); System.out.println("offsetDateTime ::" + offsetDateTime); System.out.println(" offsetDateTime compareTo :: " +OffsetDateTime.now().compareTo(offsetDateTime)); – user1660325 Feb 20 '19 at 18:37
  • @Meno Hochschild but it is always returning 1 only – user1660325 Feb 20 '19 at 18:44
  • @user1660325 That’s as I would expect since “now” is after the parsed date-time in all cases. As an aside, “The comparison is based on the instant then on the local date-time.” ([docs](https://docs.oracle.com/javase/9/docs/api/java/time/OffsetDateTime.html#compareTo-java.time.OffsetDateTime-)) Is this what you wanted? – Ole V.V. Feb 21 '19 at 07:36
  • Don’t rely on parsing `IST` as a time zone. You may get Iceland time, Irish summer time, Israel standard time or India Standard Time (these are the possibilities I know of, there may be more). – Ole V.V. Feb 21 '19 at 09:25

1 Answers1

4

Your compareTo coding is a distraction. Your exception is about parsing the string inputs into objects.

Another problem: You are using wrong classes on the 2nd and 3rd inputs.

Another problem: You are relying implicitly on your JVM’s current default time zone when calling now(). Poor practice as any programmer reading will not know if you intended the default or if you were unaware of the issue as are so many programmers. Furthermore, the current default can be changed at any moment during runtime by any code in any thread of any app within the JVM. So better to always specify explicitly your desired/expected zone or offset.

OffsetDateTime.now( 
    ZoneOffset.UTC
)

Or better yet, use a ZonedDateTime to capture more information than a OffsetDateTime.

ZonedDateTime.now(
    ZoneId.of( "Pacific/Auckland" )
)

First: OffsetDateTime works

Your first string input is proper, and parses successfully.

OffsetDateTime.parse( "2017-02-03T12:30:30+01:00" )

Full line of code:

OffsetDateTime odt = OffsetDateTime.parse( "2017-02-03T12:30:30+01:00" ) ;

See this code run live at IdeOne.com.

odt.toString(): 2017-02-03T12:30:30+01:00

To compare, extract an Instant. Doing so effectively adjusts your moment from some offset to an offset of zero, or UTC itself. An Instant is always in UTC, by definition.

Instant instant = Instant.now() ;                          // Capture the current moment as seen in UTC.
boolean odtIsPast = odt.toInstant().isBefore( instant ) ;

Second: LocalDateTime

Your second string input lacks any indicator of offset-from-UTC or time zone. So an OffsetDateTime is the wrong class to use. Instead use LocalDateTime which lacks any concept of offset or zone.

This means a LocalDateTime cannot represent a moment. For example, noon on the 23rd of January this year could mean noon on Asia/Tokyo which would be hours earlier than noon in Europe/Paris, or it could mean noon in America/Montreal which would be a moment even more hours later. Without the context of a zone or offset, a LocalDateTime has no real meaning. So comparing a LocalDateTime to the current moment is senseless.

LocalDateTime.parse( "2019-02-14T00:00:00" )

See this code run live at IdeOne.com.

ldt.toString(): 2019-02-14T00:00

To compare, you can’t — illogical as discussed above. You must assign a time zone (or offset) to determine a moment on the timeline. If you know for certain this date and time were meant for a specific time zone, assign ZoneId to get a ZonedDateTime. Then extract a Instant to compare.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;                   // India time.
ZonedDateTime zdt = ldt.atZone( z ) ;
Instant instant = Instant.now() ;                          // Capture the current moment as seen in UTC.
boolean zdtIsPast = zdt.toInstant().isBefore( instant ) ;  // Compare.

By the way, I noticed the time-of-day is zero. If your goal was to represent the date only, without any time-of-day and without any zone, use LocalDate class.

Third: Don’t bother, ambiguous input

Your third string input carries a time zone indicator. So it should be parsed as a ZonedDateTime.

Unfortunately, you’ve chosen a terrible string format to parse. Never use the 2-4 character pseudo-zones like IST. They are not standardized. And they are not unique! Your IST could mean Ireland Standard Time or India Standard Time or others.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

See this code run live at IdeOne.com.

zdt.toString(): 2019-02-20T22:34:26.833+01:00[Africa/Tunis]

You could try to parse this. ZonedDateTime will make a guess as to which zone was meant by IST. But it would be just a guess, and so is unreliable given the inherently ambiguous input. Personally, I would refuse to code that, rejecting this input data back to its source.

If you insist on making this unreliable parse attempt, see the correct Answer to a similar Question you asked recently.

Educate your source about always using standard ISO 8601 formats to exchange date-time values as human-readable text.

The java.time classes use these ISO 8601 formats by default when parsing/generating strings. The ZonedDateTime class wisely extends the standard to append the standard name of the time zone in square brackets.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

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