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,5,0) && tzids[i].equals("Asia/Amman")) { // ticket#7008
\r
442 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
443 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
444 vtz_org.setTZURL("http://source.icu-project.org/timezone");
\r
445 vtz_org.setLastModified(new Date());
\r
446 VTimeZone vtz_new = null;
\r
448 // Write out VTIMEZONE
\r
449 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
450 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
451 vtz_org.write(writer);
\r
453 byte[] vtzdata = baos.toByteArray();
\r
455 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
456 InputStreamReader reader = new InputStreamReader(bais);
\r
457 vtz_new = VTimeZone.create(reader);
\r
460 // Write out VTIMEZONE one more time
\r
461 ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
\r
462 OutputStreamWriter writer1 = new OutputStreamWriter(baos1);
\r
463 vtz_new.write(writer1);
\r
465 byte[] vtzdata1 = baos1.toByteArray();
\r
467 // Make sure VTIMEZONE data is exactly same with the first one
\r
468 if (vtzdata.length != vtzdata1.length) {
\r
469 errln("FAIL: different VTIMEZONE data length");
\r
471 for (int j = 0; j < vtzdata.length; j++) {
\r
472 if (vtzdata[j] != vtzdata1[j]) {
\r
473 errln("FAIL: different VTIMEZONE data");
\r
477 } catch (IOException ioe) {
\r
478 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
480 // Check equivalency after the first transition.
\r
481 // The DST information before the first transition might be lost
\r
482 // because there is no good way to represent the initial time with
\r
484 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) {
\r
485 errln("FAIL: VTimeZone for " + tzids[i]
\r
486 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime);
\r
488 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
\r
490 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
\r
491 errln("FAIL: VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding.");
\r
493 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, false)) {
\r
494 logln("VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding in strict comparison mode.");
\r
501 * Write out time zone rules of OlsonTimeZone after a cutoff date into VTIMEZONE format,
\r
502 * create a new VTimeZone from the VTIMEZONE data, then compare transitions
\r
504 public void TestVTimeZoneRoundTripPartial() {
\r
505 long[] startTimes = new long[] {
\r
506 getUTCMillis(1900, Calendar.JANUARY, 1),
\r
507 getUTCMillis(1950, Calendar.JANUARY, 1),
\r
508 getUTCMillis(2020, Calendar.JANUARY, 1)
\r
510 long endTime = getUTCMillis(2050, Calendar.JANUARY, 1);
\r
512 String[] tzids = getTestZIDs();
\r
513 for (int n = 0; n < startTimes.length; n++) {
\r
514 long startTime = startTimes[n];
\r
515 for (int i = 0; i < tzids.length; i++) {
\r
516 if (skipIfBeforeICU(4,5,0) && tzids[i].equals("Asia/Amman")) { // ticket#7008
\r
519 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
520 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
521 VTimeZone vtz_new = null;
\r
523 // Write out VTIMEZONE
\r
524 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
525 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
526 vtz_org.write(writer, startTime);
\r
528 byte[] vtzdata = baos.toByteArray();
\r
530 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
531 InputStreamReader reader = new InputStreamReader(bais);
\r
532 vtz_new = VTimeZone.create(reader);
\r
535 } catch (IOException ioe) {
\r
536 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
538 // Check equivalency after the first transition.
\r
539 // The DST information before the first transition might be lost
\r
540 // because there is no good way to represent the initial time with
\r
542 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) {
\r
543 errln("FAIL: VTimeZone for " + tzids[i]
\r
544 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime);
\r
546 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false);
\r
548 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) {
\r
549 errln("FAIL: VTimeZone for " + tzids[i] + "(>=" + startTime + ") is not equivalent to its OlsonTimeZone corresponding.");
\r
557 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
\r
558 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
\r
559 * and DST savings are same in these two time zones.
\r
561 public void TestVTimeZoneSimpleWrite() {
\r
562 long[] testTimes = new long[] {
\r
563 getUTCMillis(2006, Calendar.JANUARY, 1),
\r
564 getUTCMillis(2006, Calendar.MARCH, 15),
\r
565 getUTCMillis(2006, Calendar.MARCH, 31),
\r
566 getUTCMillis(2006, Calendar.APRIL, 5),
\r
567 getUTCMillis(2006, Calendar.OCTOBER, 25),
\r
568 getUTCMillis(2006, Calendar.NOVEMBER, 1),
\r
569 getUTCMillis(2006, Calendar.NOVEMBER, 5),
\r
570 getUTCMillis(2007, Calendar.JANUARY, 1)
\r
573 String[] tzids = getTestZIDs();
\r
574 for (int n = 0; n < testTimes.length; n++) {
\r
575 long time = testTimes[n];
\r
577 int[] offsets1 = new int[2];
\r
578 int[] offsets2 = new int[2];
\r
580 for (int i = 0; i < tzids.length; i++) {
\r
581 VTimeZone vtz_org = VTimeZone.create(tzids[i]);
\r
582 VTimeZone vtz_new = null;
\r
584 // Write out VTIMEZONE
\r
585 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
586 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
587 vtz_org.writeSimple(writer, time);
\r
589 byte[] vtzdata = baos.toByteArray();
\r
591 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
592 InputStreamReader reader = new InputStreamReader(bais);
\r
593 vtz_new = VTimeZone.create(reader);
\r
595 } catch (IOException ioe) {
\r
596 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
599 // Check equivalency
\r
600 vtz_org.getOffset(time, false, offsets1);
\r
601 vtz_new.getOffset(time, false, offsets2);
\r
602 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
\r
603 errln("FAIL: VTimeZone writeSimple for " + tzids[i] + " at time " + time + " failed to the round trip.");
\r
610 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
\r
611 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
\r
613 public void TestVTimeZoneHeaderProps() {
\r
614 String tzid = "America/Chicago";
\r
615 String tzurl = "http://source.icu-project.org";
\r
616 Date lastmod = new Date(getUTCMillis(2007, Calendar.JUNE, 1));
\r
618 VTimeZone vtz = VTimeZone.create(tzid);
\r
619 vtz.setTZURL(tzurl);
\r
620 vtz.setLastModified(lastmod);
\r
622 // Roundtrip conversion
\r
623 VTimeZone newvtz1 = null;
\r
625 // Write out VTIMEZONE
\r
626 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
627 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
630 byte[] vtzdata = baos.toByteArray();
\r
632 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
633 InputStreamReader reader = new InputStreamReader(bais);
\r
634 newvtz1 = VTimeZone.create(reader);
\r
637 // Check if TZURL and LAST-MODIFIED headers are preserved
\r
638 if (!(tzurl.equals(newvtz1.getTZURL()))) {
\r
639 errln("FAIL: TZURL property is not preserved during the roundtrip conversion. Before:"
\r
640 + tzurl + "/After:" + newvtz1.getTZURL());
\r
642 if (!(lastmod.equals(newvtz1.getLastModified()))) {
\r
643 errln("FAIL: LAST-MODIFIED property is not preserved during the roundtrip conversion. Before:"
\r
644 + lastmod.getTime() + "/After:" + newvtz1.getLastModified().getTime());
\r
646 } catch (IOException ioe) {
\r
647 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
650 // Second roundtrip, with a cutoff
\r
651 VTimeZone newvtz2 = null;
\r
653 // Set different tzurl
\r
654 String newtzurl = "http://www.ibm.com";
\r
655 newvtz1.setTZURL(newtzurl);
\r
656 // Write out VTIMEZONE
\r
657 ByteArrayOutputStream baos = new ByteArrayOutputStream();
\r
658 OutputStreamWriter writer = new OutputStreamWriter(baos);
\r
659 newvtz1.write(writer, getUTCMillis(2000, Calendar.JANUARY, 1));
\r
661 byte[] vtzdata = baos.toByteArray();
\r
663 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata);
\r
664 InputStreamReader reader = new InputStreamReader(bais);
\r
665 newvtz2 = VTimeZone.create(reader);
\r
668 // Check if TZURL and LAST-MODIFIED headers are preserved
\r
669 if (!(newtzurl.equals(newvtz2.getTZURL()))) {
\r
670 errln("FAIL: TZURL property is not preserved during the second roundtrip conversion. Before:"
\r
671 + newtzurl + "/After:" + newvtz2.getTZURL());
\r
673 if (!(lastmod.equals(newvtz2.getLastModified()))) {
\r
674 errln("FAIL: LAST-MODIFIED property is not preserved during the second roundtrip conversion. Before:"
\r
675 + lastmod.getTime() + "/After:" + newvtz2.getLastModified().getTime());
\r
677 } catch (IOException ioe) {
\r
678 errln("FAIL: IO error while writing/reading VTIMEZONE data");
\r
684 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
\r
685 * the expected format.
\r
687 public void TestGetSimpleRules() {
\r
688 long[] testTimes = new long[] {
\r
689 getUTCMillis(1970, Calendar.JANUARY, 1),
\r
690 getUTCMillis(2000, Calendar.MARCH, 31),
\r
691 getUTCMillis(2005, Calendar.JULY, 1),
\r
692 getUTCMillis(2010, Calendar.NOVEMBER, 1),
\r
695 String[] tzids = getTestZIDs();
\r
696 for (int n = 0; n < testTimes.length; n++) {
\r
697 long time = testTimes[n];
\r
698 for (int i = 0; i < tzids.length; i++) {
\r
699 BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU);
\r
700 TimeZoneRule[] rules = tz.getSimpleTimeZoneRulesNear(time);
\r
701 if (rules == null) {
\r
702 errln("FAIL: Failed to extract simple rules for " + tzids[i] + " at " + time);
\r
704 if (rules.length == 1) {
\r
705 if (!(rules[0] instanceof InitialTimeZoneRule)) {
\r
706 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time);
\r
708 } else if (rules.length == 3) {
\r
709 if (!(rules[0] instanceof InitialTimeZoneRule)
\r
710 || !(rules[1] instanceof AnnualTimeZoneRule)
\r
711 || !(rules[2] instanceof AnnualTimeZoneRule)) {
\r
712 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time);
\r
714 for (int idx = 1; idx <= 2; idx++) {
\r
715 DateTimeRule dtr = ((AnnualTimeZoneRule)rules[idx]).getRule();
\r
716 if (dtr.getTimeRuleType() != DateTimeRule.WALL_TIME) {
\r
717 errln("FAIL: WALL_TIME is not used as the time rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time);
\r
719 if (dtr.getDateRuleType() != DateTimeRule.DOW) {
\r
720 errln("FAIL: DOW is not used as the date rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time);
\r
724 errln("FAIL: Unexpected number of rules returned for " + tzids[i] + " at " + time);
\r
732 * API coverage tests for TimeZoneRule
\r
734 public void TestTimeZoneRuleCoverage() {
\r
735 long time1 = getUTCMillis(2005, Calendar.JULY, 4);
\r
736 long time2 = getUTCMillis(2015, Calendar.JULY, 4);
\r
737 long time3 = getUTCMillis(1950, Calendar.JULY, 4);
\r
739 DateTimeRule dtr1 = new DateTimeRule(Calendar.FEBRUARY, 29, Calendar.SUNDAY, false,
\r
740 3*HOUR, DateTimeRule.WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time
\r
741 DateTimeRule dtr2 = new DateTimeRule(Calendar.MARCH, 11, 2*HOUR,
\r
742 DateTimeRule.STANDARD_TIME); // Mar 11, at 2 AM, standard time
\r
743 DateTimeRule dtr3 = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SATURDAY,
\r
744 6*HOUR, DateTimeRule.UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC
\r
745 DateTimeRule dtr4 = new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY, true,
\r
746 2*HOUR, DateTimeRule.WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time
\r
748 AnnualTimeZoneRule a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, dtr1,
\r
749 2000, AnnualTimeZoneRule.MAX_YEAR);
\r
750 AnnualTimeZoneRule a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, dtr1,
\r
751 2000, AnnualTimeZoneRule.MAX_YEAR);
\r
752 AnnualTimeZoneRule a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, dtr1,
\r
755 InitialTimeZoneRule i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0);
\r
756 InitialTimeZoneRule i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0);
\r
757 InitialTimeZoneRule i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR);
\r
759 long[] emptytimes = {};
\r
760 long[] trtimes1 = {0};
\r
761 long[] trtimes2 = {0, 10000000};
\r
763 TimeArrayTimeZoneRule t0 = null;
\r
765 // Try to construct TimeArrayTimeZoneRule with null transition times
\r
766 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0,
\r
767 null, DateTimeRule.UTC_TIME);
\r
768 } catch (IllegalArgumentException iae) {
\r
769 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected.");
\r
773 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for null times");
\r
777 // Try to construct TimeArrayTimeZoneRule with empty transition times
\r
778 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0,
\r
779 emptytimes, DateTimeRule.UTC_TIME);
\r
780 } catch (IllegalArgumentException iae) {
\r
781 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected.");
\r
785 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for empty times");
\r
788 TimeArrayTimeZoneRule t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME);
\r
789 TimeArrayTimeZoneRule t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME);
\r
790 TimeArrayTimeZoneRule t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, DateTimeRule.UTC_TIME);
\r
791 TimeArrayTimeZoneRule t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, DateTimeRule.STANDARD_TIME);
\r
792 TimeArrayTimeZoneRule t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, DateTimeRule.WALL_TIME);
\r
794 // AnnualTimeZoneRule#getRule
\r
795 if (!a1.getRule().equals(a2.getRule())) {
\r
796 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
\r
799 // AnnualTimeZoneRule#getStartYear
\r
800 int startYear = a1.getStartYear();
\r
801 if (startYear != 2000) {
\r
802 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear);
\r
805 // AnnualTimeZoneRule#getEndYear
\r
806 int endYear = a1.getEndYear();
\r
807 if (endYear != AnnualTimeZoneRule.MAX_YEAR) {
\r
808 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear);
\r
810 endYear = a3.getEndYear();
\r
811 if (endYear != 2010) {
\r
812 errln("FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear);
\r
815 // AnnualTimeZone#getStartInYear
\r
816 Date d1 = a1.getStartInYear(2005, -3*HOUR, 0);
\r
817 Date d2 = a3.getStartInYear(2005, -3*HOUR, 0);
\r
818 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
819 errln("FAIL: AnnualTimeZoneRule#getStartInYear did not work as expected");
\r
821 d2 = a3.getStartInYear(2015, -3*HOUR, 0);
\r
823 errln("FAIL: AnnualTimeZoneRule#getSTartInYear returned non-null date for 2015 which is out of rule range");
\r
826 // AnnualTimeZone#getFirstStart
\r
827 d1 = a1.getFirstStart(-3*HOUR, 0);
\r
828 d2 = a1.getFirstStart(-4*HOUR, 1*HOUR);
\r
829 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
830 errln("FAIL: The same start time should be returned by getFirstStart");
\r
833 // AnnualTimeZone#getFinalStart
\r
834 d1 = a1.getFinalStart(-3*HOUR, 0);
\r
836 errln("FAIL: Non-null Date is returned by getFinalStart for a1");
\r
838 d1 = a1.getStartInYear(2010, -3*HOUR, 0);
\r
839 d2 = a3.getFinalStart(-3*HOUR, 0);
\r
840 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
841 errln("FAIL: Bad date is returned by getFinalStart");
\r
844 // AnnualTimeZone#getNextStart / getPreviousStart
\r
845 d1 = a1.getNextStart(time1, -3*HOUR, 0, false);
\r
847 errln("FAIL: Null Date is returned by getNextStart");
\r
849 d2 = a1.getPreviousStart(d1.getTime(), -3*HOUR, 0, true);
\r
850 if (d2 == null || !d1.equals(d2)) {
\r
851 errln("FAIL: Bad Date is returned by getPreviousStart");
\r
854 d1 = a3.getNextStart(time2, -3*HOUR, 0, false);
\r
856 errln("FAIL: getNextStart must return null when no start time is available after the base time");
\r
858 d1 = a3.getFinalStart(-3*HOUR, 0);
\r
859 d2 = a3.getPreviousStart(time2, -3*HOUR, 0, false);
\r
860 if (d1 == null || d2 == null || !d1.equals(d2)) {
\r
861 errln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
\r
864 // AnnualTimeZone#isEquavalentTo
\r
865 if (!a1.isEquivalentTo(a2)) {
\r
866 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned false");
\r
868 if (a1.isEquivalentTo(a3)) {
\r
869 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned true");
\r
871 if (!a1.isEquivalentTo(a1)) {
\r
872 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned false");
\r
874 if (a1.isEquivalentTo(t1)) {
\r
875 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned true");
\r
878 // AnnualTimeZone#isTransitionRule
\r
879 if (!a1.isTransitionRule()) {
\r
880 errln("FAIL: An AnnualTimeZoneRule is a transition rule, but returned false");
\r
883 // AnnualTimeZone#toString
\r
884 String str = a1.toString();
\r
885 if (str == null || str.length() == 0) {
\r
886 errln("FAIL: AnnualTimeZoneRule#toString for a1 returns null or empty string");
\r
888 logln("AnnualTimeZoneRule a1 : " + str);
\r
890 str = a3.toString();
\r
891 if (str == null || str.length() == 0) {
\r
892 errln("FAIL: AnnualTimeZoneRule#toString for a3 returns null or empty string");
\r
894 logln("AnnualTimeZoneRule a3 : " + str);
\r
897 // InitialTimeZoneRule#isEquivalentRule
\r
898 if (!i1.isEquivalentTo(i2)) {
\r
899 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned false");
\r
901 if (i1.isEquivalentTo(i3)) {
\r
902 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned true");
\r
904 if (i1.isEquivalentTo(a1)) {
\r
905 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned true");
\r
908 // InitialTimeZoneRule#getFirstStart/getFinalStart/getNextStart/getPreviousStart
\r
909 d1 = i1.getFirstStart(0, 0);
\r
911 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFirstStart");
\r
913 d1 = i1.getFinalStart(0, 0);
\r
915 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFinalStart");
\r
917 d1 = i1.getNextStart(time1, 0, 0, false);
\r
919 errln("FAIL: Non-null Date is returned by InitialTimeZone#getNextStart");
\r
921 d1 = i1.getPreviousStart(time1, 0, 0, false);
\r
923 errln("FAIL: Non-null Date is returned by InitialTimeZone#getPreviousStart");
\r
926 // InitialTimeZoneRule#isTransitionRule
\r
927 if (i1.isTransitionRule()) {
\r
928 errln("FAIL: An InitialTimeZoneRule is not a transition rule, but returned true");
\r
931 // InitialTimeZoneRule#toString
\r
932 str = i1.toString();
\r
933 if (str == null || str.length() == 0) {
\r
934 errln("FAIL: InitialTimeZoneRule#toString returns null or empty string");
\r
936 logln("InitialTimeZoneRule i1 : " + str);
\r
940 // TimeArrayTimeZoneRule#getStartTimes
\r
941 long[] times = t1.getStartTimes();
\r
942 if (times == null || times.length == 0 || times[0] != 0) {
\r
943 errln("FAIL: Bad start times are returned by TimeArrayTimeZoneRule#getStartTimes");
\r
946 // TimeArrayTimeZoneRule#getTimeType
\r
947 if (t1.getTimeType() != DateTimeRule.UTC_TIME) {
\r
948 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
\r
950 if (t4.getTimeType() != DateTimeRule.STANDARD_TIME) {
\r
951 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
\r
953 if (t5.getTimeType() != DateTimeRule.WALL_TIME) {
\r
954 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
\r
957 // TimeArrayTimeZoneRule#getFirstStart/getFinalStart
\r
958 d1 = t1.getFirstStart(0, 0);
\r
959 if (d1 == null || d1.getTime() != trtimes1[0]) {
\r
960 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
\r
962 d1 = t1.getFinalStart(0, 0);
\r
963 if (d1 == null || d1.getTime() != trtimes1[0]) {
\r
964 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
\r
966 d1 = t4.getFirstStart(-4*HOUR, 1*HOUR);
\r
967 if (d1 == null || (d1.getTime() != trtimes1[0] + 4*HOUR)) {
\r
968 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
\r
970 d1 = t5.getFirstStart(-4*HOUR, 1*HOUR);
\r
971 if (d1 == null || (d1.getTime() != trtimes1[0] + 3*HOUR)) {
\r
972 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
\r
975 // TimeArrayTimeZoneRule#getNextStart/getPreviousStart
\r
976 d1 = t3.getNextStart(time1, -3*HOUR, 1*HOUR, false);
\r
978 errln("FAIL: Non-null Date is returned by getNextStart after the final transition for t3");
\r
980 d1 = t3.getPreviousStart(time1, -3*HOUR, 1*HOUR, false);
\r
981 if (d1 == null || d1.getTime() != trtimes2[1]) {
\r
982 errln("FAIL: Bad start time returned by getPreviousStart for t3");
\r
984 d2 = t3.getPreviousStart(d1.getTime(), -3*HOUR, 1*HOUR, false);
\r
985 if (d2 == null || d2.getTime() != trtimes2[0]) {
\r
986 errln("FAIL: Bad start time returned by getPreviousStart for t3");
\r
989 d1 = t3.getPreviousStart(time3, -3*HOUR, 1*HOUR, false); //time3 - year 1950, no result expected
\r
991 errln("FAIL: Non-null Date is returned by getPrevoousStart for t3");
\r
994 // TimeArrayTimeZoneRule#isEquivalentTo
\r
995 if (!t1.isEquivalentTo(t2)) {
\r
996 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned false");
\r
998 if (t1.isEquivalentTo(t3)) {
\r
999 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned true");
\r
1001 if (t1.isEquivalentTo(t4)) {
\r
1002 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned true");
\r
1004 if (t1.isEquivalentTo(a1)) {
\r
1005 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned true");
\r
1008 // TimeArrayTimeZoneRule#isTransitionRule
\r
1009 if (!t1.isTransitionRule()) {
\r
1010 errln("FAIL: A TimeArrayTimeZoneRule is a transition rule, but returned false");
\r
1013 // TimeArrayTimeZoneRule#toString
\r
1014 str = t3.toString();
\r
1015 if (str == null || str.length() == 0) {
\r
1016 errln("FAIL: TimeArrayTimeZoneRule#toString returns null or empty string");
\r
1018 logln("TimeArrayTimeZoneRule t3 : " + str);
\r
1021 // DateTimeRule#toString
\r
1022 str = dtr1.toString();
\r
1023 if (str == null || str.length() == 0) {
\r
1024 errln("FAIL: DateTimeRule#toString for dtr1 returns null or empty string");
\r
1026 logln("DateTimeRule dtr1 : " + str);
\r
1028 str = dtr2.toString();
\r
1029 if (str == null || str.length() == 0) {
\r
1030 errln("FAIL: DateTimeRule#toString for dtr2 returns null or empty string");
\r
1032 logln("DateTimeRule dtr1 : " + str);
\r
1034 str = dtr3.toString();
\r
1035 if (str == null || str.length() == 0) {
\r
1036 errln("FAIL: DateTimeRule#toString for dtr3 returns null or empty string");
\r
1038 logln("DateTimeRule dtr1 : " + str);
\r
1040 str = dtr4.toString();
\r
1041 if (str == null || str.length() == 0) {
\r
1042 errln("FAIL: DateTimeRule#toString for dtr4 returns null or empty string");
\r
1044 logln("DateTimeRule dtr1 : " + str);
\r
1049 * API coverage test for BasicTimeZone APIs in SimpleTimeZone
\r
1051 public void TestSimpleTimeZoneCoverage() {
\r
1053 long time1 = getUTCMillis(1990, Calendar.JUNE, 1);
\r
1054 long time2 = getUTCMillis(2000, Calendar.JUNE, 1);
\r
1056 TimeZoneTransition tzt1, tzt2;
\r
1058 // BasicTimeZone API implementation in SimpleTimeZone
\r
1059 SimpleTimeZone stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5");
\r
1061 tzt1 = stz1.getNextTransition(time1, false);
\r
1062 if (tzt1 != null) {
\r
1063 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
\r
1065 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1066 if (tzt1 != null) {
\r
1067 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
\r
1069 TimeZoneRule[] tzrules = stz1.getTimeZoneRules();
\r
1070 if (tzrules.length != 1 || !(tzrules[0] instanceof InitialTimeZoneRule)) {
\r
1071 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules");
\r
1075 stz1.setStartRule(Calendar.MARCH, 11, 2*HOUR); // March 11
\r
1076 stz1.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*HOUR); // First Sunday in November
\r
1077 tzt1 = stz1.getNextTransition(time1, false);
\r
1078 if (tzt1 == null) {
\r
1079 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
\r
1081 String str = tzt1.toString();
\r
1082 if (str == null || str.length() == 0) {
\r
1083 errln("FAIL: TimeZoneTransition#toString returns null or empty string");
\r
1088 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1089 if (tzt1 == null) {
\r
1090 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
\r
1092 tzrules = stz1.getTimeZoneRules();
\r
1093 if (tzrules.length != 3 || !(tzrules[0] instanceof InitialTimeZoneRule)
\r
1094 || !(tzrules[1] instanceof AnnualTimeZoneRule)
\r
1095 || !(tzrules[2] instanceof AnnualTimeZoneRule)) {
\r
1096 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules for a SimpleTimeZone with DST");
\r
1098 // Set DST start year
\r
1099 stz1.setStartYear(2007);
\r
1100 tzt1 = stz1.getPreviousTransition(time1, false);
\r
1101 if (tzt1 != null) {
\r
1102 errln("FAIL: No transition must be returned before 1990");
\r
1104 tzt1 = stz1.getNextTransition(time1, false); // transition after 1990-06-01
\r
1105 tzt2 = stz1.getNextTransition(time2, false); // transition after 2000-06-01
\r
1106 if (tzt1 == null || tzt2 == null || !tzt1.equals(tzt2)) {
\r
1107 errln("FAIL: Bad transition returned by SimpleTimeZone#getNextTransition");
\r
1112 * API coverage test for VTimeZone
\r
1114 public void TestVTimeZoneCoverage() {
\r
1115 final String TZID = "Europe/Moscow";
\r
1116 BasicTimeZone otz = (BasicTimeZone)TimeZone.getTimeZone(TZID, TimeZone.TIMEZONE_ICU);
\r
1117 VTimeZone vtz = VTimeZone.create(TZID);
\r
1119 // getOffset(era, year, month, day, dayOfWeek, milliseconds)
\r
1120 int offset1 = otz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1121 int offset2 = vtz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1122 if (offset1 != offset2) {
\r
1123 errln("FAIL: getOffset(int,int,int,int,int,int) returned different results in VTimeZone and OlsonTimeZone");
\r
1126 // getOffset(date, local, offsets)
\r
1127 int[] offsets1 = new int[2];
\r
1128 int[] offsets2 = new int[2];
\r
1129 long t = System.currentTimeMillis();
\r
1130 otz.getOffset(t, false, offsets1);
\r
1131 vtz.getOffset(t, false, offsets2);
\r
1132 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) {
\r
1133 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
\r
1137 if (otz.getRawOffset() != vtz.getRawOffset()) {
\r
1138 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
\r
1142 Date d = new Date();
\r
1143 if (otz.inDaylightTime(d) != vtz.inDaylightTime(d)) {
\r
1144 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
\r
1147 // useDaylightTime
\r
1148 if (otz.useDaylightTime() != vtz.useDaylightTime()) {
\r
1149 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
\r
1153 final int RAW = -10*HOUR;
\r
1154 VTimeZone tmpvtz = (VTimeZone)vtz.clone();
\r
1155 tmpvtz.setRawOffset(RAW);
\r
1156 if (tmpvtz.getRawOffset() != RAW) {
\r
1157 logln("setRawOffset is implemented");
\r
1161 boolean bSame = otz.hasSameRules(vtz);
\r
1162 logln("OlsonTimeZone#hasSameRules(VTimeZone) should return false always for now - actual: " + bSame);
\r
1164 // getTZURL/setTZURL
\r
1165 final String TZURL = "http://icu-project.org/timezone";
\r
1166 String tzurl = vtz.getTZURL();
\r
1167 if (tzurl != null) {
\r
1168 errln("FAIL: getTZURL returned non-null value");
\r
1170 vtz.setTZURL(TZURL);
\r
1171 tzurl = vtz.getTZURL();
\r
1172 if (!TZURL.equals(tzurl)) {
\r
1173 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
\r
1176 // getLastModified/setLastModified
\r
1177 Date lastmod = vtz.getLastModified();
\r
1178 if (lastmod != null) {
\r
1179 errln("FAIL: getLastModified returned non-null value");
\r
1181 Date newdate = new Date();
\r
1182 vtz.setLastModified(newdate);
\r
1183 lastmod = vtz.getLastModified();
\r
1184 if (!newdate.equals(lastmod)) {
\r
1185 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
\r
1188 // getNextTransition/getPreviousTransition
\r
1189 long base = getUTCMillis(2007, Calendar.JULY, 1);
\r
1190 TimeZoneTransition tzt1 = otz.getNextTransition(base, true);
\r
1191 TimeZoneTransition tzt2 = vtz.getNextTransition(base, true);
\r
1192 if (tzt1.equals(tzt2)) {
\r
1193 errln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
\r
1195 tzt1 = otz.getPreviousTransition(base, false);
\r
1196 tzt2 = vtz.getPreviousTransition(base, false);
\r
1197 if (tzt1.equals(tzt2)) {
\r
1198 errln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
\r
1201 // hasEquivalentTransitions
\r
1202 long time1 = getUTCMillis(1950, Calendar.JANUARY, 1);
\r
1203 long time2 = getUTCMillis(2020, Calendar.JANUARY, 1);
\r
1204 if (!vtz.hasEquivalentTransitions(otz, time1, time2)) {
\r
1205 errln("FAIL: hasEquivalentTransitons returned false for the same time zone");
\r
1208 // getTimeZoneRules
\r
1209 TimeZoneRule[] rulesetAll = vtz.getTimeZoneRules();
\r
1210 TimeZoneRule[] ruleset1 = vtz.getTimeZoneRules(time1);
\r
1211 TimeZoneRule[] ruleset2 = vtz.getTimeZoneRules(time2);
\r
1212 if (rulesetAll.length < ruleset1.length || ruleset1.length < ruleset2.length) {
\r
1213 errln("FAIL: Number of rules returned by getRules is invalid");
\r
1217 public void TestVTimeZoneParse() {
\r
1218 // Trying to create VTimeZone from empty data
\r
1219 StringReader r = new StringReader("");
\r
1220 VTimeZone empty = VTimeZone.create(r);
\r
1221 if (empty != null) {
\r
1222 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
\r
1225 // Create VTimeZone for Asia/Tokyo
\r
1226 String asiaTokyo =
\r
1227 "BEGIN:VTIMEZONE\r\n" +
\r
1230 "BEGIN:STANDARD\r\n" +
\r
1231 "TZOFFSETFROM:+0900\r\n" +
\r
1232 "TZOFFSETTO:+0900\r\n" +
\r
1233 "TZNAME:JST\r\n" +
\r
1234 "DTSTART:19700101\r\n" +
\r
1236 "END:STANDARD\r\n" +
\r
1238 r = new StringReader(asiaTokyo);
\r
1239 VTimeZone tokyo = VTimeZone.create(r);
\r
1240 if (tokyo == null) {
\r
1241 errln("FAIL: Failed to create a VTimeZone tokyo");
\r
1243 // Make sure offsets are correct
\r
1244 int[] offsets = new int[2];
\r
1245 tokyo.getOffset(System.currentTimeMillis(), false, offsets);
\r
1246 if (offsets[0] != 9*HOUR || offsets[1] != 0) {
\r
1247 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
\r
1251 // Create VTimeZone from VTIMEZONE data
\r
1253 "BEGIN:VCALENDAR\r\n" +
\r
1254 "BEGIN:VTIMEZONE\r\n" +
\r
1256 "BEGIN:STANDARD\r\n" +
\r
1257 "TZOFFSETFROM:-0700\r\n" +
\r
1258 "TZOFFSETTO:-0800\r\n" +
\r
1259 "TZNAME:FST\r\n" +
\r
1260 "DTSTART:20071010T010000\r\n" +
\r
1261 "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\r\n" +
\r
1262 "END:STANDARD\r\n" +
\r
1263 "BEGIN:DAYLIGHT\r\n" +
\r
1264 "TZOFFSETFROM:-0800\r\n" +
\r
1265 "TZOFFSETTO:-0700\r\n" +
\r
1266 "TZNAME:FDT\r\n" +
\r
1267 "DTSTART:20070415T010000\r\n" +
\r
1268 "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\r\n" +
\r
1269 "END:DAYLIGHT\r\n" +
\r
1270 "END:VTIMEZONE\r\n" +
\r
1273 r = new StringReader(fooData);
\r
1274 VTimeZone foo = VTimeZone.create(r);
\r
1275 if (foo == null) {
\r
1276 errln("FAIL: Failed to create a VTimeZone foo");
\r
1278 // Write VTIMEZONE data
\r
1279 StringWriter w = new StringWriter();
\r
1281 foo.write(w, getUTCMillis(2005, Calendar.JANUARY, 1));
\r
1282 } catch (IOException ioe) {
\r
1283 errln("FAIL: IOException is thrown while writing VTIMEZONE data for foo");
\r
1285 logln(w.toString());
\r
1289 public void TestT6216() {
\r
1290 // Test case in #6216
\r
1292 "BEGIN:VCALENDAR\r\n" +
\r
1293 "VERSION:2.0\r\n" +
\r
1294 "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" +
\r
1295 "BEGIN:VTIMEZONE\r\n" +
\r
1296 "TZID:Asia/Tokyo\r\n" +
\r
1297 "BEGIN:STANDARD\r\n" +
\r
1298 "DTSTART:20000101T000000\r\n" +
\r
1299 "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" +
\r
1300 "TZNAME:Asia/Tokyo\r\n" +
\r
1301 "TZOFFSETFROM:+0900\r\n" +
\r
1302 "TZOFFSETTO:+0900\r\n" +
\r
1303 "END:STANDARD\r\n" +
\r
1304 "END:VTIMEZONE\r\n" +
\r
1307 // Single final rule, overlapping with another
\r
1308 String finalOverlap =
\r
1309 "BEGIN:VCALENDAR\r\n" +
\r
1310 "BEGIN:VTIMEZONE\r\n" +
\r
1311 "TZID:FinalOverlap\r\n" +
\r
1312 "BEGIN:STANDARD\r\n" +
\r
1313 "TZOFFSETFROM:-0200\r\n" +
\r
1314 "TZOFFSETTO:-0300\r\n" +
\r
1315 "TZNAME:STD\r\n" +
\r
1316 "DTSTART:20001029T020000\r\n" +
\r
1317 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" +
\r
1318 "END:STANDARD\r\n" +
\r
1319 "BEGIN:DAYLIGHT\r\n" +
\r
1320 "TZOFFSETFROM:-0300\r\n" +
\r
1321 "TZOFFSETTO:-0200\r\n" +
\r
1322 "TZNAME:DST\r\n" +
\r
1323 "DTSTART:19990404T020000\r\n" +
\r
1324 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" +
\r
1325 "END:DAYLIGHT\r\n" +
\r
1326 "END:VTIMEZONE\r\n" +
\r
1329 // Single final rule, no overlapping with another
\r
1330 String finalNonOverlap =
\r
1331 "BEGIN:VCALENDAR\r\n" +
\r
1332 "BEGIN:VTIMEZONE\r\n" +
\r
1333 "TZID:FinalNonOverlap\r\n" +
\r
1334 "BEGIN:STANDARD\r\n" +
\r
1335 "TZOFFSETFROM:-0200\r\n" +
\r
1336 "TZOFFSETTO:-0300\r\n" +
\r
1337 "TZNAME:STD\r\n" +
\r
1338 "DTSTART:20001029T020000\r\n" +
\r
1339 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" +
\r
1340 "END:STANDARD\r\n" +
\r
1341 "BEGIN:DAYLIGHT\r\n" +
\r
1342 "TZOFFSETFROM:-0300\r\n" +
\r
1343 "TZOFFSETTO:-0200\r\n" +
\r
1344 "TZNAME:DST\r\n" +
\r
1345 "DTSTART:19990404T020000\r\n" +
\r
1346 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" +
\r
1347 "END:DAYLIGHT\r\n" +
\r
1348 "BEGIN:STANDARD\r\n" +
\r
1349 "TZOFFSETFROM:-0200\r\n" +
\r
1350 "TZOFFSETTO:-0300\r\n" +
\r
1351 "TZNAME:STDFINAL\r\n" +
\r
1352 "DTSTART:20071028T020000\r\n" +
\r
1353 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" +
\r
1354 "END:STANDARD\r\n" +
\r
1355 "END:VTIMEZONE\r\n" +
\r
1358 int[][] TestDates = {
\r
1359 {1995, Calendar.JANUARY, 1},
\r
1360 {1995, Calendar.JULY, 1},
\r
1361 {2000, Calendar.JANUARY, 1},
\r
1362 {2000, Calendar.JULY, 1},
\r
1363 {2005, Calendar.JANUARY, 1},
\r
1364 {2005, Calendar.JULY, 1},
\r
1365 {2010, Calendar.JANUARY, 1},
\r
1366 {2010, Calendar.JULY, 1},
\r
1369 String[] TestZones = {
\r
1375 int[][] Expected = {
\r
1376 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10
\r
1377 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000},
\r
1378 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
\r
1379 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000},
\r
1383 long[] times = new long[TestDates.length];
\r
1384 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
\r
1385 for (int i = 0; i < TestDates.length; i++) {
\r
1387 cal.set(TestDates[i][0], TestDates[i][1], TestDates[i][2]);
\r
1388 times[i] = cal.getTimeInMillis();
\r
1391 for (int i = 0; i < TestZones.length; i++) {
\r
1393 VTimeZone vtz = VTimeZone.create(new StringReader(TestZones[i]));
\r
1394 for (int j = 0; j < times.length; j++) {
\r
1395 int offset = vtz.getOffset(times[j]);
\r
1396 if (offset != Expected[i][j]) {
\r
1397 errln("FAIL: Invalid offset at time(" + times[j] + "):" + offset + " Expected:" + Expected[i][j]);
\r
1400 } catch (Exception e) {
\r
1401 errln("FAIL: Failed to calculate the offset for VTIMEZONE data " + i);
\r
1406 public void TestT6669() {
\r
1407 // getNext/PreviousTransition implementation in SimpleTimeZone
\r
1408 // used to use a bad condition for detecting if DST is enabled or not.
\r
1410 SimpleTimeZone stz = new SimpleTimeZone(0, "CustomID",
\r
1411 Calendar.JANUARY, 1, Calendar.SUNDAY, 0,
\r
1412 Calendar.JULY, 1, Calendar.SUNDAY, 0);
\r
1414 long t = 1230681600000L; //2008-12-31T00:00:00
\r
1415 long expectedNext = 1231027200000L; //2009-01-04T00:00:00
\r
1416 long expectedPrev = 1215298800000L; //2008-07-06T00:00:00
\r
1418 TimeZoneTransition tzt = stz.getNextTransition(t, false);
\r
1419 if (tzt == null) {
\r
1420 errln("FAIL: No transition returned by getNextTransition.");
\r
1421 } else if (tzt.getTime() != expectedNext){
\r
1422 errln("FAIL: Wrong transition time returned by getNextTransition - "
\r
1423 + tzt.getTime() + " Expected: " + expectedNext);
\r
1426 tzt = stz.getPreviousTransition(t, true);
\r
1427 if (tzt == null) {
\r
1428 errln("FAIL: No transition returned by getPreviousTransition.");
\r
1429 } else if (tzt.getTime() != expectedPrev){
\r
1430 errln("FAIL: Wrong transition time returned by getPreviousTransition - "
\r
1431 + tzt.getTime() + " Expected: " + expectedPrev);
\r
1435 // Internal utility methods -----------------------------------------
\r
1438 * Check if a time shift really happens on each transition returned by getNextTransition or
\r
1439 * getPreviousTransition in the specified time range
\r
1441 private void verifyTransitions(TimeZone tz, long start, long end) {
\r
1442 BasicTimeZone icutz = (BasicTimeZone)tz;
\r
1444 int[] before = new int[2];
\r
1445 int[] after = new int[2];
\r
1446 TimeZoneTransition tzt0;
\r
1452 TimeZoneTransition tzt = icutz.getNextTransition(time, false);
\r
1454 if (tzt == null) {
\r
1457 time = tzt.getTime();
\r
1458 if (time >= end) {
\r
1461 icutz.getOffset(time, false, after);
\r
1462 icutz.getOffset(time - 1, false, before);
\r
1464 if (after[0] == before[0] && after[1] == before[1]) {
\r
1465 errln("FAIL: False transition returned by getNextTransition for " + icutz.getID() + " at " + time);
\r
1467 if (tzt0 != null &&
\r
1468 (tzt0.getTo().getRawOffset() != tzt.getFrom().getRawOffset()
\r
1469 || tzt0.getTo().getDSTSavings() != tzt.getFrom().getDSTSavings())) {
\r
1470 errln("FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
\r
1471 + time + " for " + icutz.getID());
\r
1480 TimeZoneTransition tzt = icutz.getPreviousTransition(time, false);
\r
1481 if (tzt == null) {
\r
1484 time = tzt.getTime();
\r
1485 if (time <= start) {
\r
1488 icutz.getOffset(time, false, after);
\r
1489 icutz.getOffset(time - 1, false, before);
\r
1491 if (after[0] == before[0] && after[1] == before[1]) {
\r
1492 errln("FAIL: False transition returned by getPreviousTransition for " + icutz.getID() + " at " + time);
\r
1495 if (tzt0 != null &&
\r
1496 (tzt0.getFrom().getRawOffset() != tzt.getTo().getRawOffset()
\r
1497 || tzt0.getFrom().getDSTSavings() != tzt.getTo().getDSTSavings())) {
\r
1498 errln("FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
\r
1499 + time + " for " + icutz.getID());
\r
1506 * Compare all time transitions in 2 time zones in the specified time range in ascending order
\r
1508 private void compareTransitionsAscending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) {
\r
1509 BasicTimeZone z1 = (BasicTimeZone)tz1;
\r
1510 BasicTimeZone z2 = (BasicTimeZone)tz2;
\r
1511 String zid1 = tz1.getID();
\r
1512 String zid2 = tz2.getID();
\r
1514 long time = start;
\r
1516 TimeZoneTransition tzt1 = z1.getNextTransition(time, inclusive);
\r
1517 TimeZoneTransition tzt2 = z2.getNextTransition(time, inclusive);
\r
1518 boolean inRange1 = false;
\r
1519 boolean inRange2 = false;
\r
1520 if (tzt1 != null) {
\r
1521 if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) {
\r
1525 if (tzt2 != null) {
\r
1526 if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) {
\r
1530 if (!inRange1 && !inRange2) {
\r
1531 // No more transition in the range
\r
1535 errln("FAIL: " + zid1 + " does not have any transitions after " + time + " before " + end);
\r
1539 errln("FAIL: " + zid2 + " does not have any transitions after " + time + " before " + end);
\r
1542 if (tzt1.getTime() != tzt2.getTime()) {
\r
1543 errln("FAIL: First transition after " + time + " "
\r
1544 + zid1 + "[" + tzt1.getTime() + "] "
\r
1545 + zid2 + "[" + tzt2.getTime() + "]");
\r
1548 time = tzt1.getTime();
\r
1556 * Compare all time transitions in 2 time zones in the specified time range in descending order
\r
1558 private void compareTransitionsDescending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) {
\r
1559 BasicTimeZone z1 = (BasicTimeZone)tz1;
\r
1560 BasicTimeZone z2 = (BasicTimeZone)tz2;
\r
1561 String zid1 = tz1.getID();
\r
1562 String zid2 = tz2.getID();
\r
1565 TimeZoneTransition tzt1 = z1.getPreviousTransition(time, inclusive);
\r
1566 TimeZoneTransition tzt2 = z2.getPreviousTransition(time, inclusive);
\r
1567 boolean inRange1 = false;
\r
1568 boolean inRange2 = false;
\r
1569 if (tzt1 != null) {
\r
1570 if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) {
\r
1574 if (tzt2 != null) {
\r
1575 if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) {
\r
1579 if (!inRange1 && !inRange2) {
\r
1580 // No more transition in the range
\r
1584 errln("FAIL: " + zid1 + " does not have any transitions before " + time + " after " + start);
\r
1588 errln("FAIL: " + zid2 + " does not have any transitions before " + time + " after " + start);
\r
1591 if (tzt1.getTime() != tzt2.getTime()) {
\r
1592 errln("FAIL: Last transition before " + time + " "
\r
1593 + zid1 + "[" + tzt1.getTime() + "] "
\r
1594 + zid2 + "[" + tzt2.getTime() + "]");
\r
1597 time = tzt1.getTime();
\r
1604 private static final String[] TESTZIDS = {
\r
1606 "America/New_York",
\r
1607 "America/Los_Angeles",
\r
1608 "America/Indiana/Indianapolis",
\r
1615 "Africa/Windhoek",
\r
1616 "Australia/Sydney",
\r
1620 private String[] getTestZIDs() {
\r
1621 if (getInclusion() > 5) {
\r
1622 return TimeZone.getAvailableIDs();
\r
1627 private static final int[][] TESTYEARS = {
\r
1628 {1895, 1905}, // including int32 minimum second
\r
1629 {1965, 1975}, // including the epoch
\r
1630 {1995, 2015} // practical year range
\r
1633 private long[] getTestTimeRange(int idx) {
\r
1634 int loyear, hiyear;
\r
1635 if (idx < TESTYEARS.length) {
\r
1636 loyear = TESTYEARS[idx][0];
\r
1637 hiyear = TESTYEARS[idx][1];
\r
1638 } else if (idx == TESTYEARS.length && getInclusion() > 5) {
\r
1645 long[] times = new long[2];
\r
1646 times[0] = getUTCMillis(loyear, Calendar.JANUARY, 1);
\r
1647 times[1] = getUTCMillis(hiyear + 1, Calendar.JANUARY, 1);
\r
1652 private GregorianCalendar utcCal;
\r
1654 private long getUTCMillis(int year, int month, int dayOfMonth) {
\r
1655 if (utcCal == null) {
\r
1656 utcCal = new GregorianCalendar(TimeZone.getTimeZone("UTC"), ULocale.ROOT);
\r
1659 utcCal.set(year, month, dayOfMonth);
\r
1660 return utcCal.getTimeInMillis();
\r