1

I would like to convert an String to OffsetDateTime datatype. The string has the following shape:

  2017-11-27T19:06:03

I've tried two approaches:

Approach 1

    public static OffsetDateTime convertString(String timestamp) {
        java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .toFormatter();


        return OffsetDateTime.parse(timestamp, formatter);
    }

Approach 2:

    public static OffsetDateTime convertString(String timestamp) {
        java.time.format.DateTimeFormatter parser = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
        java.time.LocalDateTime dt = java.time.LocalDateTime.parse(timestamp, parser);
        ZonedDateTime zdt = ZonedDateTime.of(dt, java.time.ZoneId.of("UTC"));
        return OffsetDateTime.from(zdt);
    }

First approach does not work since it complains the following:

java.time.format.DateTimeParseException: Text '2017-11-27T19:02:42' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2017-11-27T19:02:42 of type java.time.format.Parsed

For my understanding it comes from the fact that the string does not have ZoneId. How can I overwrite, on the formatter, the ZoneId so to ignore it?

The second approach comes from this question and works but it requieres 2 additional conversions, I would like to avoid those additional conversions.

Any help is going to be appreciated.

pafede2
  • 1,626
  • 4
  • 23
  • 40
  • 1
    What is your expected result? Since the string hasn’t got a time zone or offset in it, you need to decide an offset to use. – Ole V.V. May 18 '18 at 19:45

2 Answers2

5

To get an OffsetDateTime from a string with no offset or time zone, you need to decide an offset or a way to get one. The most obvious way is if you know in which time zone the date-time is to be interpreted. For example:

    OffsetDateTime dateTime = LocalDateTime.parse(timestamp)
            .atZone(ZoneId.of("Asia/Chongqing"))
            .toOffsetDateTime();
    System.out.println(dateTime);

Output using the string from your question:

2017-11-27T19:06:03+08:00

Don’t be afraid of the two conversions from LocalDateTime to ZonedDateTime and then to OffsetDateTime. With java.time they are not only easy to do but also clear to read.

If you know the offset, just use that, then you need only one conversion (I am using a nonsensical offset for the example, so you will have to pick your own):

    OffsetDateTime dateTime = LocalDateTime.parse(timestamp)
            .atOffset(ZoneOffset.ofTotalSeconds(-36953));
    System.out.println(dateTime);

Output:

2017-11-27T19:06:03-10:15:53

You may specify your desired offset as for example ZoneOffset.of("+08:00") or ZoneOffset.ofHours(8).

But to answer your question (it’s about time now).

How can I overwrite, on the formatter, the ZoneId so to ignore it?

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .parseDefaulting(ChronoField.OFFSET_SECONDS, -36953)
            .toFormatter();
    OffsetDateTime dateTime = OffsetDateTime.parse(timestamp, formatter);
    System.out.println(dateTime);

Output is the same as the previous one (and again you will need to pick an offset that makes sense in your situation).

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

Finally, I've solved this issue by the following code:

    public static OffsetDateTime convertString(String timestamp) {
        java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .toFormatter();

    return LocalDateTime.parse(timestamp, formatter)
            .atOffset(java.time.ZoneOffset.UTC);
    }
pafede2
  • 1,626
  • 4
  • 23
  • 40