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