src/share/classes/java/time/format/DateTimeTextProvider.java
Print this page
@@ -68,10 +68,11 @@
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
import java.time.chrono.JapaneseChronology;
import java.time.temporal.ChronoField;
+import java.time.temporal.IsoFields;
import java.time.temporal.TemporalField;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -80,14 +81,17 @@
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.util.locale.provider.CalendarDataUtility;
+import sun.util.locale.provider.LocaleProviderAdapter;
+import sun.util.locale.provider.LocaleResources;
/**
* A provider to obtain the textual form of a date-time field.
*
* <h3>Specification for implementors</h3>
@@ -139,19 +143,10 @@
return ((LocaleStore) store).getText(value, style);
}
return null;
}
- private static int toStyle(TextStyle style) {
- if (style == TextStyle.FULL) {
- return Calendar.LONG_FORMAT;
- } else if (style == TextStyle.SHORT) {
- return Calendar.SHORT_FORMAT;
- }
- return Calendar.NARROW_STANDALONE;
- }
-
/**
* Gets the text for the specified chrono, field, locale and style
* for the purpose of formatting.
* <p>
* The text associated with the value is returned.
@@ -198,12 +193,12 @@
fieldIndex = Calendar.AM_PM;
fieldValue = (int) value;
} else {
return null;
}
- return CalendarDataUtility.retrieveCldrFieldValueName(
- chrono.getCalendarType(), fieldIndex, fieldValue, toStyle(style), locale);
+ return CalendarDataUtility.retrieveJavaTimeFieldValueName(
+ chrono.getCalendarType(), fieldIndex, fieldValue, style.toCalendarStyle(), locale);
}
/**
* Gets an iterator of text to field for the specified field, locale and style
* for the purpose of parsing.
@@ -268,44 +263,44 @@
break;
default:
return null;
}
- Map<String, Integer> map = CalendarDataUtility.retrieveCldrFieldValueNames(
- chrono.getCalendarType(), fieldIndex, toStyle(style), locale);
+ int calendarStyle = (style == null) ? Calendar.ALL_STYLES : style.toCalendarStyle();
+ Map<String, Integer> map = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+ chrono.getCalendarType(), fieldIndex, calendarStyle, locale);
if (map == null) {
return null;
}
-
List<Entry<String, Long>> list = new ArrayList<>(map.size());
switch (fieldIndex) {
case Calendar.ERA:
- for (String key : map.keySet()) {
- int era = map.get(key);
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ int era = entry.getValue();
if (chrono == JapaneseChronology.INSTANCE) {
if (era == 0) {
era = -999;
} else {
era -= 2;
}
}
- list.add(createEntry(key, (long) era));
+ list.add(createEntry(entry.getKey(), (long)era));
}
break;
case Calendar.MONTH:
- for (String key : map.keySet()) {
- list.add(createEntry(key, (long)(map.get(key) + 1)));
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ list.add(createEntry(entry.getKey(), (long)(entry.getValue() + 1)));
}
break;
case Calendar.DAY_OF_WEEK:
- for (String key : map.keySet()) {
- list.add(createEntry(key, (long)toWeekDay(map.get(key))));
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ list.add(createEntry(entry.getKey(), (long)toWeekDay(entry.getValue())));
}
break;
default:
- for (String key : map.keySet()) {
- list.add(createEntry(key, (long)map.get(key)));
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ list.add(createEntry(entry.getKey(), (long)entry.getValue()));
}
break;
}
return list.iterator();
}
@@ -331,89 +326,130 @@
private Object createStore(TemporalField field, Locale locale) {
Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>();
if (field == ERA) {
for (TextStyle textStyle : TextStyle.values()) {
+ if (textStyle.isStandalone()) {
+ // Stand-alone isn't applicable to era names.
+ continue;
+ }
+ Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+ "gregory", Calendar.ERA, textStyle.toCalendarStyle(), locale);
+ if (displayNames != null) {
Map<Long, String> map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.ERA, toStyle(textStyle), locale).entrySet()) {
+ for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
+ }
return new LocaleStore(styleMap);
}
if (field == MONTH_OF_YEAR) {
+ for (TextStyle textStyle : TextStyle.values()) {
+ Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+ "gregory", Calendar.MONTH, textStyle.toCalendarStyle(), locale);
Map<Long, String> map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).entrySet()) {
+ if (displayNames != null) {
+ for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) (entry.getValue() + 1), entry.getKey());
}
- styleMap.put(TextStyle.FULL, map);
- map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.MONTH, Calendar.SHORT_FORMAT, locale).entrySet()) {
- map.put((long) (entry.getValue() + 1), entry.getKey());
- }
- styleMap.put(TextStyle.SHORT, map);
-
- map = new HashMap<>();
+ } else {
+ // Narrow names may have duplicated names, such as "J" for January, Jun, July.
+ // Get names one by one in that case.
for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
String name;
- name = CalendarDataUtility.retrieveCldrFieldValueName(
- "gregory", Calendar.MONTH, month, Calendar.NARROW_STANDALONE, locale);
- if (name != null) {
- map.put((long)(month + 1), name);
+ name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
+ "gregory", Calendar.MONTH, month, textStyle.toCalendarStyle(), locale);
+ if (name == null) {
+ break;
+ }
+ map.put((long) (month + 1), name);
}
}
if (!map.isEmpty()) {
- styleMap.put(TextStyle.NARROW, map);
+ styleMap.put(textStyle, map);
+ }
}
return new LocaleStore(styleMap);
}
if (field == DAY_OF_WEEK) {
+ for (TextStyle textStyle : TextStyle.values()) {
+ Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+ "gregory", Calendar.DAY_OF_WEEK, textStyle.toCalendarStyle(), locale);
Map<Long, String> map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).entrySet()) {
+ if (displayNames != null) {
+ for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long)toWeekDay(entry.getValue()), entry.getKey());
}
- styleMap.put(TextStyle.FULL, map);
- map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.DAY_OF_WEEK, Calendar.SHORT_FORMAT, locale).entrySet()) {
- map.put((long) toWeekDay(entry.getValue()), entry.getKey());
- }
- styleMap.put(TextStyle.SHORT, map);
- map = new HashMap<>();
+
+ } else {
+ // Narrow names may have duplicated names, such as "S" for Sunday and Saturday.
+ // Get names one by one in that case.
for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) {
- map.put((long) toWeekDay(wday),
- CalendarDataUtility.retrieveCldrFieldValueName(
- "gregory", Calendar.DAY_OF_WEEK, wday, Calendar.NARROW_FORMAT, locale));
+ String name;
+ name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
+ "gregory", Calendar.DAY_OF_WEEK, wday, textStyle.toCalendarStyle(), locale);
+ if (name == null) {
+ break;
+ }
+ map.put((long)toWeekDay(wday), name);
+ }
+ }
+ if (!map.isEmpty()) {
+ styleMap.put(textStyle, map);
+ }
}
- styleMap.put(TextStyle.NARROW, map);
return new LocaleStore(styleMap);
}
if (field == AMPM_OF_DAY) {
+ for (TextStyle textStyle : TextStyle.values()) {
+ if (textStyle.isStandalone()) {
+ // Stand-alone isn't applicable to AM/PM.
+ continue;
+ }
+ Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+ "gregory", Calendar.AM_PM, textStyle.toCalendarStyle(), locale);
+ if (displayNames != null) {
Map<Long, String> map = new HashMap<>();
- for (Entry<String, Integer> entry :
- CalendarDataUtility.retrieveCldrFieldValueNames(
- "gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).entrySet()) {
+ for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
- styleMap.put(TextStyle.FULL, map);
- styleMap.put(TextStyle.SHORT, map); // re-use, as we don't have different data
+ if (!map.isEmpty()) {
+ styleMap.put(textStyle, map);
+ }
+ }
+ }
+ return new LocaleStore(styleMap);
+ }
+
+ if (field == IsoFields.QUARTER_OF_YEAR) {
+ // The order of keys must correspond to the TextStyle.values() order.
+ final String[] keys = {
+ "QuarterNames",
+ "standalone.QuarterNames",
+ "QuarterAbbreviations",
+ "standalone.QuarterAbbreviations",
+ "QuarterNarrows",
+ "standalone.QuarterNarrows",
+ };
+ for (int i = 0; i < keys.length; i++) {
+ String[] names = getLocalizedResource(keys[i], locale);
+ if (names != null) {
+ Map<Long, String> map = new HashMap<>();
+ for (int q = 0; q < names.length; q++) {
+ map.put((long) (q + 1), names[q]);
+ }
+ styleMap.put(TextStyle.values()[i], map);
+ }
+ }
return new LocaleStore(styleMap);
}
return ""; // null marker for map
}
@@ -428,10 +464,27 @@
private static <A, B> Entry<A, B> createEntry(A text, B field) {
return new SimpleImmutableEntry<>(text, field);
}
/**
+ * Returns the localized resource of the given key and locale, or null
+ * if no localized resource is available.
+ *
+ * @param key the key of the localized resource, not null
+ * @param locale the locale, not null
+ * @return the localized resource, or null if not available
+ * @throws NullPointerException if key or locale is null
+ */
+ @SuppressWarnings("unchecked")
+ static <T> T getLocalizedResource(String key, Locale locale) {
+ LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
+ .getLocaleResources(locale);
+ ResourceBundle rb = lr.getJavaTimeFormatData();
+ return rb.containsKey(key) ? (T) rb.getObject(key) : null;
+ }
+
+ /**
* Stores the text for a single locale.
* <p>
* Some fields have a textual representation, such as day-of-week or month-of-year.
* These textual representations can be captured in this class for printing
* and parsing.
@@ -455,21 +508,21 @@
*/
LocaleStore(Map<TextStyle, Map<Long, String>> valueTextMap) {
this.valueTextMap = valueTextMap;
Map<TextStyle, List<Entry<String, Long>>> map = new HashMap<>();
List<Entry<String, Long>> allList = new ArrayList<>();
- for (TextStyle style : valueTextMap.keySet()) {
+ for (Map.Entry<TextStyle, Map<Long, String>> vtmEntry : valueTextMap.entrySet()) {
Map<String, Entry<String, Long>> reverse = new HashMap<>();
- for (Map.Entry<Long, String> entry : valueTextMap.get(style).entrySet()) {
+ for (Map.Entry<Long, String> entry : vtmEntry.getValue().entrySet()) {
if (reverse.put(entry.getValue(), createEntry(entry.getValue(), entry.getKey())) != null) {
// TODO: BUG: this has no effect
continue; // not parsable, try next style
}
}
List<Entry<String, Long>> list = new ArrayList<>(reverse.values());
Collections.sort(list, COMPARATOR);
- map.put(style, list);
+ map.put(vtmEntry.getKey(), list);
allList.addAll(list);
map.put(null, allList);
}
Collections.sort(allList, COMPARATOR);
this.parsable = map;