alhudz commented on code in PR #1800:
URL: https://github.com/apache/commons-lang/pull/1800#discussion_r4178006980
##########
src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java:
##########
@@ -1285,6 +1288,35 @@ public StringBuffer format(final Object obj, final
StringBuffer toAppendTo, fina
throw new IllegalArgumentException("Unknown class: " +
ClassUtils.getName(obj, "<null>"));
}
+ /**
+ * Gets the era names for the calendar this printer formats with.
+ * <p>
+ * {@link DateFormatSymbols#getEras()} only knows the two Gregorian eras.
A locale whose default calendar is not Gregorian, like the Thai Buddhist or
+ * Japanese Imperial calendar, prints that calendar's year, so the era
names have to come from that calendar as well, as {@link SimpleDateFormat} and
+ * {@link FastDateParser} do. The Japanese Imperial calendar also has more
than two eras, so indexing the Gregorian names by its era value would throw an
+ * {@link ArrayIndexOutOfBoundsException}.
+ * </p>
+ *
+ * @param symbols the date format symbols for this printer's locale.
+ * @param style {@link Calendar#SHORT} or {@link Calendar#LONG}.
+ * @return the era names, indexed by the {@link Calendar#ERA} value.
+ */
+ private String[] getEras(final DateFormatSymbols symbols, final int style)
{
+ final Calendar calendar = newCalendar();
+ // The Buddhist calendar extends GregorianCalendar, so test the
calendar type rather than the class.
+ if ("gregory".equals(calendar.getCalendarType())) {
+ return symbols.getEras();
+ }
+ final Map<String, Integer> displayNames =
calendar.getDisplayNames(Calendar.ERA, style, locale);
+ if (displayNames == null) {
+ return symbols.getEras();
+ }
+ final String[] eras = new String[calendar.getMaximum(Calendar.ERA) +
1];
+ Arrays.fill(eras, StringUtils.EMPTY);
+ displayNames.forEach((name, era) -> eras[era] = name);
Review Comment:
Confirmed. The table was picked from the printer's locale alone, while
`format(Calendar)` keeps the caller's calendar.
Repro:
```java
final Calendar gregorian = Calendar.getInstance(TimeZones.GMT, Locale.US);
gregorian.clear();
gregorian.set(2024, Calendar.MAY, 1);
FastDateFormat.getInstance("G", TimeZones.GMT, new Locale("ja", "JP",
"JP")).format(gregorian);
```
Expected: `西暦`
Actual: `明治`; a `th_TH` printer gave `พ.ศ.` for the same calendar where it
should give `ค.ศ.`.
Fix: 3808d5d replaces the `TextField` era rule with an `EraField` rule that
picks the name by the type of the calendar being formatted. The locale's own
calendar still uses the prebuilt table, a Gregorian calendar keeps
`DateFormatSymbols.getEras()`, and a calendar of any other type is asked for
its own name through `Calendar.getDisplayName`, as `SimpleDateFormat` does. The
lookups are bounds checked, so a Japanese Imperial calendar on an `en_US`
printer prints `Reiwa` where it threw `ArrayIndexOutOfBoundsException` before.
`testEraMixedCalendarTypes` runs Gregorian, Buddhist and Japanese Imperial
calendars through `en_US`, `th_TH` and `ja_JP_JP` printers with
`SimpleDateFormat` as the reference. It fails on the previous commit with
`en_US buddhist G ==> expected: <BE> but was: <AD>`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]