46 * * Neither the name of JSR-310 nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 package java.time.format; 63 64 import static java.time.temporal.ChronoField.AMPM_OF_DAY; 65 import static java.time.temporal.ChronoField.DAY_OF_WEEK; 66 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 67 68 import java.time.temporal.Chrono; 69 import java.time.temporal.ISOChrono; 70 import java.time.calendar.JapaneseChrono; 71 import java.time.calendar.ThaiBuddhistChrono; 72 import java.time.temporal.TemporalField; 73 import java.util.AbstractMap.SimpleImmutableEntry; 74 import java.util.ArrayList; 75 import java.util.Calendar; 76 import java.util.Collections; 77 import java.util.Comparator; 78 import java.util.HashMap; 79 import java.util.Iterator; 80 import java.util.List; 81 import java.util.Locale; 82 import java.util.Map; 83 import java.util.Map.Entry; 84 import java.util.concurrent.ConcurrentHashMap; 85 import java.util.concurrent.ConcurrentMap; 86 import java.util.spi.CalendarNameProvider; 87 88 import sun.util.locale.provider.LocaleProviderAdapter; 89 import sun.util.locale.provider.CalendarDataUtility; 90 91 /** 92 * A provider to obtain the textual form of a date-time field. 93 * 94 * <h3>Specification for implementors</h3> 95 * Implementations must be thread-safe. 96 * Implementations should cache the textual information. 97 * 98 * @since 1.8 99 */ 100 class DateTimeTextProvider { 101 102 /** Cache. */ 103 private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2); 104 /** Comparator. */ 105 private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() { 106 @Override 107 public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) { 108 return obj2.getKey().length() - obj1.getKey().length(); // longest to shortest 109 } 110 }; 111 112 DateTimeTextProvider() {} 113 114 /** 115 * Gets the provider of text. 116 * 117 * @return the provider, not null 118 */ 119 static DateTimeTextProvider getInstance() { 120 return new DateTimeTextProvider(); 121 } 122 123 /** 124 * Gets the text for the specified field, locale and style 125 * for the purpose of printing. 126 * <p> 127 * The text associated with the value is returned. 128 * The null return value should be used if there is no applicable text, or 129 * if the text would be a numeric representation of the value. 130 * 131 * @param field the field to get text for, not null 132 * @param value the field value to get text for, not null 133 * @param style the style to get text for, not null 134 * @param locale the locale to get text for, not null 135 * @return the text for the field value, null if no text found 136 */ 137 public String getText(TemporalField field, long value, TextStyle style, Locale locale) { 138 Object store = findStore(field, locale); 139 if (store instanceof LocaleStore) { 140 return ((LocaleStore) store).getText(value, style); 141 } 142 return null; 143 } 144 145 private static int toStyle(TextStyle style) { 146 if (style == TextStyle.FULL) { 147 return Calendar.LONG_FORMAT; 148 } else if (style == TextStyle.SHORT) { 149 return Calendar.SHORT_FORMAT; 150 } 151 return Calendar.NARROW_STANDALONE; 152 } 153 154 /** 155 * Gets the era text for the specified chrono, value, style and locale 156 * for the purpose of printing. 157 * <p> 158 * The era text associated with the value is returned. 159 * The null return value should be used if there is no applicable text, or 160 * if the text would be a numeric representation of the value. 161 * 162 * @param chrono the chrono to get text for, not null 163 * @param value the field value to get text for, not null 164 * @param style the style to get text for, not null 165 * @param locale the locale to get text for, not null 166 * @return the era text for the value, null if no text found 167 */ 168 public String getEraText(Chrono chrono, long value, TextStyle style, Locale locale) { 169 String type = null; 170 if (chrono == ISOChrono.INSTANCE) { 171 type = "gregory"; 172 } else if (chrono == JapaneseChrono.INSTANCE) { 173 type = "japanese"; 174 if (value == -999) { 175 value = 0; 176 } else { 177 value += 2; 178 } 179 } else if (chrono == ThaiBuddhistChrono.INSTANCE) { 180 type = "buddhist"; 181 } else { 182 return null; 183 } 184 return CalendarDataUtility.retrieveFieldValueName( 185 type, Calendar.ERA, (int)value, toStyle(style), locale); 186 } 187 188 /** 189 * Gets an iterator of text to field for the specified field, locale and style 190 * for the purpose of parsing. 191 * <p> 192 * The iterator must be returned in order from the longest text to the shortest. 193 * <p> 194 * The null return value should be used if there is no applicable parsable text, or 195 * if the text would be a numeric representation of the value. 196 * Text can only be parsed if all the values for that field-style-locale combination are unique. 197 * 198 * @param field the field to get text for, not null 199 * @param style the style to get text for, null for all parsable text 200 * @param locale the locale to get text for, not null 201 * @return the iterator of text to field pairs, in order from longest text to shortest text, 202 * null if the field or style is not parsable 203 */ 204 public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) { 205 Object store = findStore(field, locale); 206 if (store instanceof LocaleStore) { 207 return ((LocaleStore) store).getTextIterator(style); 208 } 209 return null; 210 } 211 212 private Object findStore(TemporalField field, Locale locale) { 213 Entry<TemporalField, Locale> key = createEntry(field, locale); 214 Object store = CACHE.get(key); 215 if (store == null) { 216 store = createStore(field, locale); 217 CACHE.putIfAbsent(key, store); 218 store = CACHE.get(key); 219 } 220 return store; 221 } 222 223 private static int toWeekDay(int calWeekDay) { 224 if (calWeekDay == Calendar.SUNDAY) { 225 return 7; 226 } else { 227 return calWeekDay - 1; 228 } 229 } 230 231 private Object createStore(TemporalField field, Locale locale) { 232 CalendarNameProvider provider = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, locale) 233 .getCalendarNameProvider(); 234 Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>(); 235 if (field == MONTH_OF_YEAR) { 236 Map<Long, String> map = new HashMap<>(); 237 for (Entry<String, Integer> entry : 238 provider.getDisplayNames("gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).entrySet()) { 239 map.put((long)(entry.getValue() + 1), entry.getKey()); 240 } 241 styleMap.put(TextStyle.FULL, map); 242 243 map = new HashMap<>(); 244 for (Entry<String, Integer> entry : 245 provider.getDisplayNames("gregory", Calendar.MONTH, Calendar.SHORT_FORMAT, locale).entrySet()) { 246 map.put((long)(entry.getValue() + 1), entry.getKey()); 247 } 248 styleMap.put(TextStyle.SHORT, map); 249 250 map = new HashMap<>(); 251 for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { 252 String name = provider.getDisplayName("gregory", Calendar.MONTH, month, Calendar.NARROW_STANDALONE, locale); 253 if (name != null) { 254 map.put((long)(month + 1), name); 255 } 256 } 257 if (map.size() != 0) { 258 styleMap.put(TextStyle.NARROW, map); 259 } 260 return new LocaleStore(styleMap); 261 } 262 if (field == DAY_OF_WEEK) { 263 Map<Long, String> map = new HashMap<>(); 264 for (Entry<String, Integer> entry : 265 provider.getDisplayNames("gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).entrySet()) { 266 map.put((long)toWeekDay(entry.getValue()), entry.getKey()); 267 } 268 styleMap.put(TextStyle.FULL, map); 269 map = new HashMap<>(); 270 for (Entry<String, Integer> entry : 271 provider.getDisplayNames("gregory", Calendar.DAY_OF_WEEK, Calendar.SHORT_FORMAT, locale).entrySet()) { 272 map.put((long)toWeekDay(entry.getValue()), entry.getKey()); 273 } 274 styleMap.put(TextStyle.SHORT, map); 275 map = new HashMap<>(); 276 for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) { 277 map.put((long)toWeekDay(wday), 278 provider.getDisplayName("gregory", Calendar.DAY_OF_WEEK, wday, Calendar.NARROW_FORMAT, locale)); 279 } 280 styleMap.put(TextStyle.NARROW, map); 281 return new LocaleStore(styleMap); 282 } 283 if (field == AMPM_OF_DAY) { 284 Map<Long, String> map = new HashMap<>(); 285 for (Entry<String, Integer> entry : 286 provider.getDisplayNames("gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).entrySet()) { 287 map.put((long)entry.getValue(), entry.getKey()); 288 } 289 styleMap.put(TextStyle.FULL, map); 290 styleMap.put(TextStyle.SHORT, map); // re-use, as we don't have different data 291 return new LocaleStore(styleMap); 292 } 293 return ""; // null marker for map 294 } 295 296 /** 297 * Helper method to create an immutable entry. 298 * 299 * @param text the text, not null 300 * @param field the field, not null 301 * @return the entry, not null 302 */ 303 private static <A, B> Entry<A, B> createEntry(A text, B field) { 304 return new SimpleImmutableEntry<>(text, field); 305 } 306 307 /** 308 * Stores the text for a single locale. 309 * <p> 310 * Some fields have a textual representation, such as day-of-week or month-of-year. 311 * These textual representations can be captured in this class for printing 312 * and parsing. | 46 * * Neither the name of JSR-310 nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 package java.time.format; 63 64 import static java.time.temporal.ChronoField.AMPM_OF_DAY; 65 import static java.time.temporal.ChronoField.DAY_OF_WEEK; 66 import static java.time.temporal.ChronoField.ERA; 67 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 68 69 import java.time.chrono.Chronology; 70 import java.time.chrono.IsoChronology; 71 import java.time.chrono.JapaneseChronology; 72 import java.time.temporal.ChronoField; 73 import java.time.temporal.TemporalField; 74 import java.util.AbstractMap.SimpleImmutableEntry; 75 import java.util.ArrayList; 76 import java.util.Calendar; 77 import java.util.Collections; 78 import java.util.Comparator; 79 import java.util.HashMap; 80 import java.util.Iterator; 81 import java.util.List; 82 import java.util.Locale; 83 import java.util.Map; 84 import java.util.Map.Entry; 85 import java.util.concurrent.ConcurrentHashMap; 86 import java.util.concurrent.ConcurrentMap; 87 88 import sun.util.locale.provider.CalendarDataUtility; 89 90 /** 91 * A provider to obtain the textual form of a date-time field. 92 * 93 * <h3>Specification for implementors</h3> 94 * Implementations must be thread-safe. 95 * Implementations should cache the textual information. 96 * 97 * @since 1.8 98 */ 99 class DateTimeTextProvider { 100 101 /** Cache. */ 102 private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2); 103 /** Comparator. */ 104 private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() { 105 @Override 106 public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) { 107 return obj2.getKey().length() - obj1.getKey().length(); // longest to shortest 108 } 109 }; 110 111 DateTimeTextProvider() {} 112 113 /** 114 * Gets the provider of text. 115 * 116 * @return the provider, not null 117 */ 118 static DateTimeTextProvider getInstance() { 119 return new DateTimeTextProvider(); 120 } 121 122 /** 123 * Gets the text for the specified field, locale and style 124 * for the purpose of formatting. 125 * <p> 126 * The text associated with the value is returned. 127 * The null return value should be used if there is no applicable text, or 128 * if the text would be a numeric representation of the value. 129 * 130 * @param field the field to get text for, not null 131 * @param value the field value to get text for, not null 132 * @param style the style to get text for, not null 133 * @param locale the locale to get text for, not null 134 * @return the text for the field value, null if no text found 135 */ 136 public String getText(TemporalField field, long value, TextStyle style, Locale locale) { 137 Object store = findStore(field, locale); 138 if (store instanceof LocaleStore) { 139 return ((LocaleStore) store).getText(value, style); 140 } 141 return null; 142 } 143 144 private static int toStyle(TextStyle style) { 145 if (style == TextStyle.FULL) { 146 return Calendar.LONG_FORMAT; 147 } else if (style == TextStyle.SHORT) { 148 return Calendar.SHORT_FORMAT; 149 } 150 return Calendar.NARROW_STANDALONE; 151 } 152 153 /** 154 * Gets the text for the specified chrono, field, locale and style 155 * for the purpose of formatting. 156 * <p> 157 * The text associated with the value is returned. 158 * The null return value should be used if there is no applicable text, or 159 * if the text would be a numeric representation of the value. 160 * 161 * @param chrono the Chronology to get text for, not null 162 * @param field the field to get text for, not null 163 * @param value the field value to get text for, not null 164 * @param style the style to get text for, not null 165 * @param locale the locale to get text for, not null 166 * @return the text for the field value, null if no text found 167 */ 168 public String getText(Chronology chrono, TemporalField field, long value, 169 TextStyle style, Locale locale) { 170 if (chrono == IsoChronology.INSTANCE 171 || !(field instanceof ChronoField)) { 172 return getText(field, value, style, locale); 173 } 174 175 int fieldIndex; 176 int fieldValue; 177 if (field == ERA) { 178 fieldIndex = Calendar.ERA; 179 if (chrono == JapaneseChronology.INSTANCE) { 180 if (value == -999) { 181 fieldValue = 0; 182 } else { 183 fieldValue = (int) value + 2; 184 } 185 } else { 186 fieldValue = (int) value; 187 } 188 } else if (field == MONTH_OF_YEAR) { 189 fieldIndex = Calendar.MONTH; 190 fieldValue = (int) value - 1; 191 } else if (field == DAY_OF_WEEK) { 192 fieldIndex = Calendar.DAY_OF_WEEK; 193 fieldValue = (int) value + 1; 194 if (fieldValue > 7) { 195 fieldValue = Calendar.SUNDAY; 196 } 197 } else if (field == AMPM_OF_DAY) { 198 fieldIndex = Calendar.AM_PM; 199 fieldValue = (int) value; 200 } else { 201 return null; 202 } 203 return CalendarDataUtility.retrieveCldrFieldValueName( 204 chrono.getCalendarType(), fieldIndex, fieldValue, toStyle(style), locale); 205 } 206 207 /** 208 * Gets an iterator of text to field for the specified field, locale and style 209 * for the purpose of parsing. 210 * <p> 211 * The iterator must be returned in order from the longest text to the shortest. 212 * <p> 213 * The null return value should be used if there is no applicable parsable text, or 214 * if the text would be a numeric representation of the value. 215 * Text can only be parsed if all the values for that field-style-locale combination are unique. 216 * 217 * @param field the field to get text for, not null 218 * @param style the style to get text for, null for all parsable text 219 * @param locale the locale to get text for, not null 220 * @return the iterator of text to field pairs, in order from longest text to shortest text, 221 * null if the field or style is not parsable 222 */ 223 public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) { 224 Object store = findStore(field, locale); 225 if (store instanceof LocaleStore) { 226 return ((LocaleStore) store).getTextIterator(style); 227 } 228 return null; 229 } 230 231 /** 232 * Gets an iterator of text to field for the specified chrono, field, locale and style 233 * for the purpose of parsing. 234 * <p> 235 * The iterator must be returned in order from the longest text to the shortest. 236 * <p> 237 * The null return value should be used if there is no applicable parsable text, or 238 * if the text would be a numeric representation of the value. 239 * Text can only be parsed if all the values for that field-style-locale combination are unique. 240 * 241 * @param chrono the Chronology to get text for, not null 242 * @param field the field to get text for, not null 243 * @param style the style to get text for, null for all parsable text 244 * @param locale the locale to get text for, not null 245 * @return the iterator of text to field pairs, in order from longest text to shortest text, 246 * null if the field or style is not parsable 247 */ 248 public Iterator<Entry<String, Long>> getTextIterator(Chronology chrono, TemporalField field, 249 TextStyle style, Locale locale) { 250 if (chrono == IsoChronology.INSTANCE 251 || !(field instanceof ChronoField)) { 252 return getTextIterator(field, style, locale); 253 } 254 255 int fieldIndex; 256 switch ((ChronoField)field) { 257 case ERA: 258 fieldIndex = Calendar.ERA; 259 break; 260 case MONTH_OF_YEAR: 261 fieldIndex = Calendar.MONTH; 262 break; 263 case DAY_OF_WEEK: 264 fieldIndex = Calendar.DAY_OF_WEEK; 265 break; 266 case AMPM_OF_DAY: 267 fieldIndex = Calendar.AM_PM; 268 break; 269 default: 270 return null; 271 } 272 273 Map<String, Integer> map = CalendarDataUtility.retrieveCldrFieldValueNames( 274 chrono.getCalendarType(), fieldIndex, toStyle(style), locale); 275 if (map == null) { 276 return null; 277 } 278 279 List<Entry<String, Long>> list = new ArrayList<>(map.size()); 280 switch (fieldIndex) { 281 case Calendar.ERA: 282 for (String key : map.keySet()) { 283 int era = map.get(key); 284 if (chrono == JapaneseChronology.INSTANCE) { 285 if (era == 0) { 286 era = -999; 287 } else { 288 era -= 2; 289 } 290 } 291 list.add(createEntry(key, (long) era)); 292 } 293 break; 294 case Calendar.MONTH: 295 for (String key : map.keySet()) { 296 list.add(createEntry(key, (long)(map.get(key) + 1))); 297 } 298 break; 299 case Calendar.DAY_OF_WEEK: 300 for (String key : map.keySet()) { 301 list.add(createEntry(key, (long)toWeekDay(map.get(key)))); 302 } 303 break; 304 default: 305 for (String key : map.keySet()) { 306 list.add(createEntry(key, (long)map.get(key))); 307 } 308 break; 309 } 310 return list.iterator(); 311 } 312 313 private Object findStore(TemporalField field, Locale locale) { 314 Entry<TemporalField, Locale> key = createEntry(field, locale); 315 Object store = CACHE.get(key); 316 if (store == null) { 317 store = createStore(field, locale); 318 CACHE.putIfAbsent(key, store); 319 store = CACHE.get(key); 320 } 321 return store; 322 } 323 324 private static int toWeekDay(int calWeekDay) { 325 if (calWeekDay == Calendar.SUNDAY) { 326 return 7; 327 } else { 328 return calWeekDay - 1; 329 } 330 } 331 332 private Object createStore(TemporalField field, Locale locale) { 333 Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>(); 334 if (field == ERA) { 335 for (TextStyle textStyle : TextStyle.values()) { 336 Map<Long, String> map = new HashMap<>(); 337 for (Entry<String, Integer> entry : 338 CalendarDataUtility.retrieveCldrFieldValueNames( 339 "gregory", Calendar.ERA, toStyle(textStyle), locale).entrySet()) { 340 map.put((long) entry.getValue(), entry.getKey()); 341 } 342 if (!map.isEmpty()) { 343 styleMap.put(textStyle, map); 344 } 345 } 346 return new LocaleStore(styleMap); 347 } 348 349 if (field == MONTH_OF_YEAR) { 350 Map<Long, String> map = new HashMap<>(); 351 for (Entry<String, Integer> entry : 352 CalendarDataUtility.retrieveCldrFieldValueNames( 353 "gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).entrySet()) { 354 map.put((long) (entry.getValue() + 1), entry.getKey()); 355 } 356 styleMap.put(TextStyle.FULL, map); 357 358 map = new HashMap<>(); 359 for (Entry<String, Integer> entry : 360 CalendarDataUtility.retrieveCldrFieldValueNames( 361 "gregory", Calendar.MONTH, Calendar.SHORT_FORMAT, locale).entrySet()) { 362 map.put((long) (entry.getValue() + 1), entry.getKey()); 363 } 364 styleMap.put(TextStyle.SHORT, map); 365 366 map = new HashMap<>(); 367 for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { 368 String name; 369 name = CalendarDataUtility.retrieveCldrFieldValueName( 370 "gregory", Calendar.MONTH, month, Calendar.NARROW_STANDALONE, locale); 371 if (name != null) { 372 map.put((long)(month + 1), name); 373 } 374 } 375 if (!map.isEmpty()) { 376 styleMap.put(TextStyle.NARROW, map); 377 } 378 return new LocaleStore(styleMap); 379 } 380 381 if (field == DAY_OF_WEEK) { 382 Map<Long, String> map = new HashMap<>(); 383 for (Entry<String, Integer> entry : 384 CalendarDataUtility.retrieveCldrFieldValueNames( 385 "gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).entrySet()) { 386 map.put((long)toWeekDay(entry.getValue()), entry.getKey()); 387 } 388 styleMap.put(TextStyle.FULL, map); 389 map = new HashMap<>(); 390 for (Entry<String, Integer> entry : 391 CalendarDataUtility.retrieveCldrFieldValueNames( 392 "gregory", Calendar.DAY_OF_WEEK, Calendar.SHORT_FORMAT, locale).entrySet()) { 393 map.put((long) toWeekDay(entry.getValue()), entry.getKey()); 394 } 395 styleMap.put(TextStyle.SHORT, map); 396 map = new HashMap<>(); 397 for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) { 398 map.put((long) toWeekDay(wday), 399 CalendarDataUtility.retrieveCldrFieldValueName( 400 "gregory", Calendar.DAY_OF_WEEK, wday, Calendar.NARROW_FORMAT, locale)); 401 } 402 styleMap.put(TextStyle.NARROW, map); 403 return new LocaleStore(styleMap); 404 } 405 406 if (field == AMPM_OF_DAY) { 407 Map<Long, String> map = new HashMap<>(); 408 for (Entry<String, Integer> entry : 409 CalendarDataUtility.retrieveCldrFieldValueNames( 410 "gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).entrySet()) { 411 map.put((long) entry.getValue(), entry.getKey()); 412 } 413 styleMap.put(TextStyle.FULL, map); 414 styleMap.put(TextStyle.SHORT, map); // re-use, as we don't have different data 415 return new LocaleStore(styleMap); 416 } 417 418 return ""; // null marker for map 419 } 420 421 /** 422 * Helper method to create an immutable entry. 423 * 424 * @param text the text, not null 425 * @param field the field, not null 426 * @return the entry, not null 427 */ 428 private static <A, B> Entry<A, B> createEntry(A text, B field) { 429 return new SimpleImmutableEntry<>(text, field); 430 } 431 432 /** 433 * Stores the text for a single locale. 434 * <p> 435 * Some fields have a textual representation, such as day-of-week or month-of-year. 436 * These textual representations can be captured in this class for printing 437 * and parsing. |