0

I am trying to parse the following date string received from a Bitbucket event payload:

2017-09-19T10:39:36+1000

When the incoming date is in offset +0000 then it works but +1000 does not.

This is a slightly non-standard (from the JDK's perspective) date string in that it has no colon in the offset. So I have made a custom DateTimeFormatter that works when the offset is +0000:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    .optionalStart()
    .appendOffset("+HHMM", "+0000")
    .optionalEnd()
    .toFormatter();

However, when the offset is +1000 as above, it fails with:

Cannot deserialize value of type java.time.OffsetDateTime from String "2017-09-19T10:39:36+1000": Failed to deserialize java.time.OffsetDateTime: (java.time.format.DateTimeParseException) Text '2017-09-19T10:39:36+1000' could not be parsed at index 19

If the received date string is using offset +0000 then it works. How can I parse all time zones?

Update - Extra context:

This is being used to construct an instance of JavaTimeModule used to inform the ObjectMapper of the incoming date format:

JavaTimeModule javaTimeModule = new JavaTimeModule();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    .optionalStart()
    .appendOffset("+HHMM", "+0000")
    .optionalEnd()
    .toFormatter();
// This also fails:
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssx");
LocalDateTimeDeserializer deserializer = new LocalDateTimeDeserializer(formatter);
javaTimeModule.addDeserializer(LocalDateTime.class, deserializer);
// MAPPER is an instance of com.fasterxml.jackson.databind.ObjectMapper
MAPPER.registerModule(javaTimeModule);
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Friedrich 'Fred' Clausen
  • 3,321
  • 8
  • 39
  • 70
  • which version of jackson you are using? – Neenad May 01 '19 at 05:06
  • https://stackoverflow.com/questions/33250878/datelong-1000-format the +1000 means its formatted in UTC+10:00 – Neenad May 01 '19 at 05:08
  • I am using the Jackson bundled with Dropwizard 1.3.7. And, yes, +1000 means UTC+10:00. I'd like to parse that and other time zones – Friedrich 'Fred' Clausen May 01 '19 at 05:15
  • As mentioned in the seemingly now deleted answer - that works standalone but not when used as shown in the context update above. The JavaTimeModule added to the ObjectMapper does not accept it. – Friedrich 'Fred' Clausen May 01 '19 at 05:18
  • please provide the object you are deserializing using jackson MAPPER – Neenad May 01 '19 at 05:57
  • I cannot reproduce. [See your code running online here](https://ideone.com/ippi15). – Ole V.V. May 01 '19 at 07:49
  • As an aside, is there any point in specifying the offset as optional? You need one for constructing an `OffsetDateTime`. Isn’t there always an offset in the string from the Bitbucket event? – Ole V.V. May 01 '19 at 07:54
  • This may be related to running with the Dropwizard bundled Jackson libraries. I’ll do some standalone experiments to see if it works. As for the optional offset - I don’t know why I did it that way initially. I’ll make it non-optional. – Friedrich 'Fred' Clausen May 01 '19 at 10:23

2 Answers2

0

For parsing +1000 this below code will work.

package com.iamninad.qa;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class TimeFormat {

    public static void main(String[] args) throws IOException {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
        System.out.println(dateTimeFormatter.parse("2017-09-19T10:39:36+1000"));
        LocalDateTimeDeserializer deserializer = new LocalDateTimeDeserializer(dateTimeFormatter);

        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(LocalDateTime.class, deserializer);
        ObjectMapper MAPPER = new ObjectMapper();
        MAPPER.registerModule(javaTimeModule);

        // serialize object

        String s = MAPPER.writeValueAsString(new Data());
        System.out.println(s);

        // deserialize object

        String json = "{\"date\":\"2017-09-19T10:39:36-0830\"}";
        String json1 = "{\"date\":\"2017-09-19T10:39:36+1000\"}";

        Data data = MAPPER.readValue(json, Data.class);
        System.out.println(data.toString());

        Data data1 = MAPPER.readValue(json1, Data.class);
        System.out.println(data1.toString());
    }

}

class Data {
    // Just to generate a sample data
    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
    private LocalDateTime date = LocalDateTime.parse("2017-09-19T10:39:36+1000", dateTimeFormatter);

    public LocalDateTime getDate() {
        return date;
    }

    public void setDate(LocalDateTime date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Data{" +
                "date=" + date +
                '}';
    }
}

If you want to parse +10:00 then use ISO_OFFSET_DATE_TIME for fields in format +10:00 or pattern yyyy-MM-dd'T'HH:mm:ssXXX it will either be in any one format. I guess this issue is resolved in jdk 9

OffsetDateTime.parse("2017-09-19T10:39:36+10:00")

Also parses time in only one format i.e +10:00 and not in +1000 you need to specify formatter to parse method

OffsetDateTime.parse("2017-09-19T10:39:36+1000",DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZ"))
Neenad
  • 861
  • 5
  • 19
0

The Z pattern can parse that offset. Have you tried to use this:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .append(ISO_LOCAL_DATE_TIME)
        .appendPattern("Z")
        .toFormatter();

It can parse +0000 and +1000.

assylias
  • 321,522
  • 82
  • 660
  • 783