Search code examples
javadate-formattingjava-timeiso8601localdate

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


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".


Solution

  • 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.