2 *******************************************************************************
\r
3 * Copyright (C) 2007-2009, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.timezone;
\r
9 import java.io.ByteArrayInputStream;
\r
10 import java.io.ByteArrayOutputStream;
\r
11 import java.io.IOException;
\r
12 import java.io.InputStreamReader;
\r
13 import java.io.OutputStreamWriter;
\r
14 import java.io.StringReader;
\r
15 import java.io.StringWriter;
\r
16 import java.util.Date;
\r
18 import com.ibm.icu.dev.test.TestFmwk;
\r
19 import com.ibm.icu.util.AnnualTimeZoneRule;
\r
20 import com.ibm.icu.util.BasicTimeZone;
\r
21 import com.ibm.icu.util.Calendar;
\r
22 import com.ibm.icu.util.DateTimeRule;
\r
23 import com.ibm.icu.util.GregorianCalendar;
\r
24 import com.ibm.icu.util.InitialTimeZoneRule;
\r
25 import com.ibm.icu.util.RuleBasedTimeZone;
\r
26 import com.ibm.icu.util.SimpleTimeZone;
\r
27 import com.ibm.icu.util.TimeArrayTimeZoneRule;
\r
28 import com.ibm.icu.util.TimeZone;
\r
29 import com.ibm.icu.util.TimeZoneRule;
\r
30 import com.ibm.icu.util.TimeZoneTransition;
\r
31 import com.ibm.icu.util.ULocale;
\r
32 import com.ibm.icu.util.VTimeZone;
\r
35 * Test cases for TimeZoneRule and RuleBasedTimeZone
\r
37 public class TimeZoneRuleTest extends TestFmwk {
\r
39 private static final int HOUR = 60 * 60 * 1000;
\r
41 public static void main(String[] args) throws Exception {
\r
42 new TimeZoneRuleTest().run(args);
\r
46 * RuleBasedTimeZone test cases
\r
48 public void TestSimpleRuleBasedTimeZone() {
\r
49 SimpleTimeZone stz = new SimpleTimeZone(-1*HOUR, "TestSTZ",
\r
50 Calendar.SEPTEMBER, -30, -Calendar.SATURDAY, 1*HOUR, SimpleTimeZone.WALL_TIME,
\r
51 Calendar.FEBRUARY, 2, Calendar.SUNDAY, 1*HOUR, SimpleTimeZone.WALL_TIME,
\r
56 AnnualTimeZoneRule atzr;
\r
57 final int STARTYEAR = 2000;
\r
59 InitialTimeZoneRule ir = new InitialTimeZoneRule(
\r
60 "RBTZ_Initial", // Initial time Name
\r
61 -1*HOUR, // Raw offset
\r
62 1*HOUR); // DST saving amount
\r
65 RuleBasedTimeZone rbtz1 = new RuleBasedTimeZone("RBTZ1", ir);
\r
66 dtr = new DateTimeRule(Calendar.SEPTEMBER, 30, Calendar.SATURDAY, false,
\r
67 1*HOUR, DateTimeRule.WALL_TIME); // SUN<=30 in September, at 1AM wall time
\r
68 atzr = new AnnualTimeZoneRule("RBTZ_DST1",
\r
69 -1*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr,
\r
70 STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
71 rbtz1.addTransitionRule(atzr);
\r
72 dtr = new DateTimeRule(Calendar.FEBRUARY, 2, Calendar.SUNDAY,
\r
73 1*HOUR, DateTimeRule.WALL_TIME); // 2nd Sunday in February, at 1AM wall time
\r
74 atzr = new AnnualTimeZoneRule("RBTZ_STD1",
\r
75 -1*HOUR /* rawOffset */, 0 /* dstSavings */, dtr,
\r
76 STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
77 rbtz1.addTransitionRule(atzr);
\r
79 // Equivalent, but different date rule type
\r
80 RuleBasedTimeZone rbtz2 = new RuleBasedTimeZone("RBTZ2", ir);
\r
81 dtr = new DateTimeRule(Calendar.SEPTEMBER, -1, Calendar.SATURDAY,
\r
82 1*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in September at 1AM wall time
\r
83 atzr = new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
84 rbtz2.addTransitionRule(atzr);
\r
85 dtr = new DateTimeRule(Calendar.FEBRUARY, 8, Calendar.SUNDAY, true,
\r
86 1*HOUR, DateTimeRule.WALL_TIME); // SUN>=8 in February, at 1AM wall time
\r
87 atzr = new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
88 rbtz2.addTransitionRule(atzr);
\r
90 // Equivalent, but different time rule type
\r
91 RuleBasedTimeZone rbtz3 = new RuleBasedTimeZone("RBTZ3", ir);
\r
92 dtr = new DateTimeRule(Calendar.SEPTEMBER, 30, Calendar.SATURDAY, false,
\r
93 2*HOUR, DateTimeRule.UTC_TIME);
\r
94 atzr = new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
95 rbtz3.addTransitionRule(atzr);
\r
96 dtr = new DateTimeRule(Calendar.FEBRUARY, 2, Calendar.SUNDAY,
\r
97 0*HOUR, DateTimeRule.STANDARD_TIME);
\r
98 atzr = new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
99 rbtz3.addTransitionRule(atzr);
\r
101 // Check equivalency for 10 years
\r
102 long start = getUTCMillis(STARTYEAR, Calendar.JANUARY, 1);
\r
103 long until = getUTCMillis(STARTYEAR + 10, Calendar.JANUARY, 1);
\r
105 if (!(stz.hasEquivalentTransitions(rbtz1, start, until))) {
\r
106 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range.");
\r
108 if (!(stz.hasEquivalentTransitions(rbtz2, start, until))) {
\r
109 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range.");
\r
111 if (!(stz.hasEquivalentTransitions(rbtz3, start, until))) {
\r
112 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range.");
\r
116 if (rbtz1.hasSameRules(rbtz2)) {
\r
117 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true.");
\r
119 if (rbtz1.hasSameRules(rbtz3)) {
\r
120 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true.");
\r
122 RuleBasedTimeZone rbtz1c = (RuleBasedTimeZone)rbtz1.clone();
\r
123 if (!rbtz1.hasSameRules(rbtz1c)) {
\r
124 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original.");
\r
128 GregorianCalendar cal = new GregorianCalendar();
\r
129 int[] offsets = new int[2];
\r
133 cal.setTimeZone(rbtz1);
\r
137 cal.set(Calendar.ERA, GregorianCalendar.BC);
\r
138 cal.set(1000, Calendar.JANUARY, 1);
\r
140 offset = rbtz1.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
\r
141 cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), cal.get(Calendar.MILLISECONDS_IN_DAY));
\r
143 errln("FAIL: Invalid time zone offset: " + offset + " /expected: 0");
\r
145 dst = rbtz1.inDaylightTime(cal.getTime());
\r
147 errln("FAIL: Invalid daylight saving time");
\r
149 rbtz1.getOffset(cal.getTimeInMillis(), true, offsets);
\r
150 if (offsets[0] != -3600000) {
\r
151 errln("FAIL: Invalid time zone raw offset: " + offsets[0] + " /expected: -3600000");
\r
153 if (offsets[1] != 3600000) {
\r
154 errln("FAIL: Invalid DST amount: " + offsets[1] + " /expected: 3600000");
\r
157 // July 1, 2000, AD
\r
158 cal.set(Calendar.ERA, GregorianCalendar.AD);
\r
159 cal.set(2000, Calendar.JULY, 1);
\r
161 offset = rbtz1.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
\r
162 cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), cal.get(Calendar.MILLISECONDS_IN_DAY));
\r
163 if (offset != -3600000) {
\r
164 errln("FAIL: Invalid time zone offset: " + offset + " /expected: -3600000");
\r
166 dst = rbtz1.inDaylightTime(cal.getTime());
\r
168 errln("FAIL: Invalid daylight saving time");
\r
170 rbtz1.getOffset(cal.getTimeInMillis(), true, offsets);
\r
171 if (offsets[0] != -3600000) {
\r
172 errln("FAIL: Invalid time zone raw offset: " + offsets[0] + " /expected: -3600000");
\r
174 if (offsets[1] != 0) {
\r
175 errln("FAIL: Invalid DST amount: " + offsets[1] + " /expected: 0");
\r
178 // July 1, 2000, AD
\r
180 // Try to add 3rd final rule
\r
181 dtr = new DateTimeRule(Calendar.OCTOBER, 15, 1*HOUR, DateTimeRule.WALL_TIME);
\r
182 atzr = new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR, 2*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR);
\r
183 boolean bException = false;
\r
185 rbtz1.addTransitionRule(atzr);
\r
186 } catch (IllegalStateException ise) {
\r
190 errln("FAIL: 3rd final rule must be rejected");
\r
193 // Try to add an initial rule
\r
194 bException = false;
\r
196 rbtz1.addTransitionRule(new InitialTimeZoneRule("Test Initial", 2*HOUR, 0));
\r
197 } catch (IllegalArgumentException iae) {
\r
201 errln("FAIL: InitialTimeZoneRule must be rejected");
\r
206 * Test equivalency between OlsonTimeZone and custom RBTZ representing the
\r
207 * equivalent rules in a certain time range
\r
209 public void TestHistoricalRuleBasedTimeZone() {
\r
210 // Compare to America/New_York with equivalent RBTZ
\r
211 TimeZone ny = TimeZone.getTimeZone("America/New_York", TimeZone.TIMEZONE_ICU);
\r
214 InitialTimeZoneRule ir = new InitialTimeZoneRule("EST", -5*HOUR, 0);
\r
215 RuleBasedTimeZone rbtz = new RuleBasedTimeZone("EST5EDT", ir);
\r
218 AnnualTimeZoneRule tzr;
\r
221 dtr = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SUNDAY,
\r
222 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in October, at 2AM wall time
\r
223 tzr = new AnnualTimeZoneRule("EST", -5*HOUR /* rawOffset */, 0 /* dstSavings */, dtr, 1967, 2006);
\r
224 rbtz.addTransitionRule(tzr);
\r
226 dtr = new DateTimeRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY,
\r
227 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=1 in November, at 2AM wall time
\r
228 tzr = new AnnualTimeZoneRule("EST", -5*HOUR, 0, dtr, 2007, AnnualTimeZoneRule.MAX_YEAR);
\r
229 rbtz.addTransitionRule(tzr);
\r
231 // Daylight saving time
\r
232 dtr = new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY,
\r
233 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in April, at 2AM wall time
\r
234 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1967, 1973);
\r
235 rbtz.addTransitionRule(tzr);
\r
237 dtr = new DateTimeRule(Calendar.JANUARY, 6,
\r
238 2*HOUR, DateTimeRule.WALL_TIME); // January 6, at 2AM wall time
\r
239 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1974, 1974);
\r
240 rbtz.addTransitionRule(tzr);
\r
242 dtr = new DateTimeRule(Calendar.FEBRUARY, 23,
\r
243 2*HOUR, DateTimeRule.WALL_TIME); // February 23, at 2AM wall time
\r
244 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1975, 1975);
\r
245 rbtz.addTransitionRule(tzr);
\r
247 dtr = new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY,
\r
248 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in April, at 2AM wall time
\r
249 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1976, 1986);
\r
250 rbtz.addTransitionRule(tzr);
\r
252 dtr = new DateTimeRule(Calendar.APRIL, 1, Calendar.SUNDAY,
\r
253 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=1 in April, at 2AM wall time
\r
254 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1987, 2006);
\r
255 rbtz.addTransitionRule(tzr);
\r
257 dtr = new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY,
\r
258 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=8 in March, at 2AM wall time
\r
259 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 2007, AnnualTimeZoneRule.MAX_YEAR);
\r
260 rbtz.addTransitionRule(tzr);
\r
262 // hasEquivalentTransitions
\r
263 long jan1_1950 = getUTCMillis(1950, Calendar.JANUARY, 1);
\r
264 long jan1_1967 = getUTCMillis(1971, Calendar.JANUARY, 1);
\r
265 long jan1_2010 = getUTCMillis(2010, Calendar.JANUARY, 1);
\r
267 if (!(((BasicTimeZone)ny).hasEquivalentTransitions(rbtz, jan1_1967, jan1_2010))) {
\r
268 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
\r
270 if (((BasicTimeZone)ny).hasEquivalentTransitions(rbtz, jan1_1950, jan1_2010)) {
\r
271 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
\r
274 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone
\r
275 if (!rbtz.hasEquivalentTransitions(ny, jan1_1967, jan1_2010)) {
\r
276 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
\r
278 if (rbtz.hasEquivalentTransitions(ny, jan1_1950, jan1_2010)) {
\r
279 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
\r
283 if (ny.hasSameRules(rbtz) || rbtz.hasSameRules(ny)) {
\r
284 errln("FAIL: hasSameRules must return false");
\r
286 RuleBasedTimeZone rbtzc = (RuleBasedTimeZone)rbtz.clone();
\r
287 if (!rbtz.hasSameRules(rbtzc) || !rbtz.hasEquivalentTransitions(rbtzc, jan1_1950, jan1_2010)) {
\r
288 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs");
\r
292 getUTCMillis(2006, Calendar.MARCH, 15),
\r
293 getUTCMillis(2006, Calendar.NOVEMBER, 1),
\r
294 getUTCMillis(2007, Calendar.MARCH, 15),
\r
295 getUTCMillis(2007, Calendar.NOVEMBER, 1),
\r
296 getUTCMillis(2008, Calendar.MARCH, 15),
\r
297 getUTCMillis(2008, Calendar.NOVEMBER, 1)
\r
299 int[] offsets1 = new int[2];
\r
300 int[] offsets2 = new int[2];
\r
302 for (int i = 0; i < times.length; i++) {
\r
303 // Check getOffset - must return the same results for these time data
\r
304 rbtz.getOffset(times[i], false, offsets1);
\r
305 ny.getOffset(times[i], false, offsets2);
\r
306 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
\r
307 errln("FAIL: Incompatible time zone offsets for ny and rbtz");
\r
309 // Check inDaylightTime
\r
310 Date d = new Date(times[i]);
\r
311 if (rbtz.inDaylightTime(d) != ny.inDaylightTime(d)) {
\r
312 errln("FAIL: Incompatible daylight saving time for ny and rbtz");
\r
318 * Check if transitions returned by getNextTransition/getPreviousTransition
\r
319 * are actual time transitions.
\r
321 public void TestOlsonTransition() {
\r
322 String[] zids = getTestZIDs();
\r
323 for (int i = 0; i < zids.length; i++) {
\r
324 TimeZone tz = TimeZone.getTimeZone(zids[i], TimeZone.TIMEZONE_ICU);
\r
330 long[] timerange = getTestTimeRange(j++);
\r
331 if (timerange == null) {
\r
334 verifyTransitions(tz, timerange[0], timerange[1]);
\r
340 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same
\r
343 public void TestRBTZTransition() {
\r
344 int[] STARTYEARS = {
\r
351 String[] zids = getTestZIDs();
\r
352 for (int i = 0; i < zids.length; i++) {
\r
353 TimeZone tz = TimeZone.getTimeZone(zids[i], TimeZone.TIMEZONE_ICU);
\r
357 for (int j = 0; j < STARTYEARS.length; j++) {
\r
358 long startTime = getUTCMillis(STARTYEARS[j], Calendar.JANUARY, 1);
\r
359 TimeZoneRule[] rules = ((BasicTimeZone)tz).getTimeZoneRules(startTime);
\r
360 RuleBasedTimeZone rbtz = new RuleBasedTimeZone(tz.getID() + "(RBTZ)",
\r
361 (InitialTimeZoneRule)rules[0]);
\r
362 for (int k = 1; k < rules.length; k++) {
\r
363 rbtz.addTransitionRule(rules[k]);
\r
366 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years
\r
367 long until = getUTCMillis(STARTYEARS[j] + 20, Calendar.JANUARY, 1);
\r
370 compareTransitionsAscending(tz, rbtz, startTime, until, false);
\r
371 // Ascending/inclusive
\r
372 compareTransitionsAscending(tz, rbtz, startTime + 1, until, true);
\r
374 compareTransitionsDescending(tz, rbtz, startTime, until, false);
\r
375 // Descending/inclusive
\r
376 compareTransitionsDescending(tz, rbtz, startTime + 1, until, true);
\r
383 * Test cases for HasTimeZoneRules#hasEquivalentTransitions
\r
385 public void TestHasEquivalentTransitions() {
\r
386 // America/New_York and America/Indiana/Indianapolis are equivalent
\r
388 TimeZone newyork = TimeZone.getTimeZone("America/New_York", TimeZone.TIMEZONE_ICU);
\r
389 TimeZone indianapolis = TimeZone.getTimeZone("America/Indiana/Indianapolis", TimeZone.TIMEZONE_ICU);
\r
390 TimeZone gmt_5 = TimeZone.getTimeZone("Etc/GMT+5", TimeZone.TIMEZONE_ICU);
\r
392 long jan1_1971 = getUTCMillis(1971, Calendar.JANUARY, 1);
\r
393 long jan1_2005 = getUTCMillis(2005, Calendar.JANUARY, 1);
\r
394 long jan1_2006 = getUTCMillis(2006, Calendar.JANUARY, 1);
\r
395 long jan1_2007 = getUTCMillis(2007, Calendar.JANUARY, 1);
\r
396 long jan1_2011 = getUTCMillis(2010, Calendar.JANUARY, 1);
\r
398 if (((BasicTimeZone)newyork).hasEquivalentTransitions(indianapolis, jan1_2005, jan1_2011)) {
\r
399 errln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010, but returned true");
\r
401 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(indianapolis, jan1_2006, jan1_2011)) {
\r
402 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010, but returned false");
\r
405 if (!((BasicTimeZone)indianapolis).hasEquivalentTransitions(gmt_5, jan1_1971, jan1_2006)) {
\r
406 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005, but returned false");
\r
408 if (((BasicTimeZone)indianapolis).hasEquivalentTransitions(gmt_5, jan1_1971, jan1_2007)) {
\r
409 errln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006, but returned true");
\r
413 TimeZone newyork2 = (TimeZone)newyork.clone();
\r
414 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(newyork2, jan1_1971, jan1_2011)) {
\r
415 errln("FAIL: Cloned TimeZone must have the same transitions");
\r
417 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(newyork2, jan1_1971, jan1_2011, true /*ignoreDstAmount*/)) {
\r
418 errln("FAIL: Cloned TimeZone must have the same transitions");
\r
421 // America/New_York and America/Los_Angeles has same DST start rules, but
\r
422 // raw offsets are different
\r
423 TimeZone losangeles = TimeZone.getTimeZone("America/Los_Angeles", TimeZone.TIMEZONE_ICU);
\r
424 if (((BasicTimeZone)newyork).hasEquivalentTransitions(losangeles, jan1_2006, jan1_2011)) {
\r
425 errln("FAIL: New_York is not equivalent to Los Angeles, but returned true");
\r
430 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new
\r
431 * VTimeZone from the VTIMEZONE data, then compare transitions
\r
433 public void TestVTimeZoneRoundTrip() {
\r
434 long startTime = getUTCMillis(1850, Calendar.JANUARY, 1);
\r
435 long endTime = getUTCMillis(2050, Calendar.JANUARY, 1);
\r
437 String[] tzids = getTestZIDs();
\r
438 for (int i = 0; i < tzids.length; i++) {
\r
439 if (skipIfBeforeICU(4, 3, 1) && tzids[i].equals("Asia/Amman")) {
\r
443 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
444 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
445 vtz_org.setTZURL("http://source.icu-project.org/timezone");
\r
446 vtz_org.setLastModified(new Date());
\r
447 VTimeZone vtz_new = null;
\r
449 // Write out VTIMEZONE
\r
450 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
451 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
452 vtz_org.write(writer);
\r
454 byte[] vtzdata = baos.toByteArray();
\r
456 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
457 InputStreamReader reader = new InputStreamReader(bais);
\r
458 vtz_new = VTimeZone.create(reader);
\r
461 // Write out VTIMEZONE one more time
\r
462 ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
\r
463 OutputStreamWriter writer1 = new OutputStreamWriter(baos1);
\r
464 vtz_new.write(writer1);
\r
466 byte[] vtzdata1 = baos1.toByteArray();
\r
468 // Make sure VTIMEZONE data is exactly same with the first one
\r
469 if (vtzdata.length != vtzdata1.length) {
\r
470 errln("FAIL: different VTIMEZONE data length");
\r
472 for (int j = 0; j < vtzdata.length; j++) {
\r
473 if (vtzdata[j] != vtzdata1[j]) {
\r
474 errln("FAIL: different VTIMEZONE data");
\r
478 } catch (IOException ioe) {
\r
479 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
481 // Check equivalency after the first transition.
\r
482 // The DST information before the first transition might be lost
\r
483 // because there is no good way to represent the initial time with
\r
485 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) {
\r
486 errln("FAIL: VTimeZone for " + tzids[i]
\r
487 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime);
\r
489 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
\r
491 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
\r
492 errln("FAIL: VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding.");
\r
494 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, false)) {
\r
495 logln("VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding in strict comparison mode.");
\r
502 * Write out time zone rules of OlsonTimeZone after a cutoff date into VTIMEZONE format,
\r
503 * create a new VTimeZone from the VTIMEZONE data, then compare transitions
\r
505 public void TestVTimeZoneRoundTripPartial() {
\r
506 long[] startTimes = new long[] {
\r
507 getUTCMillis(1900, Calendar.JANUARY, 1),
\r
508 getUTCMillis(1950, Calendar.JANUARY, 1),
\r
509 getUTCMillis(2020, Calendar.JANUARY, 1)
\r
511 long endTime = getUTCMillis(2050, Calendar.JANUARY, 1);
\r
513 String[] tzids = getTestZIDs();
\r
514 for (int n = 0; n < startTimes.length; n++) {
\r
515 long startTime = startTimes[n];
\r
516 for (int i = 0; i < tzids.length; i++) {
\r
517 if (skipIfBeforeICU(4, 3, 1) && tzids[i].equals("Asia/Amman")) {
\r
521 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
522 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
523 VTimeZone vtz_new = null;
\r
525 // Write out VTIMEZONE
\r
526 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
527 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
528 vtz_org.write(writer, startTime);
\r
530 byte[] vtzdata = baos.toByteArray();
\r
532 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
533 InputStreamReader reader = new InputStreamReader(bais);
\r
534 vtz_new = VTimeZone.create(reader);
\r
537 } catch (IOException ioe) {
\r
538 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
540 // Check equivalency after the first transition.
\r
541 // The DST information before the first transition might be lost
\r
542 // because there is no good way to represent the initial time with
\r
544 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) {
\r
545 errln("FAIL: VTimeZone for " + tzids[i]
\r
546 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime);
\r
548 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
\r
550 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
\r
551 errln("FAIL: VTimeZone for " + tzids[i] + "(>=" + startTime + ") is not equivalent to its OlsonTimeZone corresponding.");
\r
559 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
\r
560 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
\r
561 * and DST savings are same in these two time zones.
\r
563 public void TestVTimeZoneSimpleWrite() {
\r
564 long[] testTimes = new long[] {
\r
565 getUTCMillis(2006, Calendar.JANUARY, 1),
\r
566 getUTCMillis(2006, Calendar.MARCH, 15),
\r
567 getUTCMillis(2006, Calendar.MARCH, 31),
\r
568 getUTCMillis(2006, Calendar.APRIL, 5),
\r
569 getUTCMillis(2006, Calendar.OCTOBER, 25),
\r
570 getUTCMillis(2006, Calendar.NOVEMBER, 1),
\r
571 getUTCMillis(2006, Calendar.NOVEMBER, 5),
\r
572 getUTCMillis(2007, Calendar.JANUARY, 1)
\r
575 String[] tzids = getTestZIDs();
\r
576 for (int n = 0; n < testTimes.length; n++) {
\r
577 long time = testTimes[n];
\r
579 int[] offsets1 = new int[2];
\r
580 int[] offsets2 = new int[2];
\r
582 for (int i = 0; i < tzids.length; i++) {
\r
583 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
584 VTimeZone vtz_new = null;
\r
586 // Write out VTIMEZONE
\r
587 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
588 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
589 vtz_org.writeSimple(writer, time);
\r
591 byte[] vtzdata = baos.toByteArray();
\r
593 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
594 InputStreamReader reader = new InputStreamReader(bais);
\r
595 vtz_new = VTimeZone.create(reader);
\r
597 } catch (IOException ioe) {
\r
598 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
601 // Check equivalency
\r
602 vtz_org.getOffset(time, false, offsets1);
\r
603 vtz_new.getOffset(time, false, offsets2);
\r
604 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
\r
605 errln("FAIL: VTimeZone writeSimple for " + tzids[i] + " at time " + time + " failed to the round trip.");
\r
612 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
\r
613 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
\r
615 public void TestVTimeZoneHeaderProps() {
\r
616 String tzid = "America/Chicago";
\r
617 String tzurl = "http://source.icu-project.org";
\r
618 Date lastmod = new Date(getUTCMillis(2007, Calendar.JUNE, 1));
\r
620 VTimeZone vtz = VTimeZone.create(tzid);
\r
621 vtz.setTZURL(tzurl);
\r
622 vtz.setLastModified(lastmod);
\r
624 // Roundtrip conversion
\r
625 VTimeZone newvtz1 = null;
\r
627 // Write out VTIMEZONE
\r
628 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
629 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
632 byte[] vtzdata = baos.toByteArray();
\r
634 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
635 InputStreamReader reader = new InputStreamReader(bais);
\r
636 newvtz1 = VTimeZone.create(reader);
\r
639 // Check if TZURL and LAST-MODIFIED headers are preserved
\r
640 if (!(tzurl.equals(newvtz1.getTZURL()))) {
\r
641 errln("FAIL: TZURL property is not preserved during the roundtrip conversion. Before:"
\r
642 + tzurl + "/After:" + newvtz1.getTZURL());
\r
644 if (!(lastmod.equals(newvtz1.getLastModified()))) {
\r
645 errln("FAIL: LAST-MODIFIED property is not preserved during the roundtrip conversion. Before:"
\r
646 + lastmod.getTime() + "/After:" + newvtz1.getLastModified().getTime());
\r
648 } catch (IOException ioe) {
\r
649 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
652 // Second roundtrip, with a cutoff
\r
653 VTimeZone newvtz2 = null;
\r
655 // Set different tzurl
\r
656 String newtzurl = "http://www.ibm.com";
\r
657 newvtz1.setTZURL(newtzurl);
\r
658 // Write out VTIMEZONE
\r
659 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
660 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
661 newvtz1.write(writer, getUTCMillis(2000, Calendar.JANUARY, 1));
\r
663 byte[] vtzdata = baos.toByteArray();
\r
665 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
666 InputStreamReader reader = new InputStreamReader(bais);
\r
667 newvtz2 = VTimeZone.create(reader);
\r
670 // Check if TZURL and LAST-MODIFIED headers are preserved
\r
671 if (!(newtzurl.equals(newvtz2.getTZURL()))) {
\r
672 errln("FAIL: TZURL property is not preserved during the second roundtrip conversion. Before:"
\r
673 + newtzurl + "/After:" + newvtz2.getTZURL());
\r
675 if (!(lastmod.equals(newvtz2.getLastModified()))) {
\r
676 errln("FAIL: LAST-MODIFIED property is not preserved during the second roundtrip conversion. Before:"
\r
677 + lastmod.getTime() + "/After:" + newvtz2.getLastModified().getTime());
\r
679 } catch (IOException ioe) {
\r
680 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
686 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
\r
687 * the expected format.
\r
689 public void TestGetSimpleRules() {
\r
690 long[] testTimes = new long[] {
\r
691 getUTCMillis(1970, Calendar.JANUARY, 1),
\r
692 getUTCMillis(2000, Calendar.MARCH, 31),
\r
693 getUTCMillis(2005, Calendar.JULY, 1),
\r
694 getUTCMillis(2010, Calendar.NOVEMBER, 1),
\r
697 String[] tzids = getTestZIDs();
\r
698 for (int n = 0; n < testTimes.length; n++) {
\r
699 long time = testTimes[n];
\r
700 for (int i = 0; i < tzids.length; i++) {
\r
701 BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
702 TimeZoneRule[] rules = tz.getSimpleTimeZoneRulesNear(time);
\r
703 if (rules == null) {
\r
704 errln("FAIL: Failed to extract simple rules for " + tzids[i] + " at " + time);
\r
706 if (rules.length == 1) {
\r
707 if (!(rules[0] instanceof InitialTimeZoneRule)) {
\r
708 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time);
\r
710 } else if (rules.length == 3) {
\r
711 if (!(rules[0] instanceof InitialTimeZoneRule)
\r
712 || !(rules[1] instanceof AnnualTimeZoneRule)
\r
713 || !(rules[2] instanceof AnnualTimeZoneRule)) {
\r
714 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time);
\r
716 for (int idx = 1; idx <= 2; idx++) {
\r
717 DateTimeRule dtr = ((AnnualTimeZoneRule)rules[idx]).getRule();
\r
718 if (dtr.getTimeRuleType() != DateTimeRule.WALL_TIME) {
\r
719 errln("FAIL: WALL_TIME is not used as the time rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time);
\r
721 if (dtr.getDateRuleType() != DateTimeRule.DOW) {
\r
722 errln("FAIL: DOW is not used as the date rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time);
\r
726 errln("FAIL: Unexpected number of rules returned for " + tzids[i] + " at " + time);
\r
734 * API coverage tests for TimeZoneRule
\r
736 public void TestTimeZoneRuleCoverage() {
\r
737 long time1 = getUTCMillis(2005, Calendar.JULY, 4);
\r
738 long time2 = getUTCMillis(2015, Calendar.JULY, 4);
\r
739 long time3 = getUTCMillis(1950, Calendar.JULY, 4);
\r
741 DateTimeRule dtr1 = new DateTimeRule(Calendar.FEBRUARY, 29, Calendar.SUNDAY, false,
\r
742 3*HOUR, DateTimeRule.WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time
\r
743 DateTimeRule dtr2 = new DateTimeRule(Calendar.MARCH, 11, 2*HOUR,
\r
744 DateTimeRule.STANDARD_TIME); // Mar 11, at 2 AM, standard time
\r
745 DateTimeRule dtr3 = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SATURDAY,
\r
746 6*HOUR, DateTimeRule.UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC
\r
747 DateTimeRule dtr4 = new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY, true,
\r
748 2*HOUR, DateTimeRule.WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time
\r
750 AnnualTimeZoneRule a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, dtr1,
\r
751 2000, AnnualTimeZoneRule.MAX_YEAR);
\r
752 AnnualTimeZoneRule a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, dtr1,
\r
753 2000, AnnualTimeZoneRule.MAX_YEAR);
\r
754 AnnualTimeZoneRule a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, dtr1,
\r
757 InitialTimeZoneRule i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0);
\r
758 InitialTimeZoneRule i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0);
\r
759 InitialTimeZoneRule i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR);
\r
761 long[] emptytimes = {};
\r
762 long[] trtimes1 = {0};
\r
763 long[] trtimes2 = {0, 10000000};
\r
765 TimeArrayTimeZoneRule t0 = null;
\r
767 // Try to construct TimeArrayTimeZoneRule with null transition times
\r
768 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0,
\r
769 null, DateTimeRule.UTC_TIME);
\r
770 } catch (IllegalArgumentException iae) {
\r
771 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected.");
\r
775 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for null times");
\r
779 // Try to construct TimeArrayTimeZoneRule with empty transition times
\r
780 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0,
\r
781 emptytimes, DateTimeRule.UTC_TIME);
\r
782 } catch (IllegalArgumentException iae) {
\r
783 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected.");
\r
787 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for empty times");
\r
790 TimeArrayTimeZoneRule t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME);
\r
791 TimeArrayTimeZoneRule t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME);
\r
792 TimeArrayTimeZoneRule t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, DateTimeRule.UTC_TIME);
\r
793 TimeArrayTimeZoneRule t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, DateTimeRule.STANDARD_TIME);
\r
794 TimeArrayTimeZoneRule t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, DateTimeRule.WALL_TIME);
\r
796 // AnnualTimeZoneRule#getRule
\r
797 if (!a1.getRule().equals(a2.getRule())) {
\r
798 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
\r
801 // AnnualTimeZoneRule#getStartYear
\r
802 int startYear = a1.getStartYear();
\r
803 if (startYear != 2000) {
\r
804 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear);
\r
807 // AnnualTimeZoneRule#getEndYear
\r
808 int endYear = a1.getEndYear();
\r
809 if (endYear != AnnualTimeZoneRule.MAX_YEAR) {
\r
810 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear);
\r
812 endYear = a3.getEndYear();
\r
813 if (endYear != 2010) {
\r
814 errln("FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear);
\r
817 // AnnualTimeZone#getStartInYear
\r
818 Date d1 = a1.getStartInYear(2005, -3*HOUR, 0);
\r
819 Date d2 = a3.getStartInYear(2005, -3*HOUR, 0);
\r
820 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
821 errln("FAIL: AnnualTimeZoneRule#getStartInYear did not work as expected");
\r
823 d2 = a3.getStartInYear(2015, -3*HOUR, 0);
\r
825 errln("FAIL: AnnualTimeZoneRule#getSTartInYear returned non-null date for 2015 which is out of rule range");
\r
828 // AnnualTimeZone#getFirstStart
\r
829 d1 = a1.getFirstStart(-3*HOUR, 0);
\r
830 d2 = a1.getFirstStart(-4*HOUR, 1*HOUR);
\r
831 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
832 errln("FAIL: The same start time should be returned by getFirstStart");
\r
835 // AnnualTimeZone#getFinalStart
\r
836 d1 = a1.getFinalStart(-3*HOUR, 0);
\r
838 errln("FAIL: Non-null Date is returned by getFinalStart for a1");
\r
840 d1 = a1.getStartInYear(2010, -3*HOUR, 0);
\r
841 d2 = a3.getFinalStart(-3*HOUR, 0);
\r
842 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
843 errln("FAIL: Bad date is returned by getFinalStart");
\r
846 // AnnualTimeZone#getNextStart / getPreviousStart
\r
847 d1 = a1.getNextStart(time1, -3*HOUR, 0, false);
\r
849 errln("FAIL: Null Date is returned by getNextStart");
\r
851 d2 = a1.getPreviousStart(d1.getTime(), -3*HOUR, 0, true);
\r
852 if (d2 == null || !d1.equals(d2)) {
\r
853 errln("FAIL: Bad Date is returned by getPreviousStart");
\r
856 d1 = a3.getNextStart(time2, -3*HOUR, 0, false);
\r
858 errln("FAIL: getNextStart must return null when no start time is available after the base time");
\r
860 d1 = a3.getFinalStart(-3*HOUR, 0);
\r
861 d2 = a3.getPreviousStart(time2, -3*HOUR, 0, false);
\r
862 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
863 errln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
\r
866 // AnnualTimeZone#isEquavalentTo
\r
867 if (!a1.isEquivalentTo(a2)) {
\r
868 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned false");
\r
870 if (a1.isEquivalentTo(a3)) {
\r
871 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned true");
\r
873 if (!a1.isEquivalentTo(a1)) {
\r
874 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned false");
\r
876 if (a1.isEquivalentTo(t1)) {
\r
877 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned true");
\r
880 // AnnualTimeZone#isTransitionRule
\r
881 if (!a1.isTransitionRule()) {
\r
882 errln("FAIL: An AnnualTimeZoneRule is a transition rule, but returned false");
\r
885 // AnnualTimeZone#toString
\r
886 String str = a1.toString();
\r
887 if (str == null || str.length() == 0) {
\r
888 errln("FAIL: AnnualTimeZoneRule#toString for a1 returns null or empty string");
\r
890 logln("AnnualTimeZoneRule a1 : " + str);
\r
892 str = a3.toString();
\r
893 if (str == null || str.length() == 0) {
\r
894 errln("FAIL: AnnualTimeZoneRule#toString for a3 returns null or empty string");
\r
896 logln("AnnualTimeZoneRule a3 : " + str);
\r
899 // InitialTimeZoneRule#isEquivalentRule
\r
900 if (!i1.isEquivalentTo(i2)) {
\r
901 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned false");
\r
903 if (i1.isEquivalentTo(i3)) {
\r
904 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned true");
\r
906 if (i1.isEquivalentTo(a1)) {
\r
907 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned true");
\r
910 // InitialTimeZoneRule#getFirstStart/getFinalStart/getNextStart/getPreviousStart
\r
911 d1 = i1.getFirstStart(0, 0);
\r
913 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFirstStart");
\r
915 d1 = i1.getFinalStart(0, 0);
\r
917 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFinalStart");
\r
919 d1 = i1.getNextStart(time1, 0, 0, false);
\r
921 errln("FAIL: Non-null Date is returned by InitialTimeZone#getNextStart");
\r
923 d1 = i1.getPreviousStart(time1, 0, 0, false);
\r
925 errln("FAIL: Non-null Date is returned by InitialTimeZone#getPreviousStart");
\r
928 // InitialTimeZoneRule#isTransitionRule
\r
929 if (i1.isTransitionRule()) {
\r
930 errln("FAIL: An InitialTimeZoneRule is not a transition rule, but returned true");
\r
933 // InitialTimeZoneRule#toString
\r
934 str = i1.toString();
\r
935 if (str == null || str.length() == 0) {
\r
936 errln("FAIL: InitialTimeZoneRule#toString returns null or empty string");
\r
938 logln("InitialTimeZoneRule i1 : " + str);
\r
942 // TimeArrayTimeZoneRule#getStartTimes
\r
943 long[] times = t1.getStartTimes();
\r
944 if (times == null || times.length == 0 || times[0] != 0) {
\r
945 errln("FAIL: Bad start times are returned by TimeArrayTimeZoneRule#getStartTimes");
\r
948 // TimeArrayTimeZoneRule#getTimeType
\r
949 if (t1.getTimeType() != DateTimeRule.UTC_TIME) {
\r
950 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
\r
952 if (t4.getTimeType() != DateTimeRule.STANDARD_TIME) {
\r
953 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
\r
955 if (t5.getTimeType() != DateTimeRule.WALL_TIME) {
\r
956 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
\r
959 // TimeArrayTimeZoneRule#getFirstStart/getFinalStart
\r
960 d1 = t1.getFirstStart(0, 0);
\r
961 if (d1 == null || d1.getTime() != trtimes1[0]) {
\r
962 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
\r
964 d1 = t1.getFinalStart(0, 0);
\r
965 if (d1 == null || d1.getTime() != trtimes1[0]) {
\r
966 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
\r
968 d1 = t4.getFirstStart(-4*HOUR, 1*HOUR);
\r
969 if (d1 == null || (d1.getTime() != trtimes1[0] + 4*HOUR)) {
\r
970 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
\r
972 d1 = t5.getFirstStart(-4*HOUR, 1*HOUR);
\r
973 if (d1 == null || (d1.getTime() != trtimes1[0] + 3*HOUR)) {
\r
974 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
\r
977 // TimeArrayTimeZoneRule#getNextStart/getPreviousStart
\r
978 d1 = t3.getNextStart(time1, -3*HOUR, 1*HOUR, false);
\r
980 errln("FAIL: Non-null Date is returned by getNextStart after the final transition for t3");
\r
982 d1 = t3.getPreviousStart(time1, -3*HOUR, 1*HOUR, false);
\r
983 if (d1 == null || d1.getTime() != trtimes2[1]) {
\r
984 errln("FAIL: Bad start time returned by getPreviousStart for t3");
\r
986 d2 = t3.getPreviousStart(d1.getTime(), -3*HOUR, 1*HOUR, false);
\r
987 if (d2 == null || d2.getTime() != trtimes2[0]) {
\r
988 errln("FAIL: Bad start time returned by getPreviousStart for t3");
\r
991 d1 = t3.getPreviousStart(time3, -3*HOUR, 1*HOUR, false); //time3 - year 1950, no result expected
\r
993 errln("FAIL: Non-null Date is returned by getPrevoousStart for t3");
\r
996 // TimeArrayTimeZoneRule#isEquivalentTo
\r
997 if (!t1.isEquivalentTo(t2)) {
\r
998 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned false");
\r
1000 if (t1.isEquivalentTo(t3)) {
\r
1001 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned true");
\r
1003 if (t1.isEquivalentTo(t4)) {
\r
1004 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned true");
\r
1006 if (t1.isEquivalentTo(a1)) {
\r
1007 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned true");
\r
1010 // TimeArrayTimeZoneRule#isTransitionRule
\r
1011 if (!t1.isTransitionRule()) {
\r
1012 errln("FAIL: A TimeArrayTimeZoneRule is a transition rule, but returned false");
\r
1015 // TimeArrayTimeZoneRule#toString
\r
1016 str = t3.toString();
\r
1017 if (str == null || str.length() == 0) {
\r
1018 errln("FAIL: TimeArrayTimeZoneRule#toString returns null or empty string");
\r
1020 logln("TimeArrayTimeZoneRule t3 : " + str);
\r
1023 // DateTimeRule#toString
\r
1024 str = dtr1.toString();
\r
1025 if (str == null || str.length() == 0) {
\r
1026 errln("FAIL: DateTimeRule#toString for dtr1 returns null or empty string");
\r
1028 logln("DateTimeRule dtr1 : " + str);
\r
1030 str = dtr2.toString();
\r
1031 if (str == null || str.length() == 0) {
\r
1032 errln("FAIL: DateTimeRule#toString for dtr2 returns null or empty string");
\r
1034 logln("DateTimeRule dtr1 : " + str);
\r
1036 str = dtr3.toString();
\r
1037 if (str == null || str.length() == 0) {
\r
1038 errln("FAIL: DateTimeRule#toString for dtr3 returns null or empty string");
\r
1040 logln("DateTimeRule dtr1 : " + str);
\r
1042 str = dtr4.toString();
\r
1043 if (str == null || str.length() == 0) {
\r
1044 errln("FAIL: DateTimeRule#toString for dtr4 returns null or empty string");
\r
1046 logln("DateTimeRule dtr1 : " + str);
\r
1051 * API coverage test for BasicTimeZone APIs in SimpleTimeZone
\r
1053 public void TestSimpleTimeZoneCoverage() {
\r
1055 long time1 = getUTCMillis(1990, Calendar.JUNE, 1);
\r
1056 long time2 = getUTCMillis(2000, Calendar.JUNE, 1);
\r
1058 TimeZoneTransition tzt1, tzt2;
\r
1060 // BasicTimeZone API implementation in SimpleTimeZone
\r
1061 SimpleTimeZone stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5");
\r
1063 tzt1 = stz1.getNextTransition(time1, false);
\r
1064 if (tzt1 != null) {
\r
1065 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
\r
1067 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1068 if (tzt1 != null) {
\r
1069 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
\r
1071 TimeZoneRule[] tzrules = stz1.getTimeZoneRules();
\r
1072 if (tzrules.length != 1 || !(tzrules[0] instanceof InitialTimeZoneRule)) {
\r
1073 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules");
\r
1077 stz1.setStartRule(Calendar.MARCH, 11, 2*HOUR); // March 11
\r
1078 stz1.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*HOUR); // First Sunday in November
\r
1079 tzt1 = stz1.getNextTransition(time1, false);
\r
1080 if (tzt1 == null) {
\r
1081 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
\r
1083 String str = tzt1.toString();
\r
1084 if (str == null || str.length() == 0) {
\r
1085 errln("FAIL: TimeZoneTransition#toString returns null or empty string");
\r
1090 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1091 if (tzt1 == null) {
\r
1092 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
\r
1094 tzrules = stz1.getTimeZoneRules();
\r
1095 if (tzrules.length != 3 || !(tzrules[0] instanceof InitialTimeZoneRule)
\r
1096 || !(tzrules[1] instanceof AnnualTimeZoneRule)
\r
1097 || !(tzrules[2] instanceof AnnualTimeZoneRule)) {
\r
1098 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules for a SimpleTimeZone with DST");
\r
1100 // Set DST start year
\r
1101 stz1.setStartYear(2007);
\r
1102 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1103 if (tzt1 != null) {
\r
1104 errln("FAIL: No transition must be returned before 1990");
\r
1106 tzt1 = stz1.getNextTransition(time1, false); // transition after 1990-06-01
\r
1107 tzt2 = stz1.getNextTransition(time2, false); // transition after 2000-06-01
\r
1108 if (tzt1 == null || tzt2 == null || !tzt1.equals(tzt2)) {
\r
1109 errln("FAIL: Bad transition returned by SimpleTimeZone#getNextTransition");
\r
1114 * API coverage test for VTimeZone
\r
1116 public void TestVTimeZoneCoverage() {
\r
1117 final String TZID = "Europe/Moscow";
\r
1118 BasicTimeZone otz = (BasicTimeZone)TimeZone.getTimeZone(TZID, TimeZone.TIMEZONE_ICU);
\r
1119 VTimeZone vtz = VTimeZone.create(TZID);
\r
1121 // getOffset(era, year, month, day, dayOfWeek, milliseconds)
\r
1122 int offset1 = otz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1123 int offset2 = vtz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1124 if (offset1 != offset2) {
\r
1125 errln("FAIL: getOffset(int,int,int,int,int,int) returned different results in VTimeZone and OlsonTimeZone");
\r
1128 // getOffset(date, local, offsets)
\r
1129 int[] offsets1 = new int[2];
\r
1130 int[] offsets2 = new int[2];
\r
1131 long t = System.currentTimeMillis();
\r
1132 otz.getOffset(t, false, offsets1);
\r
1133 vtz.getOffset(t, false, offsets2);
\r
1134 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
\r
1135 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
\r
1139 if (otz.getRawOffset() != vtz.getRawOffset()) {
\r
1140 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
\r
1144 Date d = new Date();
\r
1145 if (otz.inDaylightTime(d) != vtz.inDaylightTime(d)) {
\r
1146 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
\r
1149 // useDaylightTime
\r
1150 if (otz.useDaylightTime() != vtz.useDaylightTime()) {
\r
1151 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
\r
1155 final int RAW = -10*HOUR;
\r
1156 VTimeZone tmpvtz = (VTimeZone)vtz.clone();
\r
1157 tmpvtz.setRawOffset(RAW);
\r
1158 if (tmpvtz.getRawOffset() != RAW) {
\r
1159 logln("setRawOffset is implemented");
\r
1163 boolean bSame = otz.hasSameRules(vtz);
\r
1164 logln("OlsonTimeZone#hasSameRules(VTimeZone) should return false always for now - actual: " + bSame);
\r
1166 // getTZURL/setTZURL
\r
1167 final String TZURL = "http://icu-project.org/timezone";
\r
1168 String tzurl = vtz.getTZURL();
\r
1169 if (tzurl != null) {
\r
1170 errln("FAIL: getTZURL returned non-null value");
\r
1172 vtz.setTZURL(TZURL);
\r
1173 tzurl = vtz.getTZURL();
\r
1174 if (!TZURL.equals(tzurl)) {
\r
1175 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
\r
1178 // getLastModified/setLastModified
\r
1179 Date lastmod = vtz.getLastModified();
\r
1180 if (lastmod != null) {
\r
1181 errln("FAIL: getLastModified returned non-null value");
\r
1183 Date newdate = new Date();
\r
1184 vtz.setLastModified(newdate);
\r
1185 lastmod = vtz.getLastModified();
\r
1186 if (!newdate.equals(lastmod)) {
\r
1187 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
\r
1190 // getNextTransition/getPreviousTransition
\r
1191 long base = getUTCMillis(2007, Calendar.JULY, 1);
\r
1192 TimeZoneTransition tzt1 = otz.getNextTransition(base, true);
\r
1193 TimeZoneTransition tzt2 = vtz.getNextTransition(base, true);
\r
1194 if (tzt1.equals(tzt2)) {
\r
1195 errln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
\r
1197 tzt1 = otz.getPreviousTransition(base, false);
\r
1198 tzt2 = vtz.getPreviousTransition(base, false);
\r
1199 if (tzt1.equals(tzt2)) {
\r
1200 errln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
\r
1203 // hasEquivalentTransitions
\r
1204 long time1 = getUTCMillis(1950, Calendar.JANUARY, 1);
\r
1205 long time2 = getUTCMillis(2020, Calendar.JANUARY, 1);
\r
1206 if (!vtz.hasEquivalentTransitions(otz, time1, time2)) {
\r
1207 errln("FAIL: hasEquivalentTransitons returned false for the same time zone");
\r
1210 // getTimeZoneRules
\r
1211 TimeZoneRule[] rulesetAll = vtz.getTimeZoneRules();
\r
1212 TimeZoneRule[] ruleset1 = vtz.getTimeZoneRules(time1);
\r
1213 TimeZoneRule[] ruleset2 = vtz.getTimeZoneRules(time2);
\r
1214 if (rulesetAll.length < ruleset1.length || ruleset1.length < ruleset2.length) {
\r
1215 errln("FAIL: Number of rules returned by getRules is invalid");
\r
1219 public void TestVTimeZoneParse() {
\r
1220 // Trying to create VTimeZone from empty data
\r
1221 StringReader r = new StringReader("");
\r
1222 VTimeZone empty = VTimeZone.create(r);
\r
1223 if (empty != null) {
\r
1224 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
\r
1227 // Create VTimeZone for Asia/Tokyo
\r
1228 String asiaTokyo =
\r
1229 "BEGIN:VTIMEZONE\r\n" +
\r
1232 "BEGIN:STANDARD\r\n" +
\r
1233 "TZOFFSETFROM:+0900\r\n" +
\r
1234 "TZOFFSETTO:+0900\r\n" +
\r
1235 "TZNAME:JST\r\n" +
\r
1236 "DTSTART:19700101\r\n" +
\r
1238 "END:STANDARD\r\n" +
\r
1240 r = new StringReader(asiaTokyo);
\r
1241 VTimeZone tokyo = VTimeZone.create(r);
\r
1242 if (tokyo == null) {
\r
1243 errln("FAIL: Failed to create a VTimeZone tokyo");
\r
1245 // Make sure offsets are correct
\r
1246 int[] offsets = new int[2];
\r
1247 tokyo.getOffset(System.currentTimeMillis(), false, offsets);
\r
1248 if (offsets[0] != 9*HOUR || offsets[1] != 0) {
\r
1249 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
\r
1253 // Create VTimeZone from VTIMEZONE data
\r
1255 "BEGIN:VCALENDAR\r\n" +
\r
1256 "BEGIN:VTIMEZONE\r\n" +
\r
1258 "BEGIN:STANDARD\r\n" +
\r
1259 "TZOFFSETFROM:-0700\r\n" +
\r
1260 "TZOFFSETTO:-0800\r\n" +
\r
1261 "TZNAME:FST\r\n" +
\r
1262 "DTSTART:20071010T010000\r\n" +
\r
1263 "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\r\n" +
\r
1264 "END:STANDARD\r\n" +
\r
1265 "BEGIN:DAYLIGHT\r\n" +
\r
1266 "TZOFFSETFROM:-0800\r\n" +
\r
1267 "TZOFFSETTO:-0700\r\n" +
\r
1268 "TZNAME:FDT\r\n" +
\r
1269 "DTSTART:20070415T010000\r\n" +
\r
1270 "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\r\n" +
\r
1271 "END:DAYLIGHT\r\n" +
\r
1272 "END:VTIMEZONE\r\n" +
\r
1275 r = new StringReader(fooData);
\r
1276 VTimeZone foo = VTimeZone.create(r);
\r
1277 if (foo == null) {
\r
1278 errln("FAIL: Failed to create a VTimeZone foo");
\r
1280 // Write VTIMEZONE data
\r
1281 StringWriter w = new StringWriter();
\r
1283 foo.write(w, getUTCMillis(2005, Calendar.JANUARY, 1));
\r
1284 } catch (IOException ioe) {
\r
1285 errln("FAIL: IOException is thrown while writing VTIMEZONE data for foo");
\r
1287 logln(w.toString());
\r
1291 public void TestT6216() {
\r
1292 // Test case in #6216
\r
1294 "BEGIN:VCALENDAR\r\n" +
\r
1295 "VERSION:2.0\r\n" +
\r
1296 "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" +
\r
1297 "BEGIN:VTIMEZONE\r\n" +
\r
1298 "TZID:Asia/Tokyo\r\n" +
\r
1299 "BEGIN:STANDARD\r\n" +
\r
1300 "DTSTART:20000101T000000\r\n" +
\r
1301 "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" +
\r
1302 "TZNAME:Asia/Tokyo\r\n" +
\r
1303 "TZOFFSETFROM:+0900\r\n" +
\r
1304 "TZOFFSETTO:+0900\r\n" +
\r
1305 "END:STANDARD\r\n" +
\r
1306 "END:VTIMEZONE\r\n" +
\r
1309 // Single final rule, overlapping with another
\r
1310 String finalOverlap =
\r
1311 "BEGIN:VCALENDAR\r\n" +
\r
1312 "BEGIN:VTIMEZONE\r\n" +
\r
1313 "TZID:FinalOverlap\r\n" +
\r
1314 "BEGIN:STANDARD\r\n" +
\r
1315 "TZOFFSETFROM:-0200\r\n" +
\r
1316 "TZOFFSETTO:-0300\r\n" +
\r
1317 "TZNAME:STD\r\n" +
\r
1318 "DTSTART:20001029T020000\r\n" +
\r
1319 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" +
\r
1320 "END:STANDARD\r\n" +
\r
1321 "BEGIN:DAYLIGHT\r\n" +
\r
1322 "TZOFFSETFROM:-0300\r\n" +
\r
1323 "TZOFFSETTO:-0200\r\n" +
\r
1324 "TZNAME:DST\r\n" +
\r
1325 "DTSTART:19990404T020000\r\n" +
\r
1326 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" +
\r
1327 "END:DAYLIGHT\r\n" +
\r
1328 "END:VTIMEZONE\r\n" +
\r
1331 // Single final rule, no overlapping with another
\r
1332 String finalNonOverlap =
\r
1333 "BEGIN:VCALENDAR\r\n" +
\r
1334 "BEGIN:VTIMEZONE\r\n" +
\r
1335 "TZID:FinalNonOverlap\r\n" +
\r
1336 "BEGIN:STANDARD\r\n" +
\r
1337 "TZOFFSETFROM:-0200\r\n" +
\r
1338 "TZOFFSETTO:-0300\r\n" +
\r
1339 "TZNAME:STD\r\n" +
\r
1340 "DTSTART:20001029T020000\r\n" +
\r
1341 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" +
\r
1342 "END:STANDARD\r\n" +
\r
1343 "BEGIN:DAYLIGHT\r\n" +
\r
1344 "TZOFFSETFROM:-0300\r\n" +
\r
1345 "TZOFFSETTO:-0200\r\n" +
\r
1346 "TZNAME:DST\r\n" +
\r
1347 "DTSTART:19990404T020000\r\n" +
\r
1348 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" +
\r
1349 "END:DAYLIGHT\r\n" +
\r
1350 "BEGIN:STANDARD\r\n" +
\r
1351 "TZOFFSETFROM:-0200\r\n" +
\r
1352 "TZOFFSETTO:-0300\r\n" +
\r
1353 "TZNAME:STDFINAL\r\n" +
\r
1354 "DTSTART:20071028T020000\r\n" +
\r
1355 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" +
\r
1356 "END:STANDARD\r\n" +
\r
1357 "END:VTIMEZONE\r\n" +
\r
1360 int[][] TestDates = {
\r
1361 {1995, Calendar.JANUARY, 1},
\r
1362 {1995, Calendar.JULY, 1},
\r
1363 {2000, Calendar.JANUARY, 1},
\r
1364 {2000, Calendar.JULY, 1},
\r
1365 {2005, Calendar.JANUARY, 1},
\r
1366 {2005, Calendar.JULY, 1},
\r
1367 {2010, Calendar.JANUARY, 1},
\r
1368 {2010, Calendar.JULY, 1},
\r
1371 String[] TestZones = {
\r
1377 int[][] Expected = {
\r
1378 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10
\r
1379 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000},
\r
1380 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
\r
1381 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
\r
1385 long[] times = new long[TestDates.length];
\r
1386 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
\r
1387 for (int i = 0; i < TestDates.length; i++) {
\r
1389 cal.set(TestDates[i][0], TestDates[i][1], TestDates[i][2]);
\r
1390 times[i] = cal.getTimeInMillis();
\r
1393 for (int i = 0; i < TestZones.length; i++) {
\r
1395 VTimeZone vtz = VTimeZone.create(new StringReader(TestZones[i]));
\r
1396 for (int j = 0; j < times.length; j++) {
\r
1397 int offset = vtz.getOffset(times[j]);
\r
1398 if (offset != Expected[i][j]) {
\r
1399 errln("FAIL: Invalid offset at time(" + times[j] + "):" + offset + " Expected:" + Expected[i][j]);
\r
1402 } catch (Exception e) {
\r
1403 errln("FAIL: Failed to calculate the offset for VTIMEZONE data " + i);
\r
1408 public void TestT6669() {
\r
1409 // getNext/PreviousTransition implementation in SimpleTimeZone
\r
1410 // used to use a bad condition for detecting if DST is enabled or not.
\r
1412 SimpleTimeZone stz = new SimpleTimeZone(0, "CustomID",
\r
1413 Calendar.JANUARY, 1, Calendar.SUNDAY, 0,
\r
1414 Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1416 long t = 1230681600000L; //2008-12-31T00:00:00
\r
1417 long expectedNext = 1231027200000L; //2009-01-04T00:00:00
\r
1418 long expectedPrev = 1215298800000L; //2008-07-06T00:00:00
\r
1420 TimeZoneTransition tzt = stz.getNextTransition(t, false);
\r
1421 if (tzt == null) {
\r
1422 errln("FAIL: No transition returned by getNextTransition.");
\r
1423 } else if (tzt.getTime() != expectedNext){
\r
1424 errln("FAIL: Wrong transition time returned by getNextTransition - "
\r
1425 + tzt.getTime() + " Expected: " + expectedNext);
\r
1428 tzt = stz.getPreviousTransition(t, true);
\r
1429 if (tzt == null) {
\r
1430 errln("FAIL: No transition returned by getPreviousTransition.");
\r
1431 } else if (tzt.getTime() != expectedPrev){
\r
1432 errln("FAIL: Wrong transition time returned by getPreviousTransition - "
\r
1433 + tzt.getTime() + " Expected: " + expectedPrev);
\r
1437 // Internal utility methods -----------------------------------------
\r
1440 * Check if a time shift really happens on each transition returned by getNextTransition or
\r
1441 * getPreviousTransition in the specified time range
\r
1443 private void verifyTransitions(TimeZone tz, long start, long end) {
\r
1444 BasicTimeZone icutz = (BasicTimeZone)tz;
\r
1446 int[] before = new int[2];
\r
1447 int[] after = new int[2];
\r
1448 TimeZoneTransition tzt0;
\r
1454 TimeZoneTransition tzt = icutz.getNextTransition(time, false);
\r
1456 if (tzt == null) {
\r
1459 time = tzt.getTime();
\r
1460 if (time >= end) {
\r
1463 icutz.getOffset(time, false, after);
\r
1464 icutz.getOffset(time - 1, false, before);
\r
1466 if (after[0] == before[0] && after[1] == before[1]) {
\r
1467 errln("FAIL: False transition returned by getNextTransition for " + icutz.getID() + " at " + time);
\r
1469 if (tzt0 != null &&
\r
1470 (tzt0.getTo().getRawOffset() != tzt.getFrom().getRawOffset()
\r
1471 || tzt0.getTo().getDSTSavings() != tzt.getFrom().getDSTSavings())) {
\r
1472 errln("FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
\r
1473 + time + " for " + icutz.getID());
\r
1482 TimeZoneTransition tzt = icutz.getPreviousTransition(time, false);
\r
1483 if (tzt == null) {
\r
1486 time = tzt.getTime();
\r
1487 if (time <= start) {
\r
1490 icutz.getOffset(time, false, after);
\r
1491 icutz.getOffset(time - 1, false, before);
\r
1493 if (after[0] == before[0] && after[1] == before[1]) {
\r
1494 errln("FAIL: False transition returned by getPreviousTransition for " + icutz.getID() + " at " + time);
\r
1497 if (tzt0 != null &&
\r
1498 (tzt0.getFrom().getRawOffset() != tzt.getTo().getRawOffset()
\r
1499 || tzt0.getFrom().getDSTSavings() != tzt.getTo().getDSTSavings())) {
\r
1500 errln("FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
\r
1501 + time + " for " + icutz.getID());
\r
1508 * Compare all time transitions in 2 time zones in the specified time range in ascending order
\r
1510 private void compareTransitionsAscending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) {
\r
1511 BasicTimeZone z1 = (BasicTimeZone)tz1;
\r
1512 BasicTimeZone z2 = (BasicTimeZone)tz2;
\r
1513 String zid1 = tz1.getID();
\r
1514 String zid2 = tz2.getID();
\r
1516 long time = start;
\r
1518 TimeZoneTransition tzt1 = z1.getNextTransition(time, inclusive);
\r
1519 TimeZoneTransition tzt2 = z2.getNextTransition(time, inclusive);
\r
1520 boolean inRange1 = false;
\r
1521 boolean inRange2 = false;
\r
1522 if (tzt1 != null) {
\r
1523 if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) {
\r
1527 if (tzt2 != null) {
\r
1528 if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) {
\r
1532 if (!inRange1 && !inRange2) {
\r
1533 // No more transition in the range
\r
1537 errln("FAIL: " + zid1 + " does not have any transitions after " + time + " before " + end);
\r
1541 errln("FAIL: " + zid2 + " does not have any transitions after " + time + " before " + end);
\r
1544 if (tzt1.getTime() != tzt2.getTime()) {
\r
1545 errln("FAIL: First transition after " + time + " "
\r
1546 + zid1 + "[" + tzt1.getTime() + "] "
\r
1547 + zid2 + "[" + tzt2.getTime() + "]");
\r
1550 time = tzt1.getTime();
\r
1558 * Compare all time transitions in 2 time zones in the specified time range in descending order
\r
1560 private void compareTransitionsDescending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) {
\r
1561 BasicTimeZone z1 = (BasicTimeZone)tz1;
\r
1562 BasicTimeZone z2 = (BasicTimeZone)tz2;
\r
1563 String zid1 = tz1.getID();
\r
1564 String zid2 = tz2.getID();
\r
1567 TimeZoneTransition tzt1 = z1.getPreviousTransition(time, inclusive);
\r
1568 TimeZoneTransition tzt2 = z2.getPreviousTransition(time, inclusive);
\r
1569 boolean inRange1 = false;
\r
1570 boolean inRange2 = false;
\r
1571 if (tzt1 != null) {
\r
1572 if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) {
\r
1576 if (tzt2 != null) {
\r
1577 if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) {
\r
1581 if (!inRange1 && !inRange2) {
\r
1582 // No more transition in the range
\r
1586 errln("FAIL: " + zid1 + " does not have any transitions before " + time + " after " + start);
\r
1590 errln("FAIL: " + zid2 + " does not have any transitions before " + time + " after " + start);
\r
1593 if (tzt1.getTime() != tzt2.getTime()) {
\r
1594 errln("FAIL: Last transition before " + time + " "
\r
1595 + zid1 + "[" + tzt1.getTime() + "] "
\r
1596 + zid2 + "[" + tzt2.getTime() + "]");
\r
1599 time = tzt1.getTime();
\r
1606 private static final String[] TESTZIDS = {
\r
1608 "America/New_York",
\r
1609 "America/Los_Angeles",
\r
1610 "America/Indiana/Indianapolis",
\r
1617 "Africa/Windhoek",
\r
1618 "Australia/Sydney",
\r
1622 private String[] getTestZIDs() {
\r
1623 if (getInclusion() > 5) {
\r
1624 return TimeZone.getAvailableIDs();
\r
1629 private static final int[][] TESTYEARS = {
\r
1630 {1895, 1905}, // including int32 minimum second
\r
1631 {1965, 1975}, // including the epoch
\r
1632 {1995, 2015} // practical year range
\r
1635 private long[] getTestTimeRange(int idx) {
\r
1636 int loyear, hiyear;
\r
1637 if (idx < TESTYEARS.length) {
\r
1638 loyear = TESTYEARS[idx][0];
\r
1639 hiyear = TESTYEARS[idx][1];
\r
1640 } else if (idx == TESTYEARS.length && getInclusion() > 5) {
\r
1647 long[] times = new long[2];
\r
1648 times[0] = getUTCMillis(loyear, Calendar.JANUARY, 1);
\r
1649 times[1] = getUTCMillis(hiyear + 1, Calendar.JANUARY, 1);
\r
1654 private GregorianCalendar utcCal;
\r
1656 private long getUTCMillis(int year, int month, int dayOfMonth) {
\r
1657 if (utcCal == null) {
\r
1658 utcCal = new GregorianCalendar(TimeZone.getTimeZone("UTC"), ULocale.ROOT);
\r
1661 utcCal.set(year, month, dayOfMonth);
\r
1662 return utcCal.getTimeInMillis();
\r