DateTimeFormatter.ISO_LOCAL_DATE vs DateTimeFormatter.ofPattern("yyyy-MM-dd") in Java 8+

JL Gradley picture JL Gradley · Dec 7, 2017 · Viewed 7.4k times · Source

I have a date I’ve created using ZonedDateTime.now(ZoneOffset.of("+2:00")).minusDays(5). Now I want to format it as yyyy-MM-dd.

In Java 8+, is DateTimeFormatter.ISO_LOCAL_DATE the equivalent of DateTimeFormatter.ofPattern("yyyy-MM-dd")?

The output appears identical and looks like, from the docs, they should be the same. However, the "LOCAL" part of that gave me pause. Notice I have an offset and I'm using ZonedDateTime. I wanted to make sure there were no any gotchas or "they're the same except under these special circumstances since you're dealing with offsets, etc".

Answer

Ole V.V. picture Ole V.V. · Dec 7, 2017

For formatting a date-time denoting 5 days ago the two formatters will be equivalent. They will not be equivalent for all possible dates, neither for formatting nor for parsing.

Let’s try them out:

    DateTimeFormatter yyyyMmDd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    int[] yearsToTest = { -900_000_000, -10_000, -2, 0, 1, 2017, 2099, 9999, 10_000, 900_000_000 };
    for (int year : yearsToTest) {
        LocalDate date = LocalDate.of(year, Month.DECEMBER, 2);
        String dateFormattedIso = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
        String dateFormattedYyyyMmDd = date.format(yyyyMmDd);
        String diff = dateFormattedIso.equals(dateFormattedYyyyMmDd) ? "Same" : "Different";
        System.out.format("%-18s%-18s%s%n", dateFormattedIso, dateFormattedYyyyMmDd, diff);
    }

The above snippet prints:

-900000000-12-02  +900000001-12-02  Different
-10000-12-02      +10001-12-02      Different
-0002-12-02       0003-12-02        Different
0000-12-02        0001-12-02        Different
0001-12-02        0001-12-02        Same
2017-12-02        2017-12-02        Same
2099-12-02        2099-12-02        Same
9999-12-02        9999-12-02        Same
+10000-12-02      +10000-12-02      Same
+900000000-12-02  +900000000-12-02  Same

So for formatting it seems they are equivalent for years in the common era (“AD”), but not for years before the common era. yyyy respects that there is no year 0, so a year of 0 in the LocalDate is rendered as year 1. It is understood that it is BCE, this information is not printed. The ISO formatter takes the year literally, with sign and all.

You may obtain the behaviour of ISO_LOCAL_DATE by using uuuu instead of yyyy.

“Local” here just means without time zone, in turn meaning that the time zone information from your ZonedDateTime isn’t printed, which you wouldn’t have expected anyway.