Grant Robinson
Grant Robinson

Reputation: 41

java.time.DateTimeFormat Unexpected Behavior

In Java 8 java.time package, using LocalDate with DateTimeFormatter.ISO_WEEK_DATE:

LocalDate date = LocalDate.of(2015, 12, 28);
date.format(DateTimeFormatter.ISO_WEEK_DATE).equals("2015-W53-1");

as expected, but

date.format(DateTimeFormatter.ofPattern("YYYY'-W'ww'-'e")).equals("2016-W01-2");

That is a full week later! Why? What incantation would make my custom pattern work the same as the built-in pattern?

Upvotes: 4

Views: 181

Answers (2)

Sepandar Sepehr
Sepandar Sepehr

Reputation: 11

Similar question answered here: Inconsistent `w` symbol formatting from joda time to java.time

Seems like the issue is with Locale as Basil mentioned.

Upvotes: 1

Basil Bourque
Basil Bourque

Reputation: 338624

Java 8 Uses Builder

Here is the implementation for DateTimeFormatter.ISO_WEEK_DATE. The source uses a Builder (DateTimeFormatterBuilder) rather than a coded String.

From this OpenJDK source code for Java 8 which appears to be current development version after Java 8 Update 72 (I'm not fluent with the OpenJDK site).

public static final DateTimeFormatter ISO_WEEK_DATE;
    static {
        ISO_WEEK_DATE = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
                .appendLiteral("-W")
                .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
                .appendLiteral('-')
                .appendValue(DAY_OF_WEEK, 1)
                .optionalStart()
                .appendOffsetId()
                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
    }

First Day Of Week

I do not know the exact nature of the problem, but I suspect it is the definition of the first day of week. The ISO standard says Monday starts the week. It seems .appendValue(DAY_OF_WEEK, 1) line in code above is making that a fact though I do not know why that would be necessary as the IsoChronology is specified in the last line above.

Locale

Anyways, the problem is certainly contained within Locale. Here is an example showing the Germany locale generates 2015-W53-1 while the United States locale generates: 2016-W01-2.

LocalDate localDate = LocalDate.of ( 2015 , 12 , 28 );
String builtIn = localDate.format ( DateTimeFormatter.ISO_WEEK_DATE ); // 2015-W53-1

DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "YYYY'-W'ww'-'e" );

formatter = formatter.withLocale ( Locale.GERMANY );  // 2015-W53-1
String custom = localDate.format ( formatter );
System.out.println ( "formatter.locale: " + formatter.getLocale () + " | localDate: " + localDate + " | builtIn: " + builtIn + " | custom: " + custom );

formatter = formatter.withLocale ( Locale.US );  // 2016-W01-2
custom = localDate.format ( formatter );
System.out.println ( "formatter.locale: " + formatter.getLocale () + " | localDate: " + localDate + " | builtIn: " + builtIn + " | custom: " + custom );

formatter.locale: de_DE | localDate: 2015-12-28 | builtIn: 2015-W53-1 | custom: 2015-W53-1

formatter.locale: en_US | localDate: 2015-12-28 | builtIn: 2015-W53-1 | custom: 2016-W01-2

Upvotes: 2

Related Questions