Mismatched Year And Week Fields In DateTimeFormatterBuilder
ID |
java.mismatched_week_based_year |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
date-time, reliability |
Description
Reports a DateTimeFormatterBuilder chain that pairs a regular year field
(ChronoField.YEAR, ChronoField.YEAR_OF_ERA) with WeekFields..weekOfWeekBasedYear(), or
WeekFields..weekBasedYear() with ChronoField.ALIGNED_WEEK_OF_YEAR.
Rationale
weekBasedYear() exists to be off by one, on purpose, for the days in a week that straddles
two calendar years — that is exactly why it must be paired with weekOfWeekBasedYear(), which
agrees with it about which week the date falls in. Paired with the other week field instead,
the formatter silently prints the wrong year for a handful of days every year. A payroll
system building a "week-of / year" period label is a realistic place this surfaces:
new DateTimeFormatterBuilder()
.appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
.appendLiteral(" of ")
.appendValue(ChronoField.YEAR, 4)
.toFormatter();
// formats 31 December 2018 as "1 of 2018" -- that week actually belongs to payroll year 2019
The two correct pairings are a regular year with ChronoField.ALIGNED_WEEK_OF_YEAR, and
weekBasedYear() with weekOfWeekBasedYear(). A year field with no week field in the chain
(or a week field with no year field) is not a pairing at all and is not reported.
Only one chain is examined at a time; a builder split across two statements is a known
limitation, not tracked across statements. Only the ChronoField and WeekFields members
named above are recognised — an unrelated or custom temporal field is left alone.
Remediation
Pair the year field with the week field that agrees with it.
new DateTimeFormatterBuilder()
.appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
.appendLiteral(" of ")
.appendValue(WeekFields.ISO.weekBasedYear(), 4)
.toFormatter();
new DateTimeFormatterBuilder()
.appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
.appendLiteral(" of ")
.appendValue(ChronoField.YEAR, 4)
.toFormatter();