src/share/classes/java/time/format/DateTimeTextProvider.java
Print this page
*** 68,77 ****
--- 68,78 ----
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,93 ****
--- 81,97 ----
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,157 ****
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.
--- 143,152 ----
*** 198,209 ****
fieldIndex = Calendar.AM_PM;
fieldValue = (int) value;
} else {
return null;
}
! return CalendarDataUtility.retrieveCldrFieldValueName(
! chrono.getCalendarType(), fieldIndex, fieldValue, toStyle(style), locale);
}
/**
* Gets an iterator of text to field for the specified field, locale and style
* for the purpose of parsing.
--- 193,204 ----
fieldIndex = Calendar.AM_PM;
fieldValue = (int) value;
} else {
return null;
}
! 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,311 ****
break;
default:
return null;
}
! Map<String, Integer> map = CalendarDataUtility.retrieveCldrFieldValueNames(
! chrono.getCalendarType(), fieldIndex, toStyle(style), 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);
if (chrono == JapaneseChronology.INSTANCE) {
if (era == 0) {
era = -999;
} else {
era -= 2;
}
}
! list.add(createEntry(key, (long) era));
}
break;
case Calendar.MONTH:
! for (String key : map.keySet()) {
! list.add(createEntry(key, (long)(map.get(key) + 1)));
}
break;
case Calendar.DAY_OF_WEEK:
! for (String key : map.keySet()) {
! list.add(createEntry(key, (long)toWeekDay(map.get(key))));
}
break;
default:
! for (String key : map.keySet()) {
! list.add(createEntry(key, (long)map.get(key)));
}
break;
}
return list.iterator();
}
--- 263,306 ----
break;
default:
return null;
}
! 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 (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(entry.getKey(), (long)era));
}
break;
case Calendar.MONTH:
! for (Map.Entry<String, Integer> entry : map.entrySet()) {
! list.add(createEntry(entry.getKey(), (long)(entry.getValue() + 1)));
}
break;
case Calendar.DAY_OF_WEEK:
! for (Map.Entry<String, Integer> entry : map.entrySet()) {
! list.add(createEntry(entry.getKey(), (long)toWeekDay(entry.getValue())));
}
break;
default:
! for (Map.Entry<String, Integer> entry : map.entrySet()) {
! list.add(createEntry(entry.getKey(), (long)entry.getValue()));
}
break;
}
return list.iterator();
}
*** 331,419 ****
private Object createStore(TemporalField field, Locale locale) {
Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>();
if (field == ERA) {
for (TextStyle textStyle : TextStyle.values()) {
Map<Long, String> map = new HashMap<>();
! for (Entry<String, Integer> entry :
! CalendarDataUtility.retrieveCldrFieldValueNames(
! "gregory", Calendar.ERA, toStyle(textStyle), locale).entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
return new LocaleStore(styleMap);
}
if (field == MONTH_OF_YEAR) {
Map<Long, String> map = new HashMap<>();
! for (Entry<String, Integer> entry :
! CalendarDataUtility.retrieveCldrFieldValueNames(
! "gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).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<>();
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);
}
}
if (!map.isEmpty()) {
! styleMap.put(TextStyle.NARROW, map);
}
return new LocaleStore(styleMap);
}
if (field == DAY_OF_WEEK) {
Map<Long, String> map = new HashMap<>();
! for (Entry<String, Integer> entry :
! CalendarDataUtility.retrieveCldrFieldValueNames(
! "gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).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<>();
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));
}
- styleMap.put(TextStyle.NARROW, map);
return new LocaleStore(styleMap);
}
if (field == AMPM_OF_DAY) {
Map<Long, String> map = new HashMap<>();
! for (Entry<String, Integer> entry :
! CalendarDataUtility.retrieveCldrFieldValueNames(
! "gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).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
return new LocaleStore(styleMap);
}
return ""; // null marker for map
}
--- 326,455 ----
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 : 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<>();
! if (displayNames != null) {
! for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) (entry.getValue() + 1), entry.getKey());
}
! } 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.retrieveJavaTimeFieldValueName(
! "gregory", Calendar.MONTH, month, textStyle.toCalendarStyle(), locale);
! if (name == null) {
! break;
! }
! map.put((long) (month + 1), name);
}
}
if (!map.isEmpty()) {
! 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<>();
! if (displayNames != null) {
! for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long)toWeekDay(entry.getValue()), entry.getKey());
}
!
! } 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++) {
! 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);
! }
}
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 : displayNames.entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
! 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,437 ****
--- 464,490 ----
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,475 ****
*/
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()) {
Map<String, Entry<String, Long>> reverse = new HashMap<>();
! for (Map.Entry<Long, String> entry : valueTextMap.get(style).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);
allList.addAll(list);
map.put(null, allList);
}
Collections.sort(allList, COMPARATOR);
this.parsable = map;
--- 508,528 ----
*/
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 (Map.Entry<TextStyle, Map<Long, String>> vtmEntry : valueTextMap.entrySet()) {
Map<String, Entry<String, Long>> reverse = new HashMap<>();
! 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(vtmEntry.getKey(), list);
allList.addAll(list);
map.put(null, allList);
}
Collections.sort(allList, COMPARATOR);
this.parsable = map;