Thiagarajan Ramanathan
Thiagarajan Ramanathan

Reputation: 1124

Difference between give date (UTC date) and current date in days using Java 8

Input to my method will be a String containing a date in UTC. I need to compare the input date with current date and time and check the difference between two dates. The result should be in days.

I tried the following with no success.

String dateString = "2019-06-18T16:23:41.575 UTC";
final DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS 'UTC'").withZone(ZoneId.of("UTC"));
OffsetDateTime parsedDate  = OffsetDateTime.parse(dateString, formatter1);
System.out.println("======================:"+parsedDate.format(formatter1));


OffsetDateTime currentUTC = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("Until (with crono): " + parsedDate.until(currentUTC, ChronoUnit.DAYS));

I need the result in an int (i.e., number of days).

The line OffsetDateTime parsedDate = OffsetDateTime.parse(dateString, formatter1); throws an exception with the following stack trace:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2019-06-18T16:23:41.575 UTC' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1959)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1894)
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at thiagarajanramanathan.misc.App.main(App.java:86)
Caused by: java.time.DateTimeException: Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:370)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1890)
    ... 3 more
Caused by: java.time.DateTimeException: Unable to obtain ZoneOffset from TemporalAccessor: {InstantSeconds=1560875021},ISO,UTC resolved to 2019-06-18T16:23:41.575 of type java.time.format.Parsed
    at java.base/java.time.ZoneOffset.from(ZoneOffset.java:348)
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:359)
    ... 5 more

Upvotes: 1

Views: 374

Answers (3)

Anonymous
Anonymous

Reputation: 86379

The difference between an time zone and an offset

You have got two good answers already. You are touching on an interesting and a bit tricky part of java.time, so I should like to make my contribution too. My key point is that a time zone and a UTC offset are not the same. To obtain an OffsetDateTime you need an offset. You provide a time zone through the call .withZone(ZoneId.of("UTC")) on the formatter, but it doesn’t help you. Yes, you and I know that UTC is the base of all offsets and therefore itself defines an offset of 0. But Java didn’t discover that from your code.

I admit I was surprised to discover that the following simple change was enough that your code runs on Java 9:

    final DateTimeFormatter formatter1
            = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS 'UTC'")
                    .withZone(ZoneOffset.UTC);

However on Java 8 I still get the same exception as before. The output I got on Java 9.0.4 was:

======================:2019-06-18T16:23:41.575 UTC
Until (with crono): 0

The only change is that I am now passing a ZoneOffset rather than a ZoneId object to withZone (this is possible because ZoneOffset is a subclass of ZoneId).

A formatter that works on Java 8 too is one where we supply a default offset. For that we need a DateTimeFormatterBuilder:

    final DateTimeFormatter formatter1 = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendLiteral(" UTC")
            .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
            .toFormatter();

Yet another and perhaps simpler option would be to parse into a LocalDateTime first (which requires neither offset nor time zone) and then convert to OffsetDateTime by calling .atOffset(ZoneOffset.UTC).

Upvotes: 1

Basil Bourque
Basil Bourque

Reputation: 340070

Parsing

I would simplify the parsing if your input by getting it to comply with the ISO 8601 standard.

String input = "2019-06-18T16:23:41.575 UTC".replace( " UTC", "Z" ) ;
Instant instant = Instant.parse( input ) ;

Days as 24-hour chunks

If your definition of elapsed days is 24-hour chunks of time, use Duration.

Duration d = Duration.between( instant , Instant.now() ;
long days = d.toDays() ;

Days according to calendar

If you want a count of days elapsed as seen on the calendar, meaning dates rather than 24-hour chunks of time, you must specify a time zone.

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

Extract the dates.

LocalDate start = zdt.toLocalDate() ;
LocalDate stop = now.toLocalDate() ;
long days = ChronoUnit.DAYS.between( start , stop ) ;

Upvotes: 1

AntiqTech
AntiqTech

Reputation: 717

As you can see from this thread: Unable to obtain OffsetDateTime from TemporalAccessor
I changed the following lines:

//OffsetDateTime parsedDate  = OffsetDateTime.parse(dateString, formatter1);
ZonedDateTime parsedDate = ZonedDateTime.parse(dateString, formatter1);

When your code is run with this modification, I could get the following results

for "2019-06-18T16:23:41.575 UTC" :

======================:2019-06-17T16:23:41.575 UTC
Until (with crono): 0

Since it's less than 24 hours, it returns 0

for "2019-06-17T16:23:41.575 UTC" :

======================:2019-06-17T16:23:41.575 UTC
Until (with crono): 1

Similarly, since it's over 24 hours but under 2 days, it returns 1.

I think this is what you want. Please try it and let me know if this works for you.

Upvotes: 2

Related Questions