1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2009,2016 International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.impl; 10 11 import java.util.Locale; 12 import java.util.Map; 13 import java.util.MissingResourceException; 14 import java.util.TreeMap; 15 16 import com.ibm.icu.util.ULocale; 17 import com.ibm.icu.util.UResourceBundle; 18 19 /** 20 * Calendar utilities. 21 * 22 * Date/time format service classes in com.ibm.icu.text packages 23 * sometimes need to access calendar internal APIs. But calendar 24 * classes are in com.ibm.icu.util package, so the package local 25 * cannot be used. This class is added in com.ibm.icu.impl 26 * package for sharing some calendar internal code for calendar 27 * and date format. 28 */ 29 public final class CalendarUtil { 30 private static final String CALKEY = "calendar"; 31 private static final String DEFCAL = "gregorian"; 32 33 /** 34 * Returns a calendar type for the given locale. 35 * When the given locale has calendar keyword, the 36 * value of calendar keyword is returned. Otherwise, 37 * the default calendar type for the locale is returned. 38 * @param loc The locale 39 * @return Calendar type string, such as "gregorian" 40 */ getCalendarType(ULocale loc)41 public static String getCalendarType(ULocale loc) { 42 String calType = loc.getKeywordValue(CALKEY); 43 if (calType != null) { 44 // Convert to lower case, because getKeywordValue does not 45 // canonicalize keyword value. 46 return calType.toLowerCase(Locale.ROOT); 47 } 48 49 // Canonicalize, so grandfathered variant will be transformed to keywords 50 ULocale canonical = ULocale.createCanonical(loc.toString()); 51 calType = canonical.getKeywordValue(CALKEY); 52 if (calType != null) { 53 return calType; 54 } 55 56 // When calendar keyword is not available, use the locale's 57 // region to get the default calendar type 58 String region = ULocale.getRegionForSupplementalData(canonical, true); 59 return CalendarPreferences.INSTANCE.getCalendarTypeForRegion(region); 60 } 61 62 private static final class CalendarPreferences extends UResource.Sink { 63 private static final CalendarPreferences INSTANCE = new CalendarPreferences(); 64 // A TreeMap should be good because we expect very few entries. 65 Map<String, String> prefs = new TreeMap<String, String>(); 66 CalendarPreferences()67 CalendarPreferences() { 68 try { 69 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance( 70 ICUData.ICU_BASE_NAME, "supplementalData"); 71 rb.getAllItemsWithFallback("calendarPreferenceData", this); 72 } catch (MissingResourceException mre) { 73 // Always use "gregorian". 74 } 75 } 76 getCalendarTypeForRegion(String region)77 String getCalendarTypeForRegion(String region) { 78 String type = prefs.get(region); 79 return type == null ? DEFCAL : type; 80 } 81 82 @Override put(UResource.Key key, UResource.Value value, boolean noFallback)83 public void put(UResource.Key key, UResource.Value value, boolean noFallback) { 84 UResource.Table calendarPreferenceData = value.getTable(); 85 for (int i = 0; calendarPreferenceData.getKeyAndValue(i, key, value); ++i) { 86 UResource.Array types = value.getArray(); 87 // The first calendar type is the default for the region. 88 if (types.getValue(0, value)) { 89 String type = value.getString(); 90 if (!type.equals(DEFCAL)) { 91 prefs.put(key.toString(), type); 92 } 93 } 94 } 95 } 96 } 97 } 98