blob: a8db50e51782c84e609bc92a9bcfee3c88137465 [file] [log] [blame]
Neil Fullerf7346ec2019-08-30 18:02:47 +01001/*
2 * Copyright (C) 2019 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
17package android.timezone;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
Neil Fullerf7346ec2019-08-30 18:02:47 +010021import android.icu.util.TimeZone;
22
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.List;
26import java.util.Objects;
27
28/**
29 * Information about a country's time zones.
30 *
31 * @hide
32 */
Neil Fullerf7346ec2019-08-30 18:02:47 +010033public final class CountryTimeZones {
34
35 /**
36 * A mapping to a time zone ID with some associated metadata.
37 *
38 * @hide
39 */
Neil Fullerf7346ec2019-08-30 18:02:47 +010040 public static final class TimeZoneMapping {
41
Neil Fuller2551c032020-01-16 18:39:17 +000042 @NonNull
Neil Fullerf7346ec2019-08-30 18:02:47 +010043 private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate;
44
45 TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) {
46 this.mDelegate = Objects.requireNonNull(delegate);
47 }
48
49 /**
Neil Fuller45a0c412020-01-28 16:46:59 +000050 * Returns the ID for this mapping. The ID is a tzdb time zone identifier like
51 * "America/Los_Angeles" that can be used with methods such as {@link
52 * TimeZone#getFrozenTimeZone(String)}. See {@link #getTimeZone()} which returns a frozen
53 * {@link TimeZone} object.
Neil Fullerf7346ec2019-08-30 18:02:47 +010054 */
55 @NonNull
56 public String getTimeZoneId() {
Neil Fuller4720cf02020-01-28 15:05:35 +000057 return mDelegate.getTimeZoneId();
Neil Fullerf7346ec2019-08-30 18:02:47 +010058 }
59
60 /**
Neil Fuller45a0c412020-01-28 16:46:59 +000061 * Returns a frozen {@link TimeZone} object for this mapping.
Neil Fullerf7346ec2019-08-30 18:02:47 +010062 */
Neil Fuller45a0c412020-01-28 16:46:59 +000063 @NonNull
Neil Fullerf7346ec2019-08-30 18:02:47 +010064 public TimeZone getTimeZone() {
65 return mDelegate.getTimeZone();
66 }
67
68 @Override
69 public boolean equals(Object o) {
70 if (this == o) {
71 return true;
72 }
73 if (o == null || getClass() != o.getClass()) {
74 return false;
75 }
76 TimeZoneMapping that = (TimeZoneMapping) o;
77 return this.mDelegate.equals(that.mDelegate);
78 }
79
80 @Override
81 public int hashCode() {
82 return this.mDelegate.hashCode();
83 }
84
85 @Override
86 public String toString() {
87 return mDelegate.toString();
88 }
89 }
90
91 /**
92 * The result of lookup up a time zone using offset information (and possibly more).
93 *
94 * @hide
95 */
Neil Fullerf7346ec2019-08-30 18:02:47 +010096 public static final class OffsetResult {
97
98 private final TimeZone mTimeZone;
99 private final boolean mIsOnlyMatch;
100
101 /** Creates an instance with the supplied information. */
102 public OffsetResult(@NonNull TimeZone timeZone, boolean isOnlyMatch) {
103 mTimeZone = Objects.requireNonNull(timeZone);
104 mIsOnlyMatch = isOnlyMatch;
105 }
106
107 /**
108 * Returns a time zone that matches the supplied criteria.
109 */
110 @NonNull
111 public TimeZone getTimeZone() {
112 return mTimeZone;
113 }
114
115 /**
116 * Returns {@code true} if there is only one matching time zone for the supplied criteria.
117 */
118 public boolean isOnlyMatch() {
119 return mIsOnlyMatch;
120 }
121
122 @Override
123 public boolean equals(Object o) {
124 if (this == o) {
125 return true;
126 }
127 if (o == null || getClass() != o.getClass()) {
128 return false;
129 }
130 OffsetResult that = (OffsetResult) o;
131 return mIsOnlyMatch == that.mIsOnlyMatch
132 && mTimeZone.getID().equals(that.mTimeZone.getID());
133 }
134
135 @Override
136 public int hashCode() {
137 return Objects.hash(mTimeZone, mIsOnlyMatch);
138 }
139
140 @Override
141 public String toString() {
142 return "OffsetResult{"
Neil Fullerd0213082020-03-09 10:11:36 +0000143 + "mTimeZone(ID)=" + mTimeZone.getID()
Neil Fullerf7346ec2019-08-30 18:02:47 +0100144 + ", mIsOnlyMatch=" + mIsOnlyMatch
145 + '}';
146 }
147 }
148
149 @NonNull
150 private final libcore.timezone.CountryTimeZones mDelegate;
151
152 CountryTimeZones(libcore.timezone.CountryTimeZones delegate) {
153 mDelegate = delegate;
154 }
155
156 /**
Neil Fuller45a0c412020-01-28 16:46:59 +0000157 * Returns true if the ISO code for the country is a case-insensitive match for the one
158 * supplied.
Neil Fullerf7346ec2019-08-30 18:02:47 +0100159 */
Neil Fuller45a0c412020-01-28 16:46:59 +0000160 public boolean matchesCountryCode(@NonNull String countryIso) {
Neil Fullerf7346ec2019-08-30 18:02:47 +0100161 return mDelegate.isForCountryCode(countryIso);
162 }
163
164 /**
165 * Returns the default time zone ID for the country. Can return {@code null} in cases when no
166 * data is available or the time zone ID was not recognized.
167 */
168 @Nullable
169 public String getDefaultTimeZoneId() {
170 return mDelegate.getDefaultTimeZoneId();
171 }
172
173 /**
174 * Returns the default time zone for the country. Can return {@code null} in cases when no data
175 * is available or the time zone ID was not recognized.
176 */
177 @Nullable
178 public TimeZone getDefaultTimeZone() {
179 return mDelegate.getDefaultTimeZone();
180 }
181
182 /**
Neil Fuller45a0c412020-01-28 16:46:59 +0000183 * Qualifier for a country's default time zone. {@code true} indicates that the country's
184 * default time zone would be a good choice <em>generally</em> when there's no UTC offset
185 * information available. This will only be {@code true} in countries with multiple zones where
186 * a large majority of the population is covered by only one of them.
Neil Fullerf7346ec2019-08-30 18:02:47 +0100187 */
188 public boolean isDefaultTimeZoneBoosted() {
Neil Fuller4720cf02020-01-28 15:05:35 +0000189 return mDelegate.isDefaultTimeZoneBoosted();
Neil Fullerf7346ec2019-08-30 18:02:47 +0100190 }
191
192 /**
Neil Fuller45a0c412020-01-28 16:46:59 +0000193 * Returns {@code true} if the country has at least one time zone that uses UTC at the given
194 * time. This is an efficient check when trying to validate received UTC offset information.
195 * For example, there are situations when a detected zero UTC offset cannot be distinguished
196 * from "no information available" or a corrupted signal. This method is useful because checking
197 * offset information for large countries is relatively expensive but it is generally only the
198 * countries close to the prime meridian that use UTC at <em>any</em> time of the year.
199 *
200 * @param whenMillis the time the offset information is for in milliseconds since the beginning
201 * of the Unix epoch
Neil Fullerf7346ec2019-08-30 18:02:47 +0100202 */
203 public boolean hasUtcZone(long whenMillis) {
204 return mDelegate.hasUtcZone(whenMillis);
205 }
206
207 /**
Neil Fullerb2d03062020-02-04 21:17:07 +0000208 * Returns a time zone for the country, if there is one, that matches the supplied properties.
209 * If there are multiple matches and the {@code bias} is one of them then it is returned,
210 * otherwise an arbitrary match is returned based on the {@link
211 * #getEffectiveTimeZoneMappingsAt(long)} ordering.
Neil Fullerf7346ec2019-08-30 18:02:47 +0100212 *
Neil Fullerb2d03062020-02-04 21:17:07 +0000213 * @param whenMillis the UTC time to match against
214 * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
Neil Fullerf7346ec2019-08-30 18:02:47 +0100215 * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
216 * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST,
Neil Fullerb2d03062020-02-04 21:17:07 +0000217 * {@code false} means not DST
218 * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
219 * there is no match
Neil Fullerf7346ec2019-08-30 18:02:47 +0100220 */
221 @Nullable
Neil Fullerb2d03062020-02-04 21:17:07 +0000222 public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
223 int totalOffsetMillis, boolean isDst) {
Neil Fullerf7346ec2019-08-30 18:02:47 +0100224 libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
225 mDelegate.lookupByOffsetWithBias(
Neil Fullerb2d03062020-02-04 21:17:07 +0000226 whenMillis, bias, totalOffsetMillis, isDst);
227 return delegateOffsetResult == null ? null :
228 new OffsetResult(
229 delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
230 }
231
232 /**
233 * Returns a time zone for the country, if there is one, that matches the supplied properties.
234 * If there are multiple matches and the {@code bias} is one of them then it is returned,
235 * otherwise an arbitrary match is returned based on the {@link
236 * #getEffectiveTimeZoneMappingsAt(long)} ordering.
237 *
238 * @param whenMillis the UTC time to match against
239 * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
240 * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
241 * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
242 * there is no match
243 */
244 @Nullable
245 public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
246 int totalOffsetMillis) {
247 libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
248 mDelegate.lookupByOffsetWithBias(whenMillis, bias, totalOffsetMillis);
Neil Fullerf7346ec2019-08-30 18:02:47 +0100249 return delegateOffsetResult == null ? null :
Neil Fuller4720cf02020-01-28 15:05:35 +0000250 new OffsetResult(
251 delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
Neil Fullerf7346ec2019-08-30 18:02:47 +0100252 }
253
254 /**
255 * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
256 * "priority" order, filtered so that only "effective" time zone IDs are returned. An
257 * "effective" time zone is one that differs from another time zone used in the country after
258 * {@code whenMillis}. The list can be empty if there were no zones configured or the configured
259 * zone IDs were not recognized.
260 */
261 @NonNull
262 public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
263 List<libcore.timezone.CountryTimeZones.TimeZoneMapping> delegateList =
264 mDelegate.getEffectiveTimeZoneMappingsAt(whenMillis);
265
266 List<TimeZoneMapping> toReturn = new ArrayList<>(delegateList.size());
267 for (libcore.timezone.CountryTimeZones.TimeZoneMapping delegateMapping : delegateList) {
268 toReturn.add(new TimeZoneMapping(delegateMapping));
269 }
270 return Collections.unmodifiableList(toReturn);
271 }
272
273 @Override
274 public boolean equals(Object o) {
275 if (this == o) {
276 return true;
277 }
278 if (o == null || getClass() != o.getClass()) {
279 return false;
280 }
281 CountryTimeZones that = (CountryTimeZones) o;
282 return mDelegate.equals(that.mDelegate);
283 }
284
285 @Override
286 public int hashCode() {
287 return Objects.hash(mDelegate);
288 }
289
290 @Override
291 public String toString() {
292 return mDelegate.toString();
293 }
294}