How to get consistency using DateTimeFormatter

Viewed 58

I'm seeing inconsistency between similar looking inputs when using the same DateTimeFormatter. I need this to compare with another input source of date times.

For example, given these inputs:

2020-06-29T01:00:00+01:00 -> my date time formatter -> 2020-06-29T01:00:00+01:00
2021-08-18T21:00:00+0000 -> my date time formatter -> 2021-08-18T21:00:00Z

I want the output to always be in YYYY-mm-ddT00:00:00Z format, so the second input yields my desired outcome.

The way I'm currently formatting it:

DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4)
            .optionalStart()
            .appendLiteral("-")
            .optionalEnd()
            .appendValue(ChronoField.MONTH_OF_YEAR, 2)
            .optionalStart()
            .appendLiteral("-")
            .optionalEnd()
            .appendValue(ChronoField.DAY_OF_MONTH, 2)
            .appendLiteral('T')
            .appendPattern("HH':'mm':'ss[XXX][X]")
            .toFormatter();

public OffsetDateTime convert(String dateTime) {
  return OffsetDateTime.parse(dateTime, FORMATTER);
}

public String getDateTimeString(OffsetDateTime offsetDateTime) {
  return offsetDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}

public void doStuff(String input) {
  OffsetDateTime odt = convert(input);
  String finalResult = getDateTimeString(odt);
}

..

doStuff(input);

I've been looking through this for a few hours now, but the documentation to me isn't that clear and I've been having all sorts of trouble. Any tips?

2 Answers

Convert the OffsetDateTime to Instant to get rid of timezone.

public String getDateTimeString(Instant instant) {
  return instant.toString();
}

public void doStuff(String input) {
    OffsetDateTime odt = convert(input);
    String finalResult = getDateTimeString(odt.toInstant());
    System.out.println(finalResult);
}

This is basically the same approach as in the (rightly) accepted answer, just an alternative way to write it:

public static String convertToUtcIso(String datetime) {
    // parse the given String,and format as ISO OFFSET DATE TIME
    return OffsetDateTime.parse(datetime, FORMATTER)
                         // convert the resulting OffsetDateTime to UTC
                         .withOffsetSameInstant(ZoneOffset.UTC)
                         // and format it according to ISO standard
                         .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}

There are small differences in readability due to (more) clearly pointing out that time of day will be adjusted to having an offset of 0 hours.

As in the accepted answer, the example datetime "2020-06-29T01:00:00+01:00" will be converted to "2020-06-29T00:00:00Z" (01:00 AM ⇒ 00:00 AM).

Related