33

When I do this

String datum = "20130419233512";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.of("Europe/Berlin"));
OffsetDateTime datetime = OffsetDateTime.parse(datum, formatter);

I get the following exception:

    java.time.format.DateTimeParseException: Text '20130419233512' could not be parsed: 
Unable to obtain OffsetDateTime from TemporalAccessor: {InstantSeconds=1366407312},ISO,Europe/Berlin resolved 
to 2013-04-19T23:35:12 of type java.time.format.Parsed

How can I parse my datetime string so that it is interpreted as always being from the timezone "Europe/Berlin" ?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
asmaier
  • 11,132
  • 11
  • 76
  • 103

3 Answers3

35

The problem is that there is a difference between what a ZoneId is and a ZoneOffset is. To create a OffsetDateTime, you need an zone offset. But there is no one-to-one mapping between a ZoneId and a ZoneOffset because it actually depends on the current daylight saving time. For the same ZoneId like "Europe/Berlin", there is one offset for summer and a different offset for winter.

For this case, it would be easier to use a ZonedDateTime instead of an OffsetDateTime. During parsing, the ZonedDateTime will correctly be set to the "Europe/Berlin" zone id and the offset will also be set according to the daylight saving time in effect for the date to parse:

public static void main(String[] args) {
    String datum = "20130419233512";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.of("Europe/Berlin"));
    ZonedDateTime datetime = ZonedDateTime.parse(datum, formatter);

    System.out.println(datetime.getZone()); // prints "Europe/Berlin"
    System.out.println(datetime.getOffset()); // prints "+02:00" (for this time of year)
}

Note that if you really want an OffsetDateTime, you can use ZonedDateTime.toOffsetDateTime() to convert a ZonedDateTime into an OffsetDateTime.

Community
  • 1
  • 1
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 2
    I like that you do this in one step, rather than in two like I showed. I'll leave my answer since both will work, but I'd recommend yours for the green checkmark. :) – Matt Johnson-Pint Feb 09 '16 at 17:43
  • 4
    Since I need OffsetDateTime I use now `OffsetDateTime datetime = ZonedDateTime.parse(datum, formatter).toOffsetDateTime();` . – asmaier Feb 09 '16 at 17:49
  • 1
    @asmaier Yep, that's what I commented also. You can use that to convert to an `OffsetDateTime`. – Tunaki Feb 09 '16 at 17:50
  • The documentation of that method says "The zone ID is ignored". What does that mean exactly? – malthe Oct 02 '22 at 20:51
15

There's no offset in your source data, and thus OffsetDateTime is not the correct type to use during parsing.

Instead, use a LocalDateTime, since that is the type that most closely resembles the data you have. Then use atZone to assign it a time zone, and if you still need an OffsetDateTime, you can call toOffsetDateTime from there.

String datum = "20130419233512";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
LocalDateTime datetime = LocalDateTime.parse(datum, formatter);
ZonedDateTime zoned = datetime.atZone(ZoneId.of("Europe/Berlin"));
OffsetDateTime result = zoned.toOffsetDateTime();
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Thanks. That works for me. I somehow assumed the OffsetDateTime.parse() method would do these steps internally for me. – asmaier Feb 09 '16 at 17:44
  • This one works perfectly, I somehow thought the same thing as OP. This looks neat! – BenBen Sep 13 '18 at 16:01
0

Actually, I faced similar issue when I made a parsing from String to ZonedDateTime and needed to get OffsetDateTime.

There is excellent answer: https://stackoverflow.com/a/53071826/16543524 (can't make comments)