CoderJammer
CoderJammer

Reputation: 715

String to LocalDate conversion issue

I have a SpringBoot 2.6.14 web-app with JPA 2.2 and Hibernate 5.

Now I have a String with this format

"2024-03-04T14:10:37.000Z"

And, following some instruction (googling around) I write the following String to LocalData converter:

default LocalDate stringToDate(String data) {
    if (data == null || data.isEmpty()) return null;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    formatter = formatter.withLocale(Locale.getDefault());
    return LocalDate.parse(data, formatter);
}

The parsing works but the result is 2024-03-04, the hour, minutes and seconds are truncated. What's wrong?

Upvotes: 0

Views: 57

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 338564

tl;dr

  • Never put quote marks around the Z. That discards vital information.
  • For any given moment, the date varies around the globe by time zone.
Instant
.parse( "2024-03-04T14:10:37.000Z" )
.atZone( ZoneId.of( "America/Edmonton" ) )
.toLocalDate() 

Or:

LocalDate
.ofInstant (
    Instant.parse( "2024-03-04T14:10:37.000Z" ) ,
    ZoneId.of( "America/Edmonton" )
)

No, not LocalDateTime

Both Answers recommending the LocalDateTime classes are wrong.

That class represents a date with a time-of-day. But your string input contains a third component: offset from the temporal meridian, UTC.

Your input represents a moment, a specific point on the timeline. But the LocalDateTime object cannot represent a moment.

A LocalDateTime object is inherently ambiguous. If we had a LocalDateTime object for noon on January 23rd of 2024, we have no way of knowing if that means noon in Tokyo Japan 🇯🇵, noon in Toulouse France 🇫🇷, or noon in Toledo Ohio US 🇺🇸 — three different moments several hours apart.

Instant

The Z on the end indicates on offset of zero hours-minutes-seconds from UTC. This abbreviation of +00:00 is defined in the ISO 8601 standard.

Parse your input as a Instant object to represent a moment, a specific point on the timeline.

Instant instant = Instant.parse( "2024-03-04T14:10:37.000Z" ) ;

LocalDate

To get a date from a moment, you must specify a time zone. For any given moment, the date varies around the globe by time zone. A single moment can simultaneously be “tomorrow” in Tokyo while also “yesterday” in Toledo.

Define the time zone through which you want to view the date.

ZoneId z = ZoneId.of( "America/Edmonton" ) ;

Apply that zone to our instant to produce a ZonedDateTime.

ZonedDateTime zdt = instant.atZone( z ) ;

Both the Instant object and the ZonedDateTime object represent the very same moment, the same point on the timeline.

Extract the date portion.

LocalDate ld = zdt.toLocalDate() ;

Upvotes: 2

Unmitigated
Unmitigated

Reputation: 89234

LocalDate, as the name suggests, does not include a time. Consider using LocalDateTime instead.

return LocalDateTime.parse(data, formatter);

Upvotes: 2

Related Questions