2

Following code prints output with Date in String with timeZone offset.

String BERLIN_TIME_ZONE = "Europe/Berlin";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
String dateTimeInString = formatter
        .format(ZonedDateTime.of(LocalDateTime.now(), ZoneId.of(BERLIN_TIME_ZONE)));

System.out.println(dateTimeInString); // 2021-06-07T02:12:08+0200

This works perfectly fine. Now, at this point when we have dateTimeInString so I want to convert it back to LocalDateTime object by using parse method.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ssZ");
System.out.println(LocalDateTime.parse(dateTimeInString,formatter));

but this parsing is throwing an exception.

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-06-07T02:12:08+0200' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at de.finhome.A.main(A.java:19)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:461)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {SecondOfMinute=8, MinuteOfHour=12, HourOfAmPm=2, OffsetSeconds=7200, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-06-07 of type java.time.format.Parsed
    at java.base/java.time.LocalTime.from(LocalTime.java:431)
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:457)
    ... 4 more

I have check different resources but couldn't figure out the issue.

9
  • 5
    A LocalDateTime cannot store any time zone or offset, even if the pattern of the formatter used is correct. You have to parse a ZonedDateTime or OffsetDateTime and call toLocalDateTime() on the result. Commented Jun 7, 2021 at 12:23
  • @deHaar No, that's not the issue. Commented Jun 7, 2021 at 12:32
  • 1
    @Michael yes, that's not what causes the exception, but it's an issue, too, as far as I understand OP... OP wants a LocalDateTime to output an offset and that's not possible, is it? Commented Jun 7, 2021 at 12:38
  • 1
    @deHaar ZonedDateTime is convertible to LocalDateTime, all you need to do is throw away the zone. When parsing, even if the string contains a zone, as OP's does, the formatter can parse that into a LocalDateTime no problem. Basically, a parser is not required to use every piece of information. You can parse a string containing date and time into just a LocalTime if you want. The parser just ignores the stuff it doesn't care about. Same principal Commented Jun 7, 2021 at 12:42
  • 1
    @deHaar Yes, Correct !! Commented Jun 7, 2021 at 12:43

2 Answers 2

3

Change the hour token from hh to HH. Lowercase h is 0-12, or what the docs call clock-hour-of-am-pm. Uppercase H is 0-23, or what the docs call hour-of-day.

While the formatter can oblige quite happily when outputting the date, when you try to read in the same string it creates an ambiguity. The parser doesn't know whether ...T01:... is supposed to be 1AM or PM. Since it cannot parse unambiguously, it fails.

Alternatively, add something into your format string for AM/PM (you can use a for that). Then the parser will be able to unambiguously interpret an hour such as 01.

Seems you also want to change LocalDateTime.parse to ZonedDateTime.parse so you're not throwing away the zone.

Sign up to request clarification or add additional context in comments.

9 Comments

but this won't give me my desired output which is 2021-06-07T14:34:13+0200 as soon as we convert it to LocalDateTime, it will discard the offset and will be printed like this 2021-06-07T14:34:13
But Yes, I agree that it will resolve the exception and would work fine.
@Freak I don't follow. Your current code will represent 2PM (14) as 02. If you want it to be 14, you need to use HH, not hh
@Micheal The String I am sending as an argument to parse method is with offset 2021-06-07T14:34:13+0200 mean +0200 in the end but after calling LocalDateTime.parse(dateTime,formatter) it prints 2021-06-07T14:41:55 in which offset is missing.
@Freak The string in your example given in the question is 2021-06-07T02:12:08+0200. In the example in your question, you read back in a string that the same formatter outputs. There is no way that formatter can output ...T14:... If the example does not represent your actual problem, please change it.
|
1

This does not look like a situation where one should use a LocalDateTime.

There are two alternatives: ZonedDateTime as you already use and OffsetDateTime, which you might want to use...

If you want to provide a zone, take the current moment in time in that zone and print the result without the explicit zone but with the offset of that zone, then I recommend to stick to a ZonedDateTime for most of the time.

Do something like this:

public static void main(String[] args) {
    // provide a zone
    String BERLIN_TIME_ZONE = "Europe/Berlin";
    // use ZonedDateTime.now() directly and pass the zone
    ZonedDateTime nowBerlin = ZonedDateTime.now(ZoneId.of(BERLIN_TIME_ZONE));
    // then create a String that actually keeps the offset and omits the zone
    String dateTimeInString = nowBerlin.format(
                                DateTimeFormatter.ISO_OFFSET_DATE_TIME
                              );
    // print the result
    System.out.println(dateTimeInString);
    
    // if you now want to convert back, use an OffsetDateTime
    OffsetDateTime nowPlus2h = OffsetDateTime.parse(dateTimeInString);
    // and print the result
    System.out.println(nowPlus2h.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
    // if you want it to not just be a time of 2 hours offset, apply the zone again
    ZonedDateTime nowAgainBerlin = nowPlus2h.atZoneSameInstant(
                                        ZoneId.of(BERLIN_TIME_ZONE)
                                    );
    // check if that's the same as parsed in the beginning
    if (nowAgainBerlin.equals(nowBerlin)) {
        System.out.println("Same instant in Berlin");
    } else {
        System.out.println("Something went wrong in Berlin");
    }
    
    // and if you really want to get a LocalDateTime, you can get it like this
    LocalDateTime localBerlin = nowBerlin.toLocalDateTime();
    LocalDateTime localAgainBerlin = nowPlus2h.toLocalDateTime();
    
    System.out.println(localBerlin + " == " + localAgainBerlin);
}

This just output

2021-06-07T15:16:47.259+02:00
2021-06-07T15:16:47.259+02:00
Same instant in Berlin
2021-06-07T15:16:47.259 == 2021-06-07T15:16:47.259

If you want to not have millis in your output, then define a formatter that suits your desires, but still, you won't be able to parse zones or offsets to a LocalDateTime.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.