How to parse offset with colon using DateTimeFormatter?
Asked Answered
A

3

5

I have the following string: String timeStamp = "2020-01-31 12:13:14 +03:00". And I tried to parse it using Java 8 DateTimeFormatter.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern( format );
tmpTimestamp = ZonedDateTime.parse( timeStamp, formatter );

where format is one of:

"yyyy-MM-dd' 'HH:mm:ss' 'Z",
"yyyy-MM-dd' 'HH:mm:ss' 'X",
"yyyy-MM-dd' 'HH:mm:ss' 'x",
"yyyy-MM-dd HH:mm:ss Z",
"yyyy-MM-dd HH:mm:ss X",
"yyyy-MM-dd HH:mm:ss x",

None is working. Always I got DateTimeParseException either pointing to '+' or to ':' character in offset substring "+03:00"

According to JavaDocs: Class DateTimeFormatter "+03:00" shall be supported by any of: Z, X and x.

So the question is how to construct formatter string to parse it?

Adahadaha answered 9/4, 2019 at 18:50 Comment(1)
@MS90 - not LocalDateTime, but rather OffsetDateTime (since it has an offset).Rathskeller
S
4

You should use the times X (yyyy-MM-dd HH:mm:ss XXX):

String timeStamp = "2020-01-31 12:13:14 +03:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
ZonedDateTime tmpTimestamp = ZonedDateTime.parse(timeStamp, formatter);

From the docs:

Offset X and x: This formats the offset based on the number of pattern letters.

One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'.

Two letters outputs the hour and minute, without a colon, such as '+0130'.

Three letters outputs the hour and minute, with a colon, such as '+01:30'.

Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.

Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.

Six or more letters throws IllegalArgumentException.

Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.

Alternative you can use five letters (XXXXX) and you also can use ZZZ or ZZZZZ instead of XXX or XXXXX.

Scaramouch answered 9/4, 2019 at 18:58 Comment(0)
U
4

From the javadoc

Offset Z: This formats the offset based on the number of pattern letters. One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero. Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero. Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero. Six or more letters throws IllegalArgumentException.

You need 5 Z's

String format = "yyyy-MM-dd HH:mm:ss ZZZZZ";

Demo

Unjust answered 9/4, 2019 at 18:56 Comment(0)
S
4

You should use the times X (yyyy-MM-dd HH:mm:ss XXX):

String timeStamp = "2020-01-31 12:13:14 +03:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
ZonedDateTime tmpTimestamp = ZonedDateTime.parse(timeStamp, formatter);

From the docs:

Offset X and x: This formats the offset based on the number of pattern letters.

One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'.

Two letters outputs the hour and minute, without a colon, such as '+0130'.

Three letters outputs the hour and minute, with a colon, such as '+01:30'.

Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.

Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.

Six or more letters throws IllegalArgumentException.

Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.

Alternative you can use five letters (XXXXX) and you also can use ZZZ or ZZZZZ instead of XXX or XXXXX.

Scaramouch answered 9/4, 2019 at 18:58 Comment(0)
S
4

You don’t need to fiddle with a format pattern string.

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendLiteral(' ')
            .appendOffsetId()
            .toFormatter();
    String timeStampString = "2020-01-31 12:13:14 +03:00";
    OffsetDateTime dateTime = OffsetDateTime.parse(timeStampString, formatter);
    System.out.println(dateTime);

It’s wordier, but harder to get wrong. I’m just assembling the formatter from built-in parts. Output is:

2020-01-31T12:13:14+03:00

I am also parsing into an OffsetDateTime instead of a ZonedDateTime. Since the string contains an offset (+03:00) and no time zone (such as America/Boa_Vista), even though it would probably work with a ZonedDateTime, OffsetDateTime is the correct class to use.

Spire answered 10/4, 2019 at 3:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.