• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.libcore.timezone.tzlookup.zonetree;
17 
18 import com.ibm.icu.text.TimeZoneNames;
19 import com.ibm.icu.util.BasicTimeZone;
20 import com.ibm.icu.util.TimeZone;
21 
22 import java.time.Instant;
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 /**
27  * Contains information about a tzdb-defined time zone for a time period.
28  */
29 final class ZoneInfo {
30 
31     private static final int MIN_PRIORITY = 1;
32 
33     /**
34      * Priority can be used to establish dominance of one zone info over another if they are
35      * otherwise identical for a zone offset period. Highest numerical priority "wins".
36      */
37     private final int priority;
38 
39     /** The zone offset periods for the zone. They are stored in ascending order of start time. */
40     private final List<ZoneOffsetPeriod> zoneOffsetPeriods;
41 
42     /** The time zone ID. */
43     private final String zoneId;
44 
ZoneInfo(String zoneId, int priority, List<ZoneOffsetPeriod> zoneOffsetPeriods)45     private ZoneInfo(String zoneId, int priority, List<ZoneOffsetPeriod> zoneOffsetPeriods) {
46         if (priority < MIN_PRIORITY) {
47             throw new IllegalArgumentException("priority must be >=" + MIN_PRIORITY);
48         }
49         this.zoneOffsetPeriods = zoneOffsetPeriods;
50         this.priority = priority;
51         this.zoneId = zoneId;
52     }
53 
54     /**
55      * Creates a ZoneInfo using the supplied ICU data and metadata.
56      *
57      * <p>The priority must be >= 1, and startInclusive is expected to be before endExclusive.
58      *
59      * <p>The returned {@link ZoneInfo} will be populated with {@link ZoneOffsetPeriod}s using
60      * the ICU time zone rules and names supplied in the specified period.
61      */
create(TimeZoneNames timeZoneNames, BasicTimeZone timeZone, int priority, Instant startInclusive, Instant endExclusive)62     public static ZoneInfo create(TimeZoneNames timeZoneNames, BasicTimeZone timeZone, int priority,
63             Instant startInclusive, Instant endExclusive) {
64         List<ZoneOffsetPeriod> zoneOffsetPeriods = new ArrayList<>();
65 
66         // Start off the zone key with an artificial entry at startInclusive.
67         Instant start = startInclusive;
68         do {
69             ZoneOffsetPeriod zoneOffsetPeriod =
70                     ZoneOffsetPeriod.create(timeZoneNames, timeZone, start, endExclusive);
71             zoneOffsetPeriods.add(zoneOffsetPeriod);
72             start = zoneOffsetPeriod.getEndInstant();
73         } while (start.isBefore(endExclusive));
74 
75         return new ZoneInfo(timeZone.getID(), priority, zoneOffsetPeriods);
76     }
77 
78     /**
79      * Splits the final {@link ZoneOffsetPeriod} at the specified time and replaces it with two
80      * {@link ZoneOffsetPeriod}s instead, using the supplied ICU names information to help obtain
81      * the name for the later of the two periods.
82      */
splitZoneOffsetPeriodAtTime( TimeZoneNames timeZoneNames, ZoneInfo zoneInfo, int index, Instant partitionInstant)83     public static void splitZoneOffsetPeriodAtTime(
84             TimeZoneNames timeZoneNames, ZoneInfo zoneInfo, int index, Instant partitionInstant) {
85         ZoneOffsetPeriod oldZoneOffsetPeriod = zoneInfo.zoneOffsetPeriods.get(index);
86         BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneInfo.getZoneId());
87         ZoneOffsetPeriod[] newPeriods = ZoneOffsetPeriod.splitAtTime(
88                 oldZoneOffsetPeriod, timeZoneNames, timeZone, partitionInstant);
89         zoneInfo.zoneOffsetPeriods.set(index, newPeriods[0]);
90         zoneInfo.zoneOffsetPeriods.add(index + 1, newPeriods[1]);
91     }
92 
getZoneId()93     public String getZoneId() {
94         return zoneId;
95     }
96 
getPriority()97     public int getPriority() {
98         return priority;
99     }
100 
101     @Override
toString()102     public String toString() {
103         return "ZoneInfo{" +
104                 "priority=" + priority +
105                 ", zoneId=" + zoneId +
106                 '}';
107     }
108 
109     /**
110      * Creates a hashable key object that can be used to tell if the zone is the same for a range
111      * of periods.
112      *
113      * @param zonePeriodStartIndex the start index (inclusive)
114      * @param zonePeriodEndIndex the end index (exclusive)
115      */
createZonePeriodsKey( int zonePeriodStartIndex, int zonePeriodEndIndex)116     public ZoneOffsetPeriod.ZonePeriodsKey createZonePeriodsKey(
117             int zonePeriodStartIndex, int zonePeriodEndIndex) {
118         List<ZoneOffsetPeriod> periodsSubList =
119                 zoneOffsetPeriods.subList(zonePeriodStartIndex, zonePeriodEndIndex);
120         return new ZoneOffsetPeriod.ZonePeriodsKey(periodsSubList);
121     }
122 
123     /**
124      * Returns a single {@link ZoneOffsetPeriod}.
125      */
getZoneOffsetPeriod(int index)126     public ZoneOffsetPeriod getZoneOffsetPeriod(int index) {
127         return zoneOffsetPeriods.get(index);
128     }
129 
130     /**
131      * Returns the total number of {@link ZoneOffsetPeriod}s associated with the zone.
132      */
getZoneOffsetPeriodCount()133     public int getZoneOffsetPeriodCount() {
134         return zoneOffsetPeriods.size();
135     }
136 }
137