1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. The Android Open Source 7 * Project designates this particular file as subject to the "Classpath" 8 * exception as provided by The Android Open Source Project in the LICENSE 9 * file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 22 package java.time.zone; 23 24 25 import android.icu.util.TimeZone; 26 27 import com.android.icu.util.ExtendedTimeZone; 28 29 import java.util.Collections; 30 import java.util.HashSet; 31 import java.util.NavigableMap; 32 import java.util.Set; 33 import java.util.TreeMap; 34 import libcore.util.BasicLruCache; 35 36 /** 37 * A ZoneRulesProvider that generates rules from ICU4J TimeZones. 38 * This provider ensures that classes in {@link java.time} use the same time zone information 39 * as ICU4J. 40 */ 41 public class IcuZoneRulesProvider extends ZoneRulesProvider { 42 43 private final BasicLruCache<String, ZoneRules> cache = new ZoneRulesCache(8); 44 45 @Override provideZoneIds()46 protected Set<String> provideZoneIds() { 47 Set<String> zoneIds = TimeZone.getAvailableIDs(TimeZone.SystemTimeZoneType.ANY, null, null); 48 zoneIds = new HashSet<>(zoneIds); 49 // java.time assumes ZoneId that start with "GMT" fit the pattern "GMT+HH:mm:ss" which these 50 // do not. Since they are equivalent to GMT, just remove these aliases. 51 zoneIds.remove("GMT+0"); 52 zoneIds.remove("GMT-0"); 53 return zoneIds; 54 } 55 56 @Override provideRules(String zoneId, boolean forCaching)57 protected ZoneRules provideRules(String zoneId, boolean forCaching) { 58 // Ignore forCaching, as this is a static provider. 59 return cache.get(zoneId); 60 } 61 62 @Override provideVersions(String zoneId)63 protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) { 64 return new TreeMap<>( 65 Collections.singletonMap(TimeZone.getTZDataVersion(), 66 provideRules(zoneId, /* forCaching */ false))); 67 } 68 generateZoneRules(String zoneId)69 static ZoneRules generateZoneRules(String zoneId) { 70 return ExtendedTimeZone.getInstance(zoneId).createZoneRules(); 71 } 72 73 private static class ZoneRulesCache extends BasicLruCache<String, ZoneRules> { 74 ZoneRulesCache(int maxSize)75 ZoneRulesCache(int maxSize) { 76 super(maxSize); 77 } 78 79 @Override create(String zoneId)80 protected ZoneRules create(String zoneId) { 81 String canonicalId = TimeZone.getCanonicalID(zoneId); 82 if (!canonicalId.equals(zoneId)) { 83 // Return the same object as the canonical one, to avoid wasting space, but cache 84 // it under the non-cannonical name as well, to avoid future getCanonicalID calls. 85 return get(canonicalId); 86 } 87 return generateZoneRules(zoneId); 88 } 89 } 90 } 91