0

I have to parse a String to a timestamp in UTC. The String can have those format :

  • YYYY-MM-DDThh:mm:ss.sssZ
  • YYYY-MM-DDThh:mm:ss.sss+/-hh:mm
  • YYYY-MM-DDThh:mm:ss.sss (considered at UTC, so add a Z at the end)

What's the best way to do this and avoid :

    try {
        firstDateTimeFormatter.parse(string, Instant::from).toEpochMilli();
    } catch (DateTimeParseException e) {
        try {
            secondDateTimeFormatter.parse(string, Instant::from).toEpochMilli();
        } catch (DateTimeParseException e2) {
                thirdDateTimeFormatter.parse(string, Instant::from).toEpochMilli();
        }
    }
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
BnJ
  • 1,024
  • 6
  • 18
  • 37

1 Answers1

1

There are various options. Here’s a simple one:

private static DateTimeFormatter formatter 
        = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS[XXX]")
                .withZone(ZoneOffset.UTC);

public static Instant parse(String offsetDateTimeString) {
    return OffsetDateTime.parse(offsetDateTimeString, formatter).toInstant();
}

Let’s try it out:

    System.out.println(parse("2018-08-04T21:41:55.987Z"));
    System.out.println(parse("2018-08-04T19:41:55.987-02:00"));
    System.out.println(parse("2018-08-04T21:41:55.987"));

This prints:

2018-08-04T21:41:55.987Z
2018-08-04T21:41:55.987Z
2018-08-04T21:41:55.987Z

The square brackets in the format pattern string surround an optional part, so the offset may be present or not. Offset X uses Z for offset zero so matches the first two of your three formats. To specify the offset to use if there isn’t any in the string I have set a default time zone of UTC on the formatter.

Variations include:

  • You may use predefined ISO formats rather than writing the entire format patterns string yourself.
  • Since we are after an offset, not a time zone, it may be more correct to specify a default offset rather than a default time zone.

DateTimeFormatterBuilder allows us to do both. So here’s a different formatter you may use in the above code instead:

private static DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendPattern("[XXX]")
        .parseDefaulting(ChronoField.OFFSET_SECONDS, ZoneOffset.UTC.getTotalSeconds())
        .toFormatter();

Results are identical.

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