LANG-1680 Add support for standalone month formats (#892)

This commit is contained in:
Steve Bosman 2022-05-15 20:13:41 +01:00 committed by GitHub
parent a2ed219fb8
commit 127869e88f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 126 additions and 1 deletions

View File

@ -22,6 +22,7 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@ -1831,4 +1832,40 @@ public class DateUtils {
}
}
/**
* Gets full standalone month names as used in "LLLL" date formatting.
* @param locale Locale
* @return Long names of months
*/
static String[] getStandaloneLongMonths(final Locale locale) {
return getMonthNames(locale, Calendar.LONG_STANDALONE);
}
/**
* Gets short standalone month names as used in "LLLL" date formatting.
* @param locale Locale
* @return Short names of months
*/
static String[] getStandaloneShortMonths(final Locale locale) {
return getMonthNames(locale, Calendar.SHORT_STANDALONE);
}
/**
* Gets month names in the requested style.
* @param locale Locale
* @param style Must be a valid {@link Calendar#getDisplayNames(int, int, Locale)} month style.
* @return Styled names of months
*/
private static String[] getMonthNames(final Locale locale, final int style) {
// Unfortunately standalone month names are not available in DateFormatSymbols,
// so we have to extract them.
final Calendar calendar = Calendar.getInstance(locale);
Map<String, Integer> displayNames = calendar.getDisplayNames(Calendar.MONTH, style, locale);
final String[] monthNames = new String[displayNames.size()];
for (Map.Entry<String, Integer> entry: displayNames.entrySet()) {
monthNames[entry.getValue()] = entry.getKey();
}
return monthNames;
}
}

View File

@ -606,6 +606,7 @@ public class FastDateParser implements DateParser, Serializable {
case 'K': // Hour in am/pm (0-11)
return HOUR_STRATEGY;
case 'M':
case 'L':
return width >= 3 ? getLocaleSpecificStrategy(Calendar.MONTH, definingCalendar) : NUMBER_MONTH_STRATEGY;
case 'S':
return MILLISECOND_STRATEGY;

View File

@ -233,6 +233,17 @@ public class FastDatePrinter implements DatePrinter, Serializable {
rule = UnpaddedMonthField.INSTANCE;
}
break;
case 'L': // month in year (text and number)
if (tokenLen >= 4) {
rule = new TextField(Calendar.MONTH, DateUtils.getStandaloneLongMonths(mLocale));
} else if (tokenLen == 3) {
rule = new TextField(Calendar.MONTH, DateUtils.getStandaloneShortMonths(mLocale));
} else if (tokenLen == 2) {
rule = TwoDigitMonthField.INSTANCE;
} else {
rule = UnpaddedMonthField.INSTANCE;
}
break;
case 'd': // day in month (number)
rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
break;

View File

@ -1694,5 +1694,43 @@ public class DateUtilsTest {
now.add(Calendar.DATE, 1);
}
}
@Test
public void testGetStandaloneLongMonthNames() {
Locale testLocale = Locale.GERMAN;
String[] standaloneShortMonths = DateUtils.getStandaloneLongMonths(testLocale);
assertEquals(12, standaloneShortMonths.length);
assertEquals("Januar", standaloneShortMonths[0]);
assertEquals("Februar", standaloneShortMonths[1]);
assertEquals("M\u00e4rz", standaloneShortMonths[2]);
assertEquals("April", standaloneShortMonths[3]);
assertEquals("Mai", standaloneShortMonths[4]);
assertEquals("Juni", standaloneShortMonths[5]);
assertEquals("Juli", standaloneShortMonths[6]);
assertEquals("August", standaloneShortMonths[7]);
assertEquals("September", standaloneShortMonths[8]);
assertEquals("Oktober", standaloneShortMonths[9]);
assertEquals("November", standaloneShortMonths[10]);
assertEquals("Dezember", standaloneShortMonths[11]);
}
@Test
public void testGetStandaloneShortMonthNames() {
Locale testLocale = Locale.GERMAN;
String[] standaloneShortMonths = DateUtils.getStandaloneShortMonths(testLocale);
assertEquals(12, standaloneShortMonths.length);
assertEquals("Jan", standaloneShortMonths[0]);
assertEquals("Feb", standaloneShortMonths[1]);
assertEquals("M\u00e4r", standaloneShortMonths[2]);
assertEquals("Apr", standaloneShortMonths[3]);
assertEquals("Mai", standaloneShortMonths[4]);
assertEquals("Jun", standaloneShortMonths[5]);
assertEquals("Jul", standaloneShortMonths[6]);
assertEquals("Aug", standaloneShortMonths[7]);
assertEquals("Sep", standaloneShortMonths[8]);
assertEquals("Okt", standaloneShortMonths[9]);
assertEquals("Nov", standaloneShortMonths[10]);
assertEquals("Dez", standaloneShortMonths[11]);
}
}

View File

@ -26,6 +26,9 @@ import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@ -49,6 +52,9 @@ public class FastDateFormatTest {
private static final int NROUNDS = 10000;
final Locale FINNISH = Locale.forLanguageTag("fi");
final Locale HUNGARIAN = Locale.forLanguageTag("hu");
private AtomicLongArray measureTime(final Format printer, final Format parser) throws InterruptedException {
final ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
final AtomicInteger failures = new AtomicInteger(0);
@ -319,4 +325,36 @@ public class FastDateFormatTest {
assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG),
FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
}
@Test
public void testStandaloneShortMonthForm() {
final TimeZone utc = FastTimeZone.getGmtTimeZone();
Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
final Date date = Date.from(testInstant);
String dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, Locale.GERMAN).format(date);
assertEquals("1970-Sep-15", dateAsString);
dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, FINNISH).format(date);
assertEquals("1970-syys-15", dateAsString);
dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, HUNGARIAN).format(date);
assertEquals("1970-szept.-15", dateAsString);
}
@Test
public void testStandaloneLongMonthForm() {
final TimeZone utc = FastTimeZone.getGmtTimeZone();
Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
final Date date = Date.from(testInstant);
String dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, Locale.GERMAN).format(date);
assertEquals("1970-September-15", dateAsString);
dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, FINNISH).format(date);
assertEquals("1970-syyskuu-15", dateAsString);
dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, HUNGARIAN).format(date);
assertEquals("1970-szeptember-15", dateAsString);
}
}

View File

@ -204,7 +204,7 @@ public class FastDatePrinterTest {
assertEquals("-04:00", fdf.format(cal2));
assertEquals("-04:00", fdf.format(millis2));
final String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M" +
final String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M LLLL LLL LL L" +
" dddd ddd dd d DDDD DDD DD D EEEE EEE EE E aaaa aaa aa a zzzz zzz zz z";
fdf = getInstance(pattern);
sdf = new SimpleDateFormat(pattern);