Fix negative week year formatting in FastDatePrinter - #1762
Merged
Conversation
GregorianCalendar.getWeekYear() is proleptic, so a BC date yields a negative week year that WeekYear passed straight to the digit rules. Those rules build characters arithmetically, so the value walked below '0' and emitted control characters instead of digits. Emit the sign in WeekYear and pass the magnitude down, matching TimeZoneNumberRule.
There was a problem hiding this comment.
Pull request overview
Fixes incorrect formatting of negative week-based years in FastDatePrinter when using Y/YY/YYYY… patterns with BC dates (where GregorianCalendar.getWeekYear() can return a negative, proleptic value). The change brings FastDateFormat/FastDatePrinter output in line with SimpleDateFormat and prevents control-character output from the digit rules.
Changes:
- Add sign handling to the
WeekYearrule so negative week years are rendered with-and the magnitude is passed to the underlyingNumberRule. - Add a regression test that compares multiple
Y-width patterns againstSimpleDateFormatfor a BC date and asserts exact expected strings.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java | WeekYear now emits - and formats the absolute value to avoid negative-digit rendering. |
| src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java | Adds BC week-year regression coverage and parity assertions vs SimpleDateFormat. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Member
|
Thank you @alhudz , merged 🚀 |
garydgregory
added a commit
that referenced
this pull request
Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
mvn; that'smvnon the command line by itself.Repro:FastDateFormat.getInstance("YYYY").format(cal)wherecalis 15 July 42 BC, that is aGregorianCalendarwithERAset toGregorianCalendar.BC.Expected:-0041, whatSimpleDateFormatprints for the same date and pattern.Actual:000followed byU+0007.YYgives,/againstSimpleDateFormat's-41.GregorianCalendar.getWeekYear()is proleptic, so a BC date gives a negative week year (-41here) andWeekYearhands it to the wrappedNumberRuleunchanged.(char) (value + '0'),value / 10 + '0'), so a negative value walks below'0'and lands on control characters or unrelated code points rather than digits.Fix: emit the sign inWeekYearand pass the magnitude down, the same handlingTimeZoneNumberRuleandIso8601_Rulealready apply to negative UTC offsets. Every other rule takes its value fromCalendar.get, which never returns a negative, sogetWeekYearis the only source of one;YYYandYkeep the four-digit padding the class Javadoc describes.Checked
YYYYagainstSimpleDateFormatover 46,667 dates spanning 249 BC to 4188 AD: 2,611 mismatches before this change, 337 of them carrying a control character, and 0 after.