Search code examples
javaspring-bootzoneddatetimejava-calendar

Converting Date String to ZonedDateTime


I'm receiving a query parameter date, as yyyy-MM-DD (2022-03-08).
I want to conver this to java.util.Calendar / java.util.GregorianCalendar formmat.

So my idea is converto: String -> ZonedDateTime -> Calendar.

What I did:

ZonedDateTime parsedDate = ZonedDateTime.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//date = 2022-03-08

even with the correct format, I'm getting:

Text '2022-03-08' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2022-03-08 of type java.time.format.Parsed

I found out that this error occurs because my string does not have a TimeZone.

One suggestion was to use LocalDate

 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
 LocalDate date = LocalDate.parse(fecha, formatter);

but I can't use localDate as an argument for ZonedDateTime.parse().

What else could I try?


Solution

  • I want to conver this to java.util.Calendar / java.util.GregorianCalendar formmat.

    That seems silly; Calendar/GregorianCalendar is obsolete, and the API is horrendous. Why use a broken screwdriver when there's a shiny new one right there in the toolbox? Don't do this.

    So my idea is converto: String -> ZonedDateTime -> Calendar.

    That seems silly. The string does not contain a ZonedDateTime. It doesn't even contain a LocalDateTime. It is clearly a LocalDate. So, convert it to a localdate, and you go from there.

    The power of the java.time package is that each different concept in time has a matching type in the j.t package that is properly named. For example, java.util.Date is a lie: It is a timestamp, and it has nothing whatsoever to do with dates; asking a Date object for 'what year is it', is broken (try it, you get a warning).

    Calendar, similarly, is an utter falsehood. It does not represent a calendar at all; it, too, represents a timestamp.

    LocalDate on the other hand is perfect truth: It represents a date (not a time), and it does not include timezone or other localizing information: It makes sense only as 'locally'.

    Each stop should just make sense, on its own:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd");
    LocalDate date = LocalDate.parse("2022-10-01", formatter);
    

    So far, so good. I'd just stop there - why lie? Why return a Calendar which is both API wise a lie (that class does not represent calendars), and even if someone knows exactly what Calendar is, it's still a lie: A calendar implies it has exact time and a timezone. You do not have a time, and also don't have a timezone. Why return something that suggests stuff that isn't there?

    But, if you MUST, then explicitly add a timezone and a time, and THEN go for it:

    ZonedDateTime zdt = someLocalDate.atStartOfDay().atZone(ZoneId.of("Europe/Amsterdam"));
    GregorianCalendar gc = GregorianCalendar.from(zdt);
    

    This code is clear and legible: It makes crystal clear that the code picks a time, and picks a zone.

    But, again, now you ended up with a horrible, horrible object you should not be using, for anything.