1/*
2 * Copyright (C) 2008 Google Inc.
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.util;
18
19import junit.framework.TestCase;
20
21import java.util.Calendar;
22import java.util.TimeZone;
23
24/**
25 * TimeUtilsTest tests the time zone guesser.
26 */
27public class TimeUtilsTest extends TestCase {
28    public void testMainstream() throws Exception {
29        String[] mainstream = new String[] {
30            "America/New_York", // Eastern
31            "America/Chicago", // Central
32            "America/Denver", // Mountain
33            "America/Los_Angeles", // Pacific
34            "America/Anchorage", // Alaska
35            "Pacific/Honolulu", // Hawaii, no DST
36        };
37
38        for (String name : mainstream) {
39            TimeZone tz = TimeZone.getTimeZone(name);
40            Calendar c = Calendar.getInstance(tz);
41            TimeZone guess;
42
43            c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
44            guess = guess(c, "us");
45            assertEquals(name, guess.getID());
46
47            c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
48            guess = guess(c, "us");
49            assertEquals(name, guess.getID());
50        }
51    }
52
53    public void testWeird() throws Exception {
54        String[] weird = new String[] {
55            "America/Phoenix", // Mountain, no DST
56            "America/Adak", // Same as Hawaii, but with DST
57        };
58
59        for (String name : weird) {
60            TimeZone tz = TimeZone.getTimeZone(name);
61            Calendar c = Calendar.getInstance(tz);
62            TimeZone guess;
63
64            c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
65            guess = guess(c, "us");
66            assertEquals(name, guess.getID());
67        }
68    }
69
70    public void testOld() throws Exception {
71        String[] old = new String[] {
72            "America/Indiana/Indianapolis", // Eastern, formerly no DST
73        };
74
75        for (String name : old) {
76            TimeZone tz = TimeZone.getTimeZone(name);
77            Calendar c = Calendar.getInstance(tz);
78            TimeZone guess;
79
80            c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00);
81            guess = guess(c, "us");
82            assertEquals(name, guess.getID());
83        }
84    }
85
86    public void testWorld() throws Exception {
87        String[] world = new String[] {
88            "ad", "Europe/Andorra",
89            "ae", "Asia/Dubai",
90            "af", "Asia/Kabul",
91            "ag", "America/Antigua",
92            "ai", "America/Anguilla",
93            "al", "Europe/Tirane",
94            "am", "Asia/Yerevan",
95            "an", "America/Curacao",
96            "ao", "Africa/Luanda",
97            "aq", "Antarctica/McMurdo",
98            "aq", "Antarctica/DumontDUrville",
99            "aq", "Antarctica/Casey",
100            "aq", "Antarctica/Davis",
101            "aq", "Antarctica/Mawson",
102            "aq", "Antarctica/Syowa",
103            "aq", "Antarctica/Rothera",
104            "aq", "Antarctica/Palmer",
105            "ar", "America/Argentina/Buenos_Aires",
106            "as", "Pacific/Pago_Pago",
107            "at", "Europe/Vienna",
108            "au", "Australia/Sydney",
109            "au", "Australia/Adelaide",
110            "au", "Australia/Perth",
111            "au", "Australia/Eucla",
112            "aw", "America/Aruba",
113            "ax", "Europe/Mariehamn",
114            "az", "Asia/Baku",
115            "ba", "Europe/Sarajevo",
116            "bb", "America/Barbados",
117            "bd", "Asia/Dhaka",
118            "be", "Europe/Brussels",
119            "bf", "Africa/Ouagadougou",
120            "bg", "Europe/Sofia",
121            "bh", "Asia/Bahrain",
122            "bi", "Africa/Bujumbura",
123            "bj", "Africa/Porto-Novo",
124            "bm", "Atlantic/Bermuda",
125            "bn", "Asia/Brunei",
126            "bo", "America/La_Paz",
127            "br", "America/Noronha",
128            "br", "America/Sao_Paulo",
129            "br", "America/Manaus",
130            "bs", "America/Nassau",
131            "bt", "Asia/Thimphu",
132            "bw", "Africa/Gaborone",
133            "by", "Europe/Minsk",
134            "bz", "America/Belize",
135            "ca", "America/St_Johns",
136            "ca", "America/Halifax",
137            "ca", "America/Toronto",
138            "ca", "America/Winnipeg",
139            "ca", "America/Edmonton",
140            "ca", "America/Vancouver",
141            "cc", "Indian/Cocos",
142            "cd", "Africa/Lubumbashi",
143            "cd", "Africa/Kinshasa",
144            "cf", "Africa/Bangui",
145            "cg", "Africa/Brazzaville",
146            "ch", "Europe/Zurich",
147            "ci", "Africa/Abidjan",
148            "ck", "Pacific/Rarotonga",
149            "cl", "America/Santiago",
150            "cl", "Pacific/Easter",
151            "cm", "Africa/Douala",
152            "cn", "Asia/Shanghai",
153            "co", "America/Bogota",
154            "cr", "America/Costa_Rica",
155            "cu", "America/Havana",
156            "cv", "Atlantic/Cape_Verde",
157            "cx", "Indian/Christmas",
158            "cy", "Asia/Nicosia",
159            "cz", "Europe/Prague",
160            "de", "Europe/Berlin",
161            "dj", "Africa/Djibouti",
162            "dk", "Europe/Copenhagen",
163            "dm", "America/Dominica",
164            "do", "America/Santo_Domingo",
165            "dz", "Africa/Algiers",
166            "ec", "America/Guayaquil",
167            "ec", "Pacific/Galapagos",
168            "ee", "Europe/Tallinn",
169            "eg", "Africa/Cairo",
170            "eh", "Africa/El_Aaiun",
171            "er", "Africa/Asmara",
172            "es", "Europe/Madrid",
173            "es", "Atlantic/Canary",
174            "et", "Africa/Addis_Ababa",
175            "fi", "Europe/Helsinki",
176            "fj", "Pacific/Fiji",
177            "fk", "Atlantic/Stanley",
178            "fm", "Pacific/Ponape",
179            "fm", "Pacific/Truk",
180            "fo", "Atlantic/Faroe",
181            "fr", "Europe/Paris",
182            "ga", "Africa/Libreville",
183            "gb", "Europe/London",
184            "gd", "America/Grenada",
185            "ge", "Asia/Tbilisi",
186            "gf", "America/Cayenne",
187            "gg", "Europe/Guernsey",
188            "gh", "Africa/Accra",
189            "gi", "Europe/Gibraltar",
190            "gl", "America/Danmarkshavn",
191            "gl", "America/Scoresbysund",
192            "gl", "America/Godthab",
193            "gl", "America/Thule",
194            "gm", "Africa/Banjul",
195            "gn", "Africa/Conakry",
196            "gp", "America/Guadeloupe",
197            "gq", "Africa/Malabo",
198            "gr", "Europe/Athens",
199            "gs", "Atlantic/South_Georgia",
200            "gt", "America/Guatemala",
201            "gu", "Pacific/Guam",
202            "gw", "Africa/Bissau",
203            "gy", "America/Guyana",
204            "hk", "Asia/Hong_Kong",
205            "hn", "America/Tegucigalpa",
206            "hr", "Europe/Zagreb",
207            "ht", "America/Port-au-Prince",
208            "hu", "Europe/Budapest",
209            "id", "Asia/Jayapura",
210            "id", "Asia/Makassar",
211            "id", "Asia/Jakarta",
212            "ie", "Europe/Dublin",
213            "il", "Asia/Jerusalem",
214            "im", "Europe/Isle_of_Man",
215            "in", "Asia/Calcutta",
216            "io", "Indian/Chagos",
217            "iq", "Asia/Baghdad",
218            "ir", "Asia/Tehran",
219            "is", "Atlantic/Reykjavik",
220            "it", "Europe/Rome",
221            "je", "Europe/Jersey",
222            "jm", "America/Jamaica",
223            "jo", "Asia/Amman",
224            "jp", "Asia/Tokyo",
225            "ke", "Africa/Nairobi",
226            "kg", "Asia/Bishkek",
227            "kh", "Asia/Phnom_Penh",
228            "ki", "Pacific/Kiritimati",
229            "ki", "Pacific/Enderbury",
230            "ki", "Pacific/Tarawa",
231            "km", "Indian/Comoro",
232            "kn", "America/St_Kitts",
233            "kp", "Asia/Pyongyang",
234            "kr", "Asia/Seoul",
235            "kw", "Asia/Kuwait",
236            "ky", "America/Cayman",
237            "kz", "Asia/Almaty",
238            "kz", "Asia/Aqtau",
239            "la", "Asia/Vientiane",
240            "lb", "Asia/Beirut",
241            "lc", "America/St_Lucia",
242            "li", "Europe/Vaduz",
243            "lk", "Asia/Colombo",
244            "lr", "Africa/Monrovia",
245            "ls", "Africa/Maseru",
246            "lt", "Europe/Vilnius",
247            "lu", "Europe/Luxembourg",
248            "lv", "Europe/Riga",
249            "ly", "Africa/Tripoli",
250            "ma", "Africa/Casablanca",
251            "mc", "Europe/Monaco",
252            "md", "Europe/Chisinau",
253            "me", "Europe/Podgorica",
254            "mg", "Indian/Antananarivo",
255            "mh", "Pacific/Majuro",
256            "mk", "Europe/Skopje",
257            "ml", "Africa/Bamako",
258            "mm", "Asia/Rangoon",
259            "mn", "Asia/Choibalsan",
260            "mn", "Asia/Hovd",
261            "mo", "Asia/Macau",
262            "mp", "Pacific/Saipan",
263            "mq", "America/Martinique",
264            "mr", "Africa/Nouakchott",
265            "ms", "America/Montserrat",
266            "mt", "Europe/Malta",
267            "mu", "Indian/Mauritius",
268            "mv", "Indian/Maldives",
269            "mw", "Africa/Blantyre",
270            "mx", "America/Mexico_City",
271            "mx", "America/Chihuahua",
272            "mx", "America/Tijuana",
273            "my", "Asia/Kuala_Lumpur",
274            "mz", "Africa/Maputo",
275            "na", "Africa/Windhoek",
276            "nc", "Pacific/Noumea",
277            "ne", "Africa/Niamey",
278            "nf", "Pacific/Norfolk",
279            "ng", "Africa/Lagos",
280            "ni", "America/Managua",
281            "nl", "Europe/Amsterdam",
282            "no", "Europe/Oslo",
283            "np", "Asia/Katmandu",
284            "nr", "Pacific/Nauru",
285            "nu", "Pacific/Niue",
286            "nz", "Pacific/Auckland",
287            "nz", "Pacific/Chatham",
288            "om", "Asia/Muscat",
289            "pa", "America/Panama",
290            "pe", "America/Lima",
291            "pf", "Pacific/Gambier",
292            "pf", "Pacific/Marquesas",
293            "pf", "Pacific/Tahiti",
294            "pg", "Pacific/Port_Moresby",
295            "ph", "Asia/Manila",
296            "pk", "Asia/Karachi",
297            "pl", "Europe/Warsaw",
298            "pm", "America/Miquelon",
299            "pn", "Pacific/Pitcairn",
300            "pr", "America/Puerto_Rico",
301            "ps", "Asia/Gaza",
302            "pt", "Europe/Lisbon",
303            "pt", "Atlantic/Azores",
304            "pw", "Pacific/Palau",
305            "py", "America/Asuncion",
306            "qa", "Asia/Qatar",
307            "re", "Indian/Reunion",
308            "ro", "Europe/Bucharest",
309            "rs", "Europe/Belgrade",
310            "ru", "Asia/Kamchatka",
311            "ru", "Asia/Magadan",
312            "ru", "Asia/Vladivostok",
313            "ru", "Asia/Yakutsk",
314            "ru", "Asia/Irkutsk",
315            "ru", "Asia/Krasnoyarsk",
316            "ru", "Asia/Novosibirsk",
317            "ru", "Asia/Yekaterinburg",
318            "ru", "Europe/Samara",
319            "ru", "Europe/Moscow",
320            "ru", "Europe/Kaliningrad",
321            "rw", "Africa/Kigali",
322            "sa", "Asia/Riyadh",
323            "sb", "Pacific/Guadalcanal",
324            "sc", "Indian/Mahe",
325            "sd", "Africa/Khartoum",
326            "se", "Europe/Stockholm",
327            "sg", "Asia/Singapore",
328            "sh", "Atlantic/St_Helena",
329            "si", "Europe/Ljubljana",
330            "sj", "Arctic/Longyearbyen",
331            "sk", "Europe/Bratislava",
332            "sl", "Africa/Freetown",
333            "sm", "Europe/San_Marino",
334            "sn", "Africa/Dakar",
335            "so", "Africa/Mogadishu",
336            "sr", "America/Paramaribo",
337            "st", "Africa/Sao_Tome",
338            "sv", "America/El_Salvador",
339            "sy", "Asia/Damascus",
340            "sz", "Africa/Mbabane",
341            "tc", "America/Grand_Turk",
342            "td", "Africa/Ndjamena",
343            "tf", "Indian/Kerguelen",
344            "tg", "Africa/Lome",
345            "th", "Asia/Bangkok",
346            "tj", "Asia/Dushanbe",
347            "tk", "Pacific/Fakaofo",
348            "tl", "Asia/Dili",
349            "tm", "Asia/Ashgabat",
350            "tn", "Africa/Tunis",
351            "to", "Pacific/Tongatapu",
352            "tr", "Europe/Istanbul",
353            "tt", "America/Port_of_Spain",
354            "tv", "Pacific/Funafuti",
355            "tw", "Asia/Taipei",
356            "tz", "Africa/Dar_es_Salaam",
357            "ua", "Europe/Kiev",
358            "ug", "Africa/Kampala",
359            "um", "Pacific/Wake",
360            "um", "Pacific/Johnston",
361            "um", "Pacific/Midway",
362            "us", "America/New_York",
363            "us", "America/Chicago",
364            "us", "America/Denver",
365            "us", "America/Los_Angeles",
366            "us", "America/Anchorage",
367            "us", "Pacific/Honolulu",
368            "uy", "America/Montevideo",
369            "uz", "Asia/Tashkent",
370            "va", "Europe/Vatican",
371            "vc", "America/St_Vincent",
372            "ve", "America/Caracas",
373            "vg", "America/Tortola",
374            "vi", "America/St_Thomas",
375            "vn", "Asia/Saigon",
376            "vu", "Pacific/Efate",
377            "wf", "Pacific/Wallis",
378            "ws", "Pacific/Apia",
379            "ye", "Asia/Aden",
380            "yt", "Indian/Mayotte",
381            "za", "Africa/Johannesburg",
382            "zm", "Africa/Lusaka",
383            "zw", "Africa/Harare",
384        };
385
386        for (int i = 0; i < world.length; i += 2) {
387            String country = world[i];
388            String name = world[i + 1];
389
390            TimeZone tz = TimeZone.getTimeZone(name);
391            Calendar c = Calendar.getInstance(tz);
392            TimeZone guess;
393
394            c.set(2009, Calendar.JULY, 20, 12, 00, 00);
395            guess = guess(c, country);
396            assertEquals(name, guess.getID());
397
398            c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
399            guess = guess(c, country);
400            assertEquals(name, guess.getID());
401        }
402    }
403
404    public void testWorldWeird() throws Exception {
405        String[] world = new String[] {
406            // Distinguisable from Sydney only when DST not in effect
407            "au", "Australia/Lord_Howe",
408        };
409
410        for (int i = 0; i < world.length; i += 2) {
411            String country = world[i];
412            String name = world[i + 1];
413
414            TimeZone tz = TimeZone.getTimeZone(name);
415            Calendar c = Calendar.getInstance(tz);
416            TimeZone guess;
417
418            c.set(2009, Calendar.JULY, 20, 12, 00, 00);
419            guess = guess(c, country);
420            assertEquals(name, guess.getID());
421        }
422    }
423
424    private static TimeZone guess(Calendar c, String country) {
425        return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET),
426                                     c.get(c.DST_OFFSET) != 0,
427                                     c.getTimeInMillis(),
428                                     country);
429    }
430
431    public void testFormatDuration() {
432        assertFormatDuration("0", 0);
433        assertFormatDuration("-1ms", -1);
434        assertFormatDuration("+1ms", 1);
435        assertFormatDuration("+10ms", 10);
436        assertFormatDuration("+100ms", 100);
437        assertFormatDuration("+101ms", 101);
438        assertFormatDuration("+330ms", 330);
439        assertFormatDuration("+1s0ms", 1000);
440        assertFormatDuration("+1s330ms", 1330);
441        assertFormatDuration("+10s24ms", 10024);
442        assertFormatDuration("+1m0s30ms", 60030);
443        assertFormatDuration("+1h0m0s30ms", 3600030);
444        assertFormatDuration("+1d0h0m0s30ms", 86400030);
445    }
446
447    public void testFormatHugeDuration() {
448        assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
449        assertFormatDuration("-15542d1h11m11s555ms", -1342833071555L);
450    }
451
452    private void assertFormatDuration(String expected, long duration) {
453        StringBuilder sb = new StringBuilder();
454        TimeUtils.formatDuration(duration, sb);
455        assertEquals("formatDuration(" + duration + ")", expected, sb.toString());
456    }
457}
458