2

When I pass a Javascript Date to a JAX-RS service I receive:

  1. In case the target field is LocalDate: Text '2018-06-04T22:00:00.000Z' could not be parsed, unparsed text found at index 10". The BackEnd is ok with "2018-06-04", I tried with Postman.
  2. In case the target field is LocalDateTime: Text '2019-04-02T20:16:24.999Z' could not be parsed, unparsed text found at index 23. The BackEnd is ok with "2019-04-02T20:16:24", I tried with Postman.

The information i pass to the BackEnd come from a Angular Material Datepicker component that I map on a javascript Date object.

I understand that the string has informations that the BackEnd do not aspect but I don't know how to pass the correct/modified value before call the POST.

Should I pass a String instead of a Date object? Is that the correct approach?

Is there a way from a date in the format "2018-06-04T22:00:00.000Z" or "2018-06-05T00:00:00.000Z" to be passed to a LocalDate and a LocalDateTime?

I used LocalDate and LocalDateTime because I do not want to deal with timezone. The value are supposed to be always the same even if I change the timezone.

Before I had a problem because there was a 1 hour difference between the server and the client. So when i used to pick a date from the web server it could happen that the client would see the day before on the component becasue it was going back 1 hour from midnight.

Lorenzo
  • 21
  • 1
  • 5
  • The string `2018-06-04T22:00:00.000Z` can be correctly parsed by `Instant`, `ZonedDateTime` and `OffsetDateTime`. I'd suggest using `ZonedDateTime` for most flexible time zone parsing, and so you can easily obtain `LocalDateTime` and `LocalDate` from it. – Andreas Apr 02 '19 at 20:27
  • **Warning:** Note that `2018-06-04T22:00:00.000Z` is probably supposed to be `2018-06-05` in a `UTC+02:00` time zone. If so, you'd likely want to apply that time zone first, before obtaining the `LocalDate` and `LocalDateTime` values, so the "local" is appropriate for *that* time zone. --- To do that, I'd suggest using `Instant.parse("2018-06-04T22:00:00.000Z").atOffset(ZoneOffset.of("+2")).toLocalDate()` – Andreas Apr 02 '19 at 20:29

1 Answers1

7

You seem to be confusing the various date-time types.

Table of date-time types in Java, both legacy and modern.

ISO 8601

The string 2018-06-04T22:00:00.000Z is in standard ISO 8601 format. The Z on the end means UTC, and is pronounced Zulu.

The ISO 8601 formats are wisely designed. They are easy to parse by machine. And they are easy to read by humans across cultures. Their primary purpose is to communicate date-time values in a textual format. You should indeed be using strings in these formats for exchanging date-time values between systems.

Instant

Parse as an Instant in the java.time classes.

Instant instant = Instant.parse( "2018-06-04T22:00:00.000Z" ) ;

LocalDate

The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument. If critical, confirm the zone with your user.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

So you need to decide by what time zone you want to perceive the moment in UTC as a date and time-of-day.

The ISO 8601 format for a date-only value is YYYY-MM-DD.

String output = ld.toString() ;  // Example: 2019-01-23

…and…

LocalDate ld = LocalDate.parse( "2019-01-23" ) ;

To generate such a string in JavaScript, see Format JavaScript Date to yyyy-mm-dd.

OffsetDateTime

If you want UTC itself, convert from Instant to OffsetDateTime. Then extract the date alone.

OffsetDateTime odt = instant.atOffset( ZoneOffsetUTC ) ;  // Convert to the more flexible `OffsetDateTime` class from `Instant` class.
LocalDate ld = odt.toLocalDate() ;                        // Extract a date-only value.

ZonedDateTime

If you want a particular time zone, apply a ZoneId to get a ZonedDateTime. Then extract the date alone.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;    // Adjust from UTC to a time zone.
LocalDate ld = zdt.toLocalDate() ;           // Extract a date-only value, dropping the time-of-day and the time zone.

By the way, note that ZonedDateTime class in its toString method extends the ISO 8601 format by appending the name of the time zone in square brackets. A wise addition, but may not be handled properly by some other systems.

LocalDateTime

The LocalDateTime class is the wrong type to be using for an input such as 2018-06-04T22:00:00.000Z or 2019-04-02T20:16:24.999Z. These string inputs represent a moment, a specific point on the timeline. The LocalDateTime class purposely lacks any concept of time zone or offset, so it cannot represent a moment.

People frequently misunderstand the nature of LocalDateTime. The “Local” means any locality or every locality, but not a particular locality. For a moment in a specific locality, use ZonedDateTime.

For more info, see What's the difference between Instant and LocalDateTime?.


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
  • Thank you for the answer. I know the ones i wrote are instant in the time. That is what Angular Material Datepicker component give me back. I don't want to use them with timezone. I would like them to never change even if i move to other time zones. I will explain better in the description – Lorenzo Apr 02 '19 at 22:18