Copilot commented on code in PR #1815:
URL: https://github.com/apache/commons-lang/pull/1815#discussion_r4264631887


##########
src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java:
##########
@@ -210,6 +214,36 @@ void testEraNonGregorianCalendar() {
         }
     }
 
+    /**
+     * Tests that a month-only pattern uses the standalone month names, like 
SimpleDateFormat. In some languages, like the Slavic and Baltic ones, they are a
+     * different grammatical form from the names used next to a day: "MMMM" 
alone prints Russian February as nominative "февраль" where "d MMMM" prints
+     * genitive "февраля".
+     */
+    @Test
+    void testStandaloneMonthForMonthOnlyPattern() throws ParseException {
+        // SimpleDateFormat forces the standalone form for a month-only 
pattern only since Java 9 (JDK-8114833); Java 8 has no such rule.
+        assumeTrue(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9));
+        final Locale[] locales = { Locale.US, Locale.GERMANY, new 
Locale("ru"), new Locale("cs"), new Locale("pl"), new Locale("fi") };
+        // Month-only patterns, with or without literals, use the standalone 
form; patterns with another field keep the format form.
+        final String[] patterns = { "MMM", "MMMM", "'m:'MMMM", "MMMM''", "d 
MMMM", "MMMM yyyy", "MMM MMM" };
+        for (final Locale locale : locales) {
+            for (final String pattern : patterns) {
+                for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; 
month++) {
+                    final Calendar cal = Calendar.getInstance(TimeZones.GMT, 
locale);
+                    cal.clear();
+                    cal.set(2024, month, 10);
+                    final Date date = cal.getTime();
+                    final SimpleDateFormat sdf = new SimpleDateFormat(pattern, 
locale);
+                    sdf.setTimeZone(TimeZones.GMT);
+                    final FastDateFormat fdf = 
FastDateFormat.getInstance(pattern, TimeZones.GMT, locale);
+                    assertEquals(sdf.format(date), fdf.format(date), () -> 
locale + " " + pattern);
+                    // FastDateParser accepts all name styles, so the 
printer's output parses back.
+                    assertEquals(month, 
DateUtils.toCalendar(fdf.parse(fdf.format(date))).get(Calendar.MONTH), () -> 
locale + " " + pattern);

Review Comment:
   `DateUtils.toCalendar(Date)` uses the system default time zone, but 
`fdf.parse(...)` is run in `TimeZones.GMT`. This can make the assertion 
timezone-dependent (and potentially flaky near month boundaries, since parsing 
month-only patterns commonly defaults the day-of-month). Prefer constructing 
the `Calendar` in GMT (e.g., `DateUtils.toCalendar(parsedDate, TimeZones.GMT)` 
or `Calendar.getInstance(TimeZones.GMT, locale)` + `setTime(...)`) before 
reading `Calendar.MONTH`.



##########
src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java:
##########
@@ -1462,6 +1467,7 @@ protected List<Rule> parsePattern() {
 
         final int length = pattern.length();
         final int[] indexRef = new int[1];
+        final boolean monthOnly = STANDALONE_MONTH_PATTERN && 
isMonthOnlyPattern();

Review Comment:
   When `monthOnly` is true, `CalendarUtils.getInstance(locale)` is invoked 
separately for the long and short month lookups. Even though `parsePattern()` 
is typically called only during formatter construction, this is easy to 
streamline by retrieving the `CalendarUtils` instance once (and optionally the 
standalone arrays) into locals before the loop/case, reducing repeated lookups 
and keeping the rule construction simpler.



##########
src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java:
##########
@@ -1493,9 +1499,9 @@ protected List<Rule> parsePattern() {
                 break;
             case 'M': // month in year (text and number)
                 if (tokenLen >= 4) {
-                    rule = new TextField(Calendar.MONTH, months);
+                    rule = new TextField(Calendar.MONTH, monthOnly ? 
CalendarUtils.getInstance(locale).getStandaloneLongMonthNames() : months);
                 } else if (tokenLen == 3) {
-                    rule = new TextField(Calendar.MONTH, shortMonths);
+                    rule = new TextField(Calendar.MONTH, monthOnly ? 
CalendarUtils.getInstance(locale).getStandaloneShortMonthNames() : shortMonths);

Review Comment:
   When `monthOnly` is true, `CalendarUtils.getInstance(locale)` is invoked 
separately for the long and short month lookups. Even though `parsePattern()` 
is typically called only during formatter construction, this is easy to 
streamline by retrieving the `CalendarUtils` instance once (and optionally the 
standalone arrays) into locals before the loop/case, reducing repeated lookups 
and keeping the rule construction simpler.



-- 
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]

Reply via email to