1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 2007-2011, International Business Machines Corporation and * 7 * others. All Rights Reserved. * 8 ******************************************************************************* 9 */ 10 package ohos.global.icu.dev.test.timezone; 11 12 import java.io.ByteArrayInputStream; 13 import java.io.ByteArrayOutputStream; 14 import java.io.IOException; 15 import java.io.InputStreamReader; 16 import java.io.OutputStreamWriter; 17 import java.io.StringReader; 18 import java.io.StringWriter; 19 import java.util.Date; 20 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.junit.runners.JUnit4; 24 25 import ohos.global.icu.dev.test.TestFmwk; 26 import ohos.global.icu.util.AnnualTimeZoneRule; 27 import ohos.global.icu.util.BasicTimeZone; 28 import ohos.global.icu.util.Calendar; 29 import ohos.global.icu.util.DateTimeRule; 30 import ohos.global.icu.util.GregorianCalendar; 31 import ohos.global.icu.util.InitialTimeZoneRule; 32 import ohos.global.icu.util.RuleBasedTimeZone; 33 import ohos.global.icu.util.SimpleTimeZone; 34 import ohos.global.icu.util.TimeArrayTimeZoneRule; 35 import ohos.global.icu.util.TimeZone; 36 import ohos.global.icu.util.TimeZoneRule; 37 import ohos.global.icu.util.TimeZoneTransition; 38 import ohos.global.icu.util.ULocale; 39 import ohos.global.icu.util.VTimeZone; 40 41 42 /** 43 * Test cases for TimeZoneRule and RuleBasedTimeZone 44 */ 45 46 @RunWith(JUnit4.class) 47 public class TimeZoneRuleTest extends TestFmwk { 48 49 private static final int HOUR = 60 * 60 * 1000; 50 51 /* 52 * RuleBasedTimeZone test cases 53 */ 54 @Test TestSimpleRuleBasedTimeZone()55 public void TestSimpleRuleBasedTimeZone() { 56 SimpleTimeZone stz = new SimpleTimeZone(-1*HOUR, "TestSTZ", 57 Calendar.SEPTEMBER, -30, -Calendar.SATURDAY, 1*HOUR, SimpleTimeZone.WALL_TIME, 58 Calendar.FEBRUARY, 2, Calendar.SUNDAY, 1*HOUR, SimpleTimeZone.WALL_TIME, 59 1*HOUR); 60 61 62 DateTimeRule dtr; 63 AnnualTimeZoneRule atzr; 64 final int STARTYEAR = 2000; 65 66 InitialTimeZoneRule ir = new InitialTimeZoneRule( 67 "RBTZ_Initial", // Initial time Name 68 -1*HOUR, // Raw offset 69 1*HOUR); // DST saving amount 70 71 // RBTZ 72 RuleBasedTimeZone rbtz1 = new RuleBasedTimeZone("RBTZ1", ir); 73 dtr = new DateTimeRule(Calendar.SEPTEMBER, 30, Calendar.SATURDAY, false, 74 1*HOUR, DateTimeRule.WALL_TIME); // SUN<=30 in September, at 1AM wall time 75 atzr = new AnnualTimeZoneRule("RBTZ_DST1", 76 -1*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr, 77 STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 78 rbtz1.addTransitionRule(atzr); 79 dtr = new DateTimeRule(Calendar.FEBRUARY, 2, Calendar.SUNDAY, 80 1*HOUR, DateTimeRule.WALL_TIME); // 2nd Sunday in February, at 1AM wall time 81 atzr = new AnnualTimeZoneRule("RBTZ_STD1", 82 -1*HOUR /* rawOffset */, 0 /* dstSavings */, dtr, 83 STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 84 rbtz1.addTransitionRule(atzr); 85 86 // Equivalent, but different date rule type 87 RuleBasedTimeZone rbtz2 = new RuleBasedTimeZone("RBTZ2", ir); 88 dtr = new DateTimeRule(Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 89 1*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in September at 1AM wall time 90 atzr = new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 91 rbtz2.addTransitionRule(atzr); 92 dtr = new DateTimeRule(Calendar.FEBRUARY, 8, Calendar.SUNDAY, true, 93 1*HOUR, DateTimeRule.WALL_TIME); // SUN>=8 in February, at 1AM wall time 94 atzr = new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 95 rbtz2.addTransitionRule(atzr); 96 97 // Equivalent, but different time rule type 98 RuleBasedTimeZone rbtz3 = new RuleBasedTimeZone("RBTZ3", ir); 99 dtr = new DateTimeRule(Calendar.SEPTEMBER, 30, Calendar.SATURDAY, false, 100 2*HOUR, DateTimeRule.UTC_TIME); 101 atzr = new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 102 rbtz3.addTransitionRule(atzr); 103 dtr = new DateTimeRule(Calendar.FEBRUARY, 2, Calendar.SUNDAY, 104 0*HOUR, DateTimeRule.STANDARD_TIME); 105 atzr = new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 106 rbtz3.addTransitionRule(atzr); 107 108 // Check equivalency for 10 years 109 long start = getUTCMillis(STARTYEAR, Calendar.JANUARY, 1); 110 long until = getUTCMillis(STARTYEAR + 10, Calendar.JANUARY, 1); 111 112 if (!(stz.hasEquivalentTransitions(rbtz1, start, until))) { 113 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range."); 114 } 115 if (!(stz.hasEquivalentTransitions(rbtz2, start, until))) { 116 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range."); 117 } 118 if (!(stz.hasEquivalentTransitions(rbtz3, start, until))) { 119 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range."); 120 } 121 122 // hasSameRules 123 if (rbtz1.hasSameRules(rbtz2)) { 124 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true."); 125 } 126 if (rbtz1.hasSameRules(rbtz3)) { 127 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true."); 128 } 129 RuleBasedTimeZone rbtz1c = (RuleBasedTimeZone)rbtz1.clone(); 130 if (!rbtz1.hasSameRules(rbtz1c)) { 131 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original."); 132 } 133 134 // getOffset 135 GregorianCalendar cal = new GregorianCalendar(); 136 int[] offsets = new int[2]; 137 int offset; 138 boolean dst; 139 140 cal.setTimeZone(rbtz1); 141 cal.clear(); 142 143 // Jan 1, 1000 BC 144 cal.set(Calendar.ERA, GregorianCalendar.BC); 145 cal.set(1000, Calendar.JANUARY, 1); 146 147 offset = rbtz1.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 148 cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), cal.get(Calendar.MILLISECONDS_IN_DAY)); 149 if (offset != 0) { 150 errln("FAIL: Invalid time zone offset: " + offset + " /expected: 0"); 151 } 152 dst = rbtz1.inDaylightTime(cal.getTime()); 153 if (!dst) { 154 errln("FAIL: Invalid daylight saving time"); 155 } 156 rbtz1.getOffset(cal.getTimeInMillis(), true, offsets); 157 if (offsets[0] != -3600000) { 158 errln("FAIL: Invalid time zone raw offset: " + offsets[0] + " /expected: -3600000"); 159 } 160 if (offsets[1] != 3600000) { 161 errln("FAIL: Invalid DST amount: " + offsets[1] + " /expected: 3600000"); 162 } 163 164 // July 1, 2000, AD 165 cal.set(Calendar.ERA, GregorianCalendar.AD); 166 cal.set(2000, Calendar.JULY, 1); 167 168 offset = rbtz1.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 169 cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), cal.get(Calendar.MILLISECONDS_IN_DAY)); 170 if (offset != -3600000) { 171 errln("FAIL: Invalid time zone offset: " + offset + " /expected: -3600000"); 172 } 173 dst = rbtz1.inDaylightTime(cal.getTime()); 174 if (dst) { 175 errln("FAIL: Invalid daylight saving time"); 176 } 177 rbtz1.getOffset(cal.getTimeInMillis(), true, offsets); 178 if (offsets[0] != -3600000) { 179 errln("FAIL: Invalid time zone raw offset: " + offsets[0] + " /expected: -3600000"); 180 } 181 if (offsets[1] != 0) { 182 errln("FAIL: Invalid DST amount: " + offsets[1] + " /expected: 0"); 183 } 184 185 // July 1, 2000, AD 186 187 // Try to add 3rd final rule 188 dtr = new DateTimeRule(Calendar.OCTOBER, 15, 1*HOUR, DateTimeRule.WALL_TIME); 189 atzr = new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR, 2*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule.MAX_YEAR); 190 boolean bException = false; 191 try { 192 rbtz1.addTransitionRule(atzr); 193 } catch (IllegalStateException ise) { 194 bException = true; 195 } 196 if (!bException) { 197 errln("FAIL: 3rd final rule must be rejected"); 198 } 199 200 // Try to add an initial rule 201 bException = false; 202 try { 203 rbtz1.addTransitionRule(new InitialTimeZoneRule("Test Initial", 2*HOUR, 0)); 204 } catch (IllegalArgumentException iae) { 205 bException = true; 206 } 207 if (!bException) { 208 errln("FAIL: InitialTimeZoneRule must be rejected"); 209 } 210 } 211 212 /* 213 * Test equivalency between OlsonTimeZone and custom RBTZ representing the 214 * equivalent rules in a certain time range 215 */ 216 @Test TestHistoricalRuleBasedTimeZone()217 public void TestHistoricalRuleBasedTimeZone() { 218 // Compare to America/New_York with equivalent RBTZ 219 TimeZone ny = TimeZone.getTimeZone("America/New_York", TimeZone.TIMEZONE_ICU); 220 221 //RBTZ 222 InitialTimeZoneRule ir = new InitialTimeZoneRule("EST", -5*HOUR, 0); 223 RuleBasedTimeZone rbtz = new RuleBasedTimeZone("EST5EDT", ir); 224 225 DateTimeRule dtr; 226 AnnualTimeZoneRule tzr; 227 228 // Standard time 229 dtr = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 230 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in October, at 2AM wall time 231 tzr = new AnnualTimeZoneRule("EST", -5*HOUR /* rawOffset */, 0 /* dstSavings */, dtr, 1967, 2006); 232 rbtz.addTransitionRule(tzr); 233 234 dtr = new DateTimeRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 235 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=1 in November, at 2AM wall time 236 tzr = new AnnualTimeZoneRule("EST", -5*HOUR, 0, dtr, 2007, AnnualTimeZoneRule.MAX_YEAR); 237 rbtz.addTransitionRule(tzr); 238 239 // Daylight saving time 240 dtr = new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY, 241 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in April, at 2AM wall time 242 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1967, 1973); 243 rbtz.addTransitionRule(tzr); 244 245 dtr = new DateTimeRule(Calendar.JANUARY, 6, 246 2*HOUR, DateTimeRule.WALL_TIME); // January 6, at 2AM wall time 247 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1974, 1974); 248 rbtz.addTransitionRule(tzr); 249 250 dtr = new DateTimeRule(Calendar.FEBRUARY, 23, 251 2*HOUR, DateTimeRule.WALL_TIME); // February 23, at 2AM wall time 252 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1975, 1975); 253 rbtz.addTransitionRule(tzr); 254 255 dtr = new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY, 256 2*HOUR, DateTimeRule.WALL_TIME); // Last Sunday in April, at 2AM wall time 257 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1976, 1986); 258 rbtz.addTransitionRule(tzr); 259 260 dtr = new DateTimeRule(Calendar.APRIL, 1, Calendar.SUNDAY, 261 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=1 in April, at 2AM wall time 262 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1987, 2006); 263 rbtz.addTransitionRule(tzr); 264 265 dtr = new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY, 266 true, 2*HOUR, DateTimeRule.WALL_TIME); // SUN>=8 in March, at 2AM wall time 267 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 2007, AnnualTimeZoneRule.MAX_YEAR); 268 rbtz.addTransitionRule(tzr); 269 270 // hasEquivalentTransitions 271 long jan1_1950 = getUTCMillis(1950, Calendar.JANUARY, 1); 272 long jan1_1967 = getUTCMillis(1971, Calendar.JANUARY, 1); 273 long jan1_2010 = getUTCMillis(2010, Calendar.JANUARY, 1); 274 275 if (!(((BasicTimeZone)ny).hasEquivalentTransitions(rbtz, jan1_1967, jan1_2010))) { 276 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010"); 277 } 278 if (((BasicTimeZone)ny).hasEquivalentTransitions(rbtz, jan1_1950, jan1_2010)) { 279 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010"); 280 } 281 282 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone 283 if (!rbtz.hasEquivalentTransitions(ny, jan1_1967, jan1_2010)) { 284 errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010"); 285 } 286 if (rbtz.hasEquivalentTransitions(ny, jan1_1950, jan1_2010)) { 287 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010"); 288 } 289 290 // TimeZone APIs 291 if (ny.hasSameRules(rbtz) || rbtz.hasSameRules(ny)) { 292 errln("FAIL: hasSameRules must return false"); 293 } 294 RuleBasedTimeZone rbtzc = (RuleBasedTimeZone)rbtz.clone(); 295 if (!rbtz.hasSameRules(rbtzc) || !rbtz.hasEquivalentTransitions(rbtzc, jan1_1950, jan1_2010)) { 296 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs"); 297 } 298 299 long times[] = { 300 getUTCMillis(2006, Calendar.MARCH, 15), 301 getUTCMillis(2006, Calendar.NOVEMBER, 1), 302 getUTCMillis(2007, Calendar.MARCH, 15), 303 getUTCMillis(2007, Calendar.NOVEMBER, 1), 304 getUTCMillis(2008, Calendar.MARCH, 15), 305 getUTCMillis(2008, Calendar.NOVEMBER, 1) 306 }; 307 int[] offsets1 = new int[2]; 308 int[] offsets2 = new int[2]; 309 310 for (int i = 0; i < times.length; i++) { 311 // Check getOffset - must return the same results for these time data 312 rbtz.getOffset(times[i], false, offsets1); 313 ny.getOffset(times[i], false, offsets2); 314 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) { 315 errln("FAIL: Incompatible time zone offsets for ny and rbtz"); 316 } 317 // Check inDaylightTime 318 Date d = new Date(times[i]); 319 if (rbtz.inDaylightTime(d) != ny.inDaylightTime(d)) { 320 errln("FAIL: Incompatible daylight saving time for ny and rbtz"); 321 } 322 } 323 } 324 325 /* 326 * Check if transitions returned by getNextTransition/getPreviousTransition 327 * are actual time transitions. 328 */ 329 @Test TestOlsonTransition()330 public void TestOlsonTransition() { 331 String[] zids = getTestZIDs(); 332 for (int i = 0; i < zids.length; i++) { 333 TimeZone tz = TimeZone.getTimeZone(zids[i], TimeZone.TIMEZONE_ICU); 334 if (tz == null) { 335 break; 336 } 337 int j = 0; 338 while (true) { 339 long[] timerange = getTestTimeRange(j++); 340 if (timerange == null) { 341 break; 342 } 343 verifyTransitions(tz, timerange[0], timerange[1]); 344 } 345 } 346 } 347 348 /* 349 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same 350 * transitions. 351 */ 352 @Test TestRBTZTransition()353 public void TestRBTZTransition() { 354 int[] STARTYEARS = { 355 1950, 356 1975, 357 2000, 358 2010 359 }; 360 361 String[] zids = getTestZIDs(); 362 for (int i = 0; i < zids.length; i++) { 363 TimeZone tz = TimeZone.getTimeZone(zids[i], TimeZone.TIMEZONE_ICU); 364 if (tz == null) { 365 break; 366 } 367 for (int j = 0; j < STARTYEARS.length; j++) { 368 long startTime = getUTCMillis(STARTYEARS[j], Calendar.JANUARY, 1); 369 TimeZoneRule[] rules = ((BasicTimeZone)tz).getTimeZoneRules(startTime); 370 RuleBasedTimeZone rbtz = new RuleBasedTimeZone(tz.getID() + "(RBTZ)", 371 (InitialTimeZoneRule)rules[0]); 372 for (int k = 1; k < rules.length; k++) { 373 rbtz.addTransitionRule(rules[k]); 374 } 375 376 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years 377 long until = getUTCMillis(STARTYEARS[j] + 20, Calendar.JANUARY, 1); 378 379 // Ascending 380 compareTransitionsAscending(tz, rbtz, startTime, until, false); 381 // Ascending/inclusive 382 compareTransitionsAscending(tz, rbtz, startTime + 1, until, true); 383 // Descending 384 compareTransitionsDescending(tz, rbtz, startTime, until, false); 385 // Descending/inclusive 386 compareTransitionsDescending(tz, rbtz, startTime + 1, until, true); 387 } 388 389 } 390 } 391 392 /* 393 * Test cases for HasTimeZoneRules#hasEquivalentTransitions 394 */ 395 @Test TestHasEquivalentTransitions()396 public void TestHasEquivalentTransitions() { 397 // America/New_York and America/Indiana/Indianapolis are equivalent 398 // since 2006 399 TimeZone newyork = TimeZone.getTimeZone("America/New_York", TimeZone.TIMEZONE_ICU); 400 TimeZone indianapolis = TimeZone.getTimeZone("America/Indiana/Indianapolis", TimeZone.TIMEZONE_ICU); 401 TimeZone gmt_5 = TimeZone.getTimeZone("Etc/GMT+5", TimeZone.TIMEZONE_ICU); 402 403 long jan1_1971 = getUTCMillis(1971, Calendar.JANUARY, 1); 404 long jan1_2005 = getUTCMillis(2005, Calendar.JANUARY, 1); 405 long jan1_2006 = getUTCMillis(2006, Calendar.JANUARY, 1); 406 long jan1_2007 = getUTCMillis(2007, Calendar.JANUARY, 1); 407 long jan1_2011 = getUTCMillis(2010, Calendar.JANUARY, 1); 408 409 if (((BasicTimeZone)newyork).hasEquivalentTransitions(indianapolis, jan1_2005, jan1_2011)) { 410 errln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010, but returned true"); 411 } 412 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(indianapolis, jan1_2006, jan1_2011)) { 413 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010, but returned false"); 414 } 415 416 if (!((BasicTimeZone)indianapolis).hasEquivalentTransitions(gmt_5, jan1_1971, jan1_2006)) { 417 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005, but returned false"); 418 } 419 if (((BasicTimeZone)indianapolis).hasEquivalentTransitions(gmt_5, jan1_1971, jan1_2007)) { 420 errln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006, but returned true"); 421 } 422 423 // Cloned TimeZone 424 TimeZone newyork2 = (TimeZone)newyork.clone(); 425 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(newyork2, jan1_1971, jan1_2011)) { 426 errln("FAIL: Cloned TimeZone must have the same transitions"); 427 } 428 if (!((BasicTimeZone)newyork).hasEquivalentTransitions(newyork2, jan1_1971, jan1_2011, true /*ignoreDstAmount*/)) { 429 errln("FAIL: Cloned TimeZone must have the same transitions"); 430 } 431 432 // America/New_York and America/Los_Angeles has same DST start rules, but 433 // raw offsets are different 434 TimeZone losangeles = TimeZone.getTimeZone("America/Los_Angeles", TimeZone.TIMEZONE_ICU); 435 if (((BasicTimeZone)newyork).hasEquivalentTransitions(losangeles, jan1_2006, jan1_2011)) { 436 errln("FAIL: New_York is not equivalent to Los Angeles, but returned true"); 437 } 438 } 439 440 /* 441 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new 442 * VTimeZone from the VTIMEZONE data, then compare transitions 443 */ 444 @Test TestVTimeZoneRoundTrip()445 public void TestVTimeZoneRoundTrip() { 446 long startTime = getUTCMillis(1850, Calendar.JANUARY, 1); 447 long endTime = getUTCMillis(2050, Calendar.JANUARY, 1); 448 449 String[] tzids = getTestZIDs(); 450 for (int i = 0; i < tzids.length; i++) { 451 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU); 452 VTimeZone vtz_org = VTimeZone.create(tzids[i]); 453 vtz_org.setTZURL("http://source.icu-project.org/timezone"); 454 vtz_org.setLastModified(new Date()); 455 VTimeZone vtz_new = null; 456 try { 457 // Write out VTIMEZONE 458 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 459 OutputStreamWriter writer = new OutputStreamWriter(baos); 460 vtz_org.write(writer); 461 writer.close(); 462 byte[] vtzdata = baos.toByteArray(); 463 // Read VTIMEZONE 464 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata); 465 InputStreamReader reader = new InputStreamReader(bais); 466 vtz_new = VTimeZone.create(reader); 467 reader.close(); 468 469 // Write out VTIMEZONE one more time 470 ByteArrayOutputStream baos1 = new ByteArrayOutputStream(); 471 OutputStreamWriter writer1 = new OutputStreamWriter(baos1); 472 vtz_new.write(writer1); 473 writer1.close(); 474 byte[] vtzdata1 = baos1.toByteArray(); 475 476 // Make sure VTIMEZONE data is exactly same with the first one 477 if (vtzdata.length != vtzdata1.length) { 478 errln("FAIL: different VTIMEZONE data length"); 479 } 480 for (int j = 0; j < vtzdata.length; j++) { 481 if (vtzdata[j] != vtzdata1[j]) { 482 errln("FAIL: different VTIMEZONE data"); 483 break; 484 } 485 } 486 } catch (IOException ioe) { 487 errln("FAIL: IO error while writing/reading VTIMEZONE data"); 488 } 489 // Check equivalency after the first transition. 490 // The DST information before the first transition might be lost 491 // because there is no good way to represent the initial time with 492 // VTIMEZONE. 493 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) { 494 errln("FAIL: VTimeZone for " + tzids[i] 495 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime); 496 } 497 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false); 498 if (tzt != null) { 499 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) { 500 int maxDelta = 1000; 501 if (!hasEquivalentTransitions(vtz_new, olsontz, tzt.getTime() + maxDelta, endTime, true, maxDelta)) { 502 errln("FAIL: VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding."); 503 } else { 504 logln("VTimeZone for " + tzids[i] + " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta); 505 } 506 } 507 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, false)) { 508 logln("VTimeZone for " + tzids[i] + " is not equivalent to its OlsonTimeZone corresponding in strict comparison mode."); 509 } 510 } 511 } 512 } 513 514 /* 515 * Write out time zone rules of OlsonTimeZone after a cutoff date into VTIMEZONE format, 516 * create a new VTimeZone from the VTIMEZONE data, then compare transitions 517 */ 518 @Test TestVTimeZoneRoundTripPartial()519 public void TestVTimeZoneRoundTripPartial() { 520 long[] startTimes = new long[] { 521 getUTCMillis(1900, Calendar.JANUARY, 1), 522 getUTCMillis(1950, Calendar.JANUARY, 1), 523 getUTCMillis(2020, Calendar.JANUARY, 1) 524 }; 525 long endTime = getUTCMillis(2050, Calendar.JANUARY, 1); 526 527 String[] tzids = getTestZIDs(); 528 for (int n = 0; n < startTimes.length; n++) { 529 long startTime = startTimes[n]; 530 for (int i = 0; i < tzids.length; i++) { 531 BasicTimeZone olsontz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU); 532 VTimeZone vtz_org = VTimeZone.create(tzids[i]); 533 VTimeZone vtz_new = null; 534 try { 535 // Write out VTIMEZONE 536 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 537 OutputStreamWriter writer = new OutputStreamWriter(baos); 538 vtz_org.write(writer, startTime); 539 writer.close(); 540 byte[] vtzdata = baos.toByteArray(); 541 // Read VTIMEZONE 542 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata); 543 InputStreamReader reader = new InputStreamReader(bais); 544 vtz_new = VTimeZone.create(reader); 545 reader.close(); 546 547 } catch (IOException ioe) { 548 errln("FAIL: IO error while writing/reading VTIMEZONE data"); 549 } 550 // Check equivalency after the first transition. 551 // The DST information before the first transition might be lost 552 // because there is no good way to represent the initial time with 553 // VTIMEZONE. 554 if (vtz_new.getOffset(startTime) != olsontz.getOffset(startTime)) { 555 errln("FAIL: VTimeZone for " + tzids[i] 556 + " is not equivalent to its OlsonTimeZone corresponding at " + startTime); 557 } 558 TimeZoneTransition tzt = olsontz.getNextTransition(startTime, false); 559 if (tzt != null) { 560 if (!vtz_new.hasEquivalentTransitions(olsontz, tzt.getTime(), endTime, true)) { 561 int maxDelta = 1000; 562 if (!hasEquivalentTransitions(vtz_new, olsontz, tzt.getTime() + maxDelta, endTime, true, maxDelta)) { 563 errln("FAIL: VTimeZone for " + tzids[i] + "(>=" + startTime + ") is not equivalent to its OlsonTimeZone corresponding."); 564 } else { 565 logln("VTimeZone for " + tzids[i] + "(>=" + startTime + ") differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta); 566 } 567 } 568 } 569 } 570 } 571 } 572 573 /* 574 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE 575 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset 576 * and DST savings are same in these two time zones. 577 */ 578 @Test TestVTimeZoneSimpleWrite()579 public void TestVTimeZoneSimpleWrite() { 580 long[] testTimes = new long[] { 581 getUTCMillis(2006, Calendar.JANUARY, 1), 582 getUTCMillis(2006, Calendar.MARCH, 15), 583 getUTCMillis(2006, Calendar.MARCH, 31), 584 getUTCMillis(2006, Calendar.APRIL, 5), 585 getUTCMillis(2006, Calendar.OCTOBER, 25), 586 getUTCMillis(2006, Calendar.NOVEMBER, 1), 587 getUTCMillis(2006, Calendar.NOVEMBER, 5), 588 getUTCMillis(2007, Calendar.JANUARY, 1) 589 }; 590 591 String[] tzids = getTestZIDs(); 592 for (int n = 0; n < testTimes.length; n++) { 593 long time = testTimes[n]; 594 595 int[] offsets1 = new int[2]; 596 int[] offsets2 = new int[2]; 597 598 for (int i = 0; i < tzids.length; i++) { 599 VTimeZone vtz_org = VTimeZone.create(tzids[i]); 600 VTimeZone vtz_new = null; 601 try { 602 // Write out VTIMEZONE 603 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 604 OutputStreamWriter writer = new OutputStreamWriter(baos); 605 vtz_org.writeSimple(writer, time); 606 writer.close(); 607 byte[] vtzdata = baos.toByteArray(); 608 // Read VTIMEZONE 609 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata); 610 InputStreamReader reader = new InputStreamReader(bais); 611 vtz_new = VTimeZone.create(reader); 612 reader.close(); 613 } catch (IOException ioe) { 614 errln("FAIL: IO error while writing/reading VTIMEZONE data"); 615 } 616 617 // Check equivalency 618 vtz_org.getOffset(time, false, offsets1); 619 vtz_new.getOffset(time, false, offsets2); 620 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) { 621 errln("FAIL: VTimeZone writeSimple for " + tzids[i] + " at time " + time + " failed to the round trip."); 622 } 623 } 624 } 625 } 626 627 /* 628 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and 629 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved. 630 */ 631 @Test TestVTimeZoneHeaderProps()632 public void TestVTimeZoneHeaderProps() { 633 String tzid = "America/Chicago"; 634 String tzurl = "http://source.icu-project.org"; 635 Date lastmod = new Date(getUTCMillis(2007, Calendar.JUNE, 1)); 636 637 VTimeZone vtz = VTimeZone.create(tzid); 638 vtz.setTZURL(tzurl); 639 vtz.setLastModified(lastmod); 640 641 // Roundtrip conversion 642 VTimeZone newvtz1 = null; 643 try { 644 // Write out VTIMEZONE 645 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 646 OutputStreamWriter writer = new OutputStreamWriter(baos); 647 vtz.write(writer); 648 writer.close(); 649 byte[] vtzdata = baos.toByteArray(); 650 // Read VTIMEZONE 651 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata); 652 InputStreamReader reader = new InputStreamReader(bais); 653 newvtz1 = VTimeZone.create(reader); 654 reader.close(); 655 656 // Check if TZURL and LAST-MODIFIED headers are preserved 657 if (!(tzurl.equals(newvtz1.getTZURL()))) { 658 errln("FAIL: TZURL property is not preserved during the roundtrip conversion. Before:" 659 + tzurl + "/After:" + newvtz1.getTZURL()); 660 } 661 if (!(lastmod.equals(newvtz1.getLastModified()))) { 662 errln("FAIL: LAST-MODIFIED property is not preserved during the roundtrip conversion. Before:" 663 + lastmod.getTime() + "/After:" + newvtz1.getLastModified().getTime()); 664 } 665 } catch (IOException ioe) { 666 errln("FAIL: IO error while writing/reading VTIMEZONE data"); 667 } 668 669 // Second roundtrip, with a cutoff 670 VTimeZone newvtz2 = null; 671 try { 672 // Set different tzurl 673 String newtzurl = "http://www.ibm.com"; 674 newvtz1.setTZURL(newtzurl); 675 // Write out VTIMEZONE 676 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 677 OutputStreamWriter writer = new OutputStreamWriter(baos); 678 newvtz1.write(writer, getUTCMillis(2000, Calendar.JANUARY, 1)); 679 writer.close(); 680 byte[] vtzdata = baos.toByteArray(); 681 // Read VTIMEZONE 682 ByteArrayInputStream bais = new ByteArrayInputStream(vtzdata); 683 InputStreamReader reader = new InputStreamReader(bais); 684 newvtz2 = VTimeZone.create(reader); 685 reader.close(); 686 687 // Check if TZURL and LAST-MODIFIED headers are preserved 688 if (!(newtzurl.equals(newvtz2.getTZURL()))) { 689 errln("FAIL: TZURL property is not preserved during the second roundtrip conversion. Before:" 690 + newtzurl + "/After:" + newvtz2.getTZURL()); 691 } 692 if (!(lastmod.equals(newvtz2.getLastModified()))) { 693 errln("FAIL: LAST-MODIFIED property is not preserved during the second roundtrip conversion. Before:" 694 + lastmod.getTime() + "/After:" + newvtz2.getLastModified().getTime()); 695 } 696 } catch (IOException ioe) { 697 errln("FAIL: IO error while writing/reading VTIMEZONE data"); 698 } 699 700 } 701 702 /* 703 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches 704 * the expected format. 705 */ 706 @Test TestGetSimpleRules()707 public void TestGetSimpleRules() { 708 long[] testTimes = new long[] { 709 getUTCMillis(1970, Calendar.JANUARY, 1), 710 getUTCMillis(2000, Calendar.MARCH, 31), 711 getUTCMillis(2005, Calendar.JULY, 1), 712 getUTCMillis(2010, Calendar.NOVEMBER, 1), 713 }; 714 715 String[] tzids = getTestZIDs(); 716 for (int n = 0; n < testTimes.length; n++) { 717 long time = testTimes[n]; 718 for (int i = 0; i < tzids.length; i++) { 719 BasicTimeZone tz = (BasicTimeZone)TimeZone.getTimeZone(tzids[i], TimeZone.TIMEZONE_ICU); 720 TimeZoneRule[] rules = tz.getSimpleTimeZoneRulesNear(time); 721 if (rules == null) { 722 errln("FAIL: Failed to extract simple rules for " + tzids[i] + " at " + time); 723 } else { 724 if (rules.length == 1) { 725 if (!(rules[0] instanceof InitialTimeZoneRule)) { 726 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time); 727 } 728 } else if (rules.length == 3) { 729 if (!(rules[0] instanceof InitialTimeZoneRule) 730 || !(rules[1] instanceof AnnualTimeZoneRule) 731 || !(rules[2] instanceof AnnualTimeZoneRule)) { 732 errln("FAIL: Unexpected rule object type is returned for " + tzids[i] + " at " + time); 733 } 734 for (int idx = 1; idx <= 2; idx++) { 735 DateTimeRule dtr = ((AnnualTimeZoneRule)rules[idx]).getRule(); 736 if (dtr.getTimeRuleType() != DateTimeRule.WALL_TIME) { 737 errln("FAIL: WALL_TIME is not used as the time rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time); 738 } 739 if (dtr.getDateRuleType() != DateTimeRule.DOW) { 740 errln("FAIL: DOW is not used as the date rule in the time zone rule(" + idx + ") for " + tzids[i] + " at " + time); 741 } 742 } 743 } else { 744 errln("FAIL: Unexpected number of rules returned for " + tzids[i] + " at " + time); 745 } 746 } 747 } 748 } 749 } 750 751 /* 752 * API coverage tests for TimeZoneRule 753 */ 754 @Test TestTimeZoneRuleCoverage()755 public void TestTimeZoneRuleCoverage() { 756 long time1 = getUTCMillis(2005, Calendar.JULY, 4); 757 long time2 = getUTCMillis(2015, Calendar.JULY, 4); 758 long time3 = getUTCMillis(1950, Calendar.JULY, 4); 759 760 DateTimeRule dtr1 = new DateTimeRule(Calendar.FEBRUARY, 29, Calendar.SUNDAY, false, 761 3*HOUR, DateTimeRule.WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time 762 DateTimeRule dtr2 = new DateTimeRule(Calendar.MARCH, 11, 2*HOUR, 763 DateTimeRule.STANDARD_TIME); // Mar 11, at 2 AM, standard time 764 DateTimeRule dtr3 = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SATURDAY, 765 6*HOUR, DateTimeRule.UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC 766 DateTimeRule dtr4 = new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY, true, 767 2*HOUR, DateTimeRule.WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time 768 769 AnnualTimeZoneRule a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, dtr1, 770 2000, AnnualTimeZoneRule.MAX_YEAR); 771 AnnualTimeZoneRule a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, dtr1, 772 2000, AnnualTimeZoneRule.MAX_YEAR); 773 AnnualTimeZoneRule a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, dtr1, 774 2000, 2010); 775 776 InitialTimeZoneRule i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0); 777 InitialTimeZoneRule i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0); 778 InitialTimeZoneRule i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR); 779 780 long[] emptytimes = {}; 781 long[] trtimes1 = {0}; 782 long[] trtimes2 = {0, 10000000}; 783 784 TimeArrayTimeZoneRule t0 = null; 785 try { 786 // Try to construct TimeArrayTimeZoneRule with null transition times 787 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0, 788 null, DateTimeRule.UTC_TIME); 789 } catch (IllegalArgumentException iae) { 790 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected."); 791 t0 = null; 792 } 793 if (t0 != null) { 794 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for null times"); 795 } 796 797 try { 798 // Try to construct TimeArrayTimeZoneRule with empty transition times 799 t0 = new TimeArrayTimeZoneRule("nulltimes", -3*HOUR, 0, 800 emptytimes, DateTimeRule.UTC_TIME); 801 } catch (IllegalArgumentException iae) { 802 logln("TimeArrayTimeZoneRule constructor throws IllegalArgumentException as expected."); 803 t0 = null; 804 } 805 if (t0 != null) { 806 errln("FAIL: TimeArrayTimeZoneRule constructor did not throw IllegalArgumentException for empty times"); 807 } 808 809 TimeArrayTimeZoneRule t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME); 810 TimeArrayTimeZoneRule t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, DateTimeRule.UTC_TIME); 811 TimeArrayTimeZoneRule t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, DateTimeRule.UTC_TIME); 812 TimeArrayTimeZoneRule t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, DateTimeRule.STANDARD_TIME); 813 TimeArrayTimeZoneRule t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, DateTimeRule.WALL_TIME); 814 815 // AnnualTimeZoneRule#getRule 816 if (!a1.getRule().equals(a2.getRule())) { 817 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2"); 818 } 819 820 // AnnualTimeZoneRule#getStartYear 821 int startYear = a1.getStartYear(); 822 if (startYear != 2000) { 823 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear); 824 } 825 826 // AnnualTimeZoneRule#getEndYear 827 int endYear = a1.getEndYear(); 828 if (endYear != AnnualTimeZoneRule.MAX_YEAR) { 829 errln("FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear); 830 } 831 endYear = a3.getEndYear(); 832 if (endYear != 2010) { 833 errln("FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear); 834 } 835 836 // AnnualTimeZone#getStartInYear 837 Date d1 = a1.getStartInYear(2005, -3*HOUR, 0); 838 Date d2 = a3.getStartInYear(2005, -3*HOUR, 0); 839 if (d1 == null || d2 == null || !d1.equals(d2)) { 840 errln("FAIL: AnnualTimeZoneRule#getStartInYear did not work as expected"); 841 } 842 d2 = a3.getStartInYear(2015, -3*HOUR, 0); 843 if (d2 != null) { 844 errln("FAIL: AnnualTimeZoneRule#getSTartInYear returned non-null date for 2015 which is out of rule range"); 845 } 846 847 // AnnualTimeZone#getFirstStart 848 d1 = a1.getFirstStart(-3*HOUR, 0); 849 d2 = a1.getFirstStart(-4*HOUR, 1*HOUR); 850 if (d1 == null || d2 == null || !d1.equals(d2)) { 851 errln("FAIL: The same start time should be returned by getFirstStart"); 852 } 853 854 // AnnualTimeZone#getFinalStart 855 d1 = a1.getFinalStart(-3*HOUR, 0); 856 if (d1 != null) { 857 errln("FAIL: Non-null Date is returned by getFinalStart for a1"); 858 } 859 d1 = a1.getStartInYear(2010, -3*HOUR, 0); 860 d2 = a3.getFinalStart(-3*HOUR, 0); 861 if (d1 == null || d2 == null || !d1.equals(d2)) { 862 errln("FAIL: Bad date is returned by getFinalStart"); 863 } 864 865 // AnnualTimeZone#getNextStart / getPreviousStart 866 d1 = a1.getNextStart(time1, -3*HOUR, 0, false); 867 if (d1 == null) { 868 errln("FAIL: Null Date is returned by getNextStart"); 869 } else { 870 d2 = a1.getPreviousStart(d1.getTime(), -3*HOUR, 0, true); 871 if (d2 == null || !d1.equals(d2)) { 872 errln("FAIL: Bad Date is returned by getPreviousStart"); 873 } 874 } 875 d1 = a3.getNextStart(time2, -3*HOUR, 0, false); 876 if (d1 != null) { 877 errln("FAIL: getNextStart must return null when no start time is available after the base time"); 878 } 879 d1 = a3.getFinalStart(-3*HOUR, 0); 880 d2 = a3.getPreviousStart(time2, -3*HOUR, 0, false); 881 if (d1 == null || d2 == null || !d1.equals(d2)) { 882 errln("FAIL: getPreviousStart does not match with getFinalStart after the end year"); 883 } 884 885 // AnnualTimeZone#isEquavalentTo 886 if (!a1.isEquivalentTo(a2)) { 887 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned false"); 888 } 889 if (a1.isEquivalentTo(a3)) { 890 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned true"); 891 } 892 if (!a1.isEquivalentTo(a1)) { 893 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned false"); 894 } 895 if (a1.isEquivalentTo(t1)) { 896 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned true"); 897 } 898 899 // AnnualTimeZone#isTransitionRule 900 if (!a1.isTransitionRule()) { 901 errln("FAIL: An AnnualTimeZoneRule is a transition rule, but returned false"); 902 } 903 904 // AnnualTimeZone#toString 905 String str = a1.toString(); 906 if (str == null || str.length() == 0) { 907 errln("FAIL: AnnualTimeZoneRule#toString for a1 returns null or empty string"); 908 } else { 909 logln("AnnualTimeZoneRule a1 : " + str); 910 } 911 str = a3.toString(); 912 if (str == null || str.length() == 0) { 913 errln("FAIL: AnnualTimeZoneRule#toString for a3 returns null or empty string"); 914 } else { 915 logln("AnnualTimeZoneRule a3 : " + str); 916 } 917 918 // InitialTimeZoneRule#isEquivalentRule 919 if (!i1.isEquivalentTo(i2)) { 920 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned false"); 921 } 922 if (i1.isEquivalentTo(i3)) { 923 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned true"); 924 } 925 if (i1.isEquivalentTo(a1)) { 926 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned true"); 927 } 928 929 // InitialTimeZoneRule#getFirstStart/getFinalStart/getNextStart/getPreviousStart 930 d1 = i1.getFirstStart(0, 0); 931 if (d1 != null) { 932 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFirstStart"); 933 } 934 d1 = i1.getFinalStart(0, 0); 935 if (d1 != null) { 936 errln("FAIL: Non-null Date is returned by InitialTimeZone#getFinalStart"); 937 } 938 d1 = i1.getNextStart(time1, 0, 0, false); 939 if (d1 != null) { 940 errln("FAIL: Non-null Date is returned by InitialTimeZone#getNextStart"); 941 } 942 d1 = i1.getPreviousStart(time1, 0, 0, false); 943 if (d1 != null) { 944 errln("FAIL: Non-null Date is returned by InitialTimeZone#getPreviousStart"); 945 } 946 947 // InitialTimeZoneRule#isTransitionRule 948 if (i1.isTransitionRule()) { 949 errln("FAIL: An InitialTimeZoneRule is not a transition rule, but returned true"); 950 } 951 952 // InitialTimeZoneRule#toString 953 str = i1.toString(); 954 if (str == null || str.length() == 0) { 955 errln("FAIL: InitialTimeZoneRule#toString returns null or empty string"); 956 } else { 957 logln("InitialTimeZoneRule i1 : " + str); 958 } 959 960 961 // TimeArrayTimeZoneRule#getStartTimes 962 long[] times = t1.getStartTimes(); 963 if (times == null || times.length == 0 || times[0] != 0) { 964 errln("FAIL: Bad start times are returned by TimeArrayTimeZoneRule#getStartTimes"); 965 } 966 967 // TimeArrayTimeZoneRule#getTimeType 968 if (t1.getTimeType() != DateTimeRule.UTC_TIME) { 969 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned"); 970 } 971 if (t4.getTimeType() != DateTimeRule.STANDARD_TIME) { 972 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned"); 973 } 974 if (t5.getTimeType() != DateTimeRule.WALL_TIME) { 975 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned"); 976 } 977 978 // TimeArrayTimeZoneRule#getFirstStart/getFinalStart 979 d1 = t1.getFirstStart(0, 0); 980 if (d1 == null || d1.getTime() != trtimes1[0]) { 981 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1"); 982 } 983 d1 = t1.getFinalStart(0, 0); 984 if (d1 == null || d1.getTime() != trtimes1[0]) { 985 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1"); 986 } 987 d1 = t4.getFirstStart(-4*HOUR, 1*HOUR); 988 if (d1 == null || (d1.getTime() != trtimes1[0] + 4*HOUR)) { 989 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4"); 990 } 991 d1 = t5.getFirstStart(-4*HOUR, 1*HOUR); 992 if (d1 == null || (d1.getTime() != trtimes1[0] + 3*HOUR)) { 993 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5"); 994 } 995 996 // TimeArrayTimeZoneRule#getNextStart/getPreviousStart 997 d1 = t3.getNextStart(time1, -3*HOUR, 1*HOUR, false); 998 if (d1 != null) { 999 errln("FAIL: Non-null Date is returned by getNextStart after the final transition for t3"); 1000 } 1001 d1 = t3.getPreviousStart(time1, -3*HOUR, 1*HOUR, false); 1002 if (d1 == null || d1.getTime() != trtimes2[1]) { 1003 errln("FAIL: Bad start time returned by getPreviousStart for t3"); 1004 } else { 1005 d2 = t3.getPreviousStart(d1.getTime(), -3*HOUR, 1*HOUR, false); 1006 if (d2 == null || d2.getTime() != trtimes2[0]) { 1007 errln("FAIL: Bad start time returned by getPreviousStart for t3"); 1008 } 1009 } 1010 d1 = t3.getPreviousStart(time3, -3*HOUR, 1*HOUR, false); //time3 - year 1950, no result expected 1011 if (d1 != null) { 1012 errln("FAIL: Non-null Date is returned by getPrevoousStart for t3"); 1013 } 1014 1015 // TimeArrayTimeZoneRule#isEquivalentTo 1016 if (!t1.isEquivalentTo(t2)) { 1017 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned false"); 1018 } 1019 if (t1.isEquivalentTo(t3)) { 1020 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned true"); 1021 } 1022 if (t1.isEquivalentTo(t4)) { 1023 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned true"); 1024 } 1025 if (t1.isEquivalentTo(a1)) { 1026 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned true"); 1027 } 1028 1029 // TimeArrayTimeZoneRule#isTransitionRule 1030 if (!t1.isTransitionRule()) { 1031 errln("FAIL: A TimeArrayTimeZoneRule is a transition rule, but returned false"); 1032 } 1033 1034 // TimeArrayTimeZoneRule#toString 1035 str = t3.toString(); 1036 if (str == null || str.length() == 0) { 1037 errln("FAIL: TimeArrayTimeZoneRule#toString returns null or empty string"); 1038 } else { 1039 logln("TimeArrayTimeZoneRule t3 : " + str); 1040 } 1041 1042 // DateTimeRule#toString 1043 str = dtr1.toString(); 1044 if (str == null || str.length() == 0) { 1045 errln("FAIL: DateTimeRule#toString for dtr1 returns null or empty string"); 1046 } else { 1047 logln("DateTimeRule dtr1 : " + str); 1048 } 1049 str = dtr2.toString(); 1050 if (str == null || str.length() == 0) { 1051 errln("FAIL: DateTimeRule#toString for dtr2 returns null or empty string"); 1052 } else { 1053 logln("DateTimeRule dtr1 : " + str); 1054 } 1055 str = dtr3.toString(); 1056 if (str == null || str.length() == 0) { 1057 errln("FAIL: DateTimeRule#toString for dtr3 returns null or empty string"); 1058 } else { 1059 logln("DateTimeRule dtr1 : " + str); 1060 } 1061 str = dtr4.toString(); 1062 if (str == null || str.length() == 0) { 1063 errln("FAIL: DateTimeRule#toString for dtr4 returns null or empty string"); 1064 } else { 1065 logln("DateTimeRule dtr1 : " + str); 1066 } 1067 } 1068 1069 /* 1070 * API coverage test for BasicTimeZone APIs in SimpleTimeZone 1071 */ 1072 @Test TestSimpleTimeZoneCoverage()1073 public void TestSimpleTimeZoneCoverage() { 1074 1075 long time1 = getUTCMillis(1990, Calendar.JUNE, 1); 1076 long time2 = getUTCMillis(2000, Calendar.JUNE, 1); 1077 1078 TimeZoneTransition tzt1, tzt2; 1079 1080 // BasicTimeZone API implementation in SimpleTimeZone 1081 SimpleTimeZone stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5"); 1082 1083 tzt1 = stz1.getNextTransition(time1, false); 1084 if (tzt1 != null) { 1085 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule"); 1086 } 1087 tzt1 = stz1.getPreviousTransition(time1, false); 1088 if (tzt1 != null) { 1089 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule"); 1090 } 1091 TimeZoneRule[] tzrules = stz1.getTimeZoneRules(); 1092 if (tzrules.length != 1 || !(tzrules[0] instanceof InitialTimeZoneRule)) { 1093 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules"); 1094 } 1095 1096 // Set DST rule 1097 stz1.setStartRule(Calendar.MARCH, 11, 2*HOUR); // March 11 1098 stz1.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2*HOUR); // First Sunday in November 1099 tzt1 = stz1.getNextTransition(time1, false); 1100 if (tzt1 == null) { 1101 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule"); 1102 } else { 1103 String str = tzt1.toString(); 1104 if (str == null || str.length() == 0) { 1105 errln("FAIL: TimeZoneTransition#toString returns null or empty string"); 1106 } else { 1107 logln(str); 1108 } 1109 } 1110 tzt1 = stz1.getPreviousTransition(time1, false); 1111 if (tzt1 == null) { 1112 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule"); 1113 } 1114 tzrules = stz1.getTimeZoneRules(); 1115 if (tzrules.length != 3 || !(tzrules[0] instanceof InitialTimeZoneRule) 1116 || !(tzrules[1] instanceof AnnualTimeZoneRule) 1117 || !(tzrules[2] instanceof AnnualTimeZoneRule)) { 1118 errln("FAIL: Invalid results returned by SimpleTimeZone#getTimeZoneRules for a SimpleTimeZone with DST"); 1119 } 1120 // Set DST start year 1121 stz1.setStartYear(2007); 1122 tzt1 = stz1.getPreviousTransition(time1, false); 1123 if (tzt1 != null) { 1124 errln("FAIL: No transition must be returned before 1990"); 1125 } 1126 tzt1 = stz1.getNextTransition(time1, false); // transition after 1990-06-01 1127 tzt2 = stz1.getNextTransition(time2, false); // transition after 2000-06-01 1128 if (tzt1 == null || tzt2 == null || !tzt1.equals(tzt2)) { 1129 errln("FAIL: Bad transition returned by SimpleTimeZone#getNextTransition"); 1130 } 1131 } 1132 1133 /* 1134 * API coverage test for VTimeZone 1135 */ 1136 @Test TestVTimeZoneCoverage()1137 public void TestVTimeZoneCoverage() { 1138 final String TZID = "Europe/Moscow"; 1139 BasicTimeZone otz = (BasicTimeZone)TimeZone.getTimeZone(TZID, TimeZone.TIMEZONE_ICU); 1140 VTimeZone vtz = VTimeZone.create(TZID); 1141 1142 // getOffset(era, year, month, day, dayOfWeek, milliseconds) 1143 int offset1 = otz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0); 1144 int offset2 = vtz.getOffset(GregorianCalendar.AD, 2007, Calendar.JULY, 1, Calendar.SUNDAY, 0); 1145 if (offset1 != offset2) { 1146 errln("FAIL: getOffset(int,int,int,int,int,int) returned different results in VTimeZone and OlsonTimeZone"); 1147 } 1148 1149 // getOffset(date, local, offsets) 1150 int[] offsets1 = new int[2]; 1151 int[] offsets2 = new int[2]; 1152 long t = System.currentTimeMillis(); 1153 otz.getOffset(t, false, offsets1); 1154 vtz.getOffset(t, false, offsets2); 1155 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) { 1156 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone"); 1157 } 1158 1159 // getRawOffset 1160 if (otz.getRawOffset() != vtz.getRawOffset()) { 1161 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone"); 1162 } 1163 1164 // inDaylightTime 1165 Date d = new Date(); 1166 if (otz.inDaylightTime(d) != vtz.inDaylightTime(d)) { 1167 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone"); 1168 } 1169 1170 // useDaylightTime 1171 if (otz.useDaylightTime() != vtz.useDaylightTime()) { 1172 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone"); 1173 } 1174 1175 // setRawOffset 1176 final int RAW = -10*HOUR; 1177 VTimeZone tmpvtz = (VTimeZone)vtz.clone(); 1178 tmpvtz.setRawOffset(RAW); 1179 if (tmpvtz.getRawOffset() != RAW) { 1180 logln("setRawOffset is implemented"); 1181 } 1182 1183 // hasSameRules 1184 boolean bSame = otz.hasSameRules(vtz); 1185 logln("OlsonTimeZone#hasSameRules(VTimeZone) should return false always for now - actual: " + bSame); 1186 1187 // getTZURL/setTZURL 1188 final String TZURL = "http://icu-project.org/timezone"; 1189 String tzurl = vtz.getTZURL(); 1190 if (tzurl != null) { 1191 errln("FAIL: getTZURL returned non-null value"); 1192 } 1193 vtz.setTZURL(TZURL); 1194 tzurl = vtz.getTZURL(); 1195 if (!TZURL.equals(tzurl)) { 1196 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL"); 1197 } 1198 1199 // getLastModified/setLastModified 1200 Date lastmod = vtz.getLastModified(); 1201 if (lastmod != null) { 1202 errln("FAIL: getLastModified returned non-null value"); 1203 } 1204 Date newdate = new Date(); 1205 vtz.setLastModified(newdate); 1206 lastmod = vtz.getLastModified(); 1207 if (!newdate.equals(lastmod)) { 1208 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified"); 1209 } 1210 1211 // getNextTransition/getPreviousTransition 1212 long base = getUTCMillis(2007, Calendar.JULY, 1); 1213 TimeZoneTransition tzt1 = otz.getNextTransition(base, true); 1214 TimeZoneTransition tzt2 = vtz.getNextTransition(base, true); 1215 if (tzt1.equals(tzt2)) { 1216 errln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone"); 1217 } 1218 tzt1 = otz.getPreviousTransition(base, false); 1219 tzt2 = vtz.getPreviousTransition(base, false); 1220 if (tzt1.equals(tzt2)) { 1221 errln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone"); 1222 } 1223 1224 // hasEquivalentTransitions 1225 long time1 = getUTCMillis(1950, Calendar.JANUARY, 1); 1226 long time2 = getUTCMillis(2020, Calendar.JANUARY, 1); 1227 if (!vtz.hasEquivalentTransitions(otz, time1, time2)) { 1228 errln("FAIL: hasEquivalentTransitons returned false for the same time zone"); 1229 } 1230 1231 // getTimeZoneRules 1232 TimeZoneRule[] rulesetAll = vtz.getTimeZoneRules(); 1233 TimeZoneRule[] ruleset1 = vtz.getTimeZoneRules(time1); 1234 TimeZoneRule[] ruleset2 = vtz.getTimeZoneRules(time2); 1235 if (rulesetAll.length < ruleset1.length || ruleset1.length < ruleset2.length) { 1236 errln("FAIL: Number of rules returned by getRules is invalid"); 1237 } 1238 1239 int[] offsets_vtzc = new int[2]; 1240 VTimeZone vtzc = VTimeZone.create("PST"); 1241 vtzc.getOffsetFromLocal(Calendar.getInstance(vtzc).getTimeInMillis(), VTimeZone.LOCAL_STD, VTimeZone.LOCAL_STD, offsets_vtzc); 1242 if (offsets_vtzc[0] > offsets_vtzc[1]) { 1243 errln("Error getOffsetFromLocal()"); 1244 } 1245 } 1246 1247 @Test TestVTimeZoneParse()1248 public void TestVTimeZoneParse() { 1249 // Trying to create VTimeZone from empty data 1250 StringReader r = new StringReader(""); 1251 VTimeZone empty = VTimeZone.create(r); 1252 if (empty != null) { 1253 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data"); 1254 } 1255 1256 // Create VTimeZone for Asia/Tokyo 1257 String asiaTokyo = 1258 "BEGIN:VTIMEZONE\r\n" + 1259 "TZID:Asia\r\n" + 1260 "\t/Tokyo\r\n" + 1261 "BEGIN:STANDARD\r\n" + 1262 "TZOFFSETFROM:+0900\r\n" + 1263 "TZOFFSETTO:+0900\r\n" + 1264 "TZNAME:JST\r\n" + 1265 "DTSTART:19700101\r\n" + 1266 " T000000\r\n" + 1267 "END:STANDARD\r\n" + 1268 "END:VTIMEZONE"; 1269 r = new StringReader(asiaTokyo); 1270 VTimeZone tokyo = VTimeZone.create(r); 1271 if (tokyo == null) { 1272 errln("FAIL: Failed to create a VTimeZone tokyo"); 1273 } else { 1274 // Make sure offsets are correct 1275 int[] offsets = new int[2]; 1276 tokyo.getOffset(System.currentTimeMillis(), false, offsets); 1277 if (offsets[0] != 9*HOUR || offsets[1] != 0) { 1278 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo"); 1279 } 1280 } 1281 1282 // Create VTimeZone from VTIMEZONE data 1283 String fooData = 1284 "BEGIN:VCALENDAR\r\n" + 1285 "BEGIN:VTIMEZONE\r\n" + 1286 "TZID:FOO\r\n" + 1287 "BEGIN:STANDARD\r\n" + 1288 "TZOFFSETFROM:-0700\r\n" + 1289 "TZOFFSETTO:-0800\r\n" + 1290 "TZNAME:FST\r\n" + 1291 "DTSTART:20071010T010000\r\n" + 1292 "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\r\n" + 1293 "END:STANDARD\r\n" + 1294 "BEGIN:DAYLIGHT\r\n" + 1295 "TZOFFSETFROM:-0800\r\n" + 1296 "TZOFFSETTO:-0700\r\n" + 1297 "TZNAME:FDT\r\n" + 1298 "DTSTART:20070415T010000\r\n" + 1299 "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\r\n" + 1300 "END:DAYLIGHT\r\n" + 1301 "END:VTIMEZONE\r\n" + 1302 "END:VCALENDAR"; 1303 1304 r = new StringReader(fooData); 1305 VTimeZone foo = VTimeZone.create(r); 1306 if (foo == null) { 1307 errln("FAIL: Failed to create a VTimeZone foo"); 1308 } else { 1309 // Write VTIMEZONE data 1310 StringWriter w = new StringWriter(); 1311 try { 1312 foo.write(w, getUTCMillis(2005, Calendar.JANUARY, 1)); 1313 } catch (IOException ioe) { 1314 errln("FAIL: IOException is thrown while writing VTIMEZONE data for foo"); 1315 } 1316 logln(w.toString()); 1317 } 1318 } 1319 1320 @Test TestT6216()1321 public void TestT6216() { 1322 // Test case in #6216 1323 String tokyoTZ = 1324 "BEGIN:VCALENDAR\r\n" + 1325 "VERSION:2.0\r\n" + 1326 "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" + 1327 "BEGIN:VTIMEZONE\r\n" + 1328 "TZID:Asia/Tokyo\r\n" + 1329 "BEGIN:STANDARD\r\n" + 1330 "DTSTART:20000101T000000\r\n" + 1331 "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" + 1332 "TZNAME:Asia/Tokyo\r\n" + 1333 "TZOFFSETFROM:+0900\r\n" + 1334 "TZOFFSETTO:+0900\r\n" + 1335 "END:STANDARD\r\n" + 1336 "END:VTIMEZONE\r\n" + 1337 "END:VCALENDAR"; 1338 1339 // Single final rule, overlapping with another 1340 String finalOverlap = 1341 "BEGIN:VCALENDAR\r\n" + 1342 "BEGIN:VTIMEZONE\r\n" + 1343 "TZID:FinalOverlap\r\n" + 1344 "BEGIN:STANDARD\r\n" + 1345 "TZOFFSETFROM:-0200\r\n" + 1346 "TZOFFSETTO:-0300\r\n" + 1347 "TZNAME:STD\r\n" + 1348 "DTSTART:20001029T020000\r\n" + 1349 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" + 1350 "END:STANDARD\r\n" + 1351 "BEGIN:DAYLIGHT\r\n" + 1352 "TZOFFSETFROM:-0300\r\n" + 1353 "TZOFFSETTO:-0200\r\n" + 1354 "TZNAME:DST\r\n" + 1355 "DTSTART:19990404T020000\r\n" + 1356 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" + 1357 "END:DAYLIGHT\r\n" + 1358 "END:VTIMEZONE\r\n" + 1359 "END:VCALENDAR"; 1360 1361 // Single final rule, no overlapping with another 1362 String finalNonOverlap = 1363 "BEGIN:VCALENDAR\r\n" + 1364 "BEGIN:VTIMEZONE\r\n" + 1365 "TZID:FinalNonOverlap\r\n" + 1366 "BEGIN:STANDARD\r\n" + 1367 "TZOFFSETFROM:-0200\r\n" + 1368 "TZOFFSETTO:-0300\r\n" + 1369 "TZNAME:STD\r\n" + 1370 "DTSTART:20001029T020000\r\n" + 1371 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" + 1372 "END:STANDARD\r\n" + 1373 "BEGIN:DAYLIGHT\r\n" + 1374 "TZOFFSETFROM:-0300\r\n" + 1375 "TZOFFSETTO:-0200\r\n" + 1376 "TZNAME:DST\r\n" + 1377 "DTSTART:19990404T020000\r\n" + 1378 "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" + 1379 "END:DAYLIGHT\r\n" + 1380 "BEGIN:STANDARD\r\n" + 1381 "TZOFFSETFROM:-0200\r\n" + 1382 "TZOFFSETTO:-0300\r\n" + 1383 "TZNAME:STDFINAL\r\n" + 1384 "DTSTART:20071028T020000\r\n" + 1385 "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" + 1386 "END:STANDARD\r\n" + 1387 "END:VTIMEZONE\r\n" + 1388 "END:VCALENDAR"; 1389 1390 int[][] TestDates = { 1391 {1995, Calendar.JANUARY, 1}, 1392 {1995, Calendar.JULY, 1}, 1393 {2000, Calendar.JANUARY, 1}, 1394 {2000, Calendar.JULY, 1}, 1395 {2005, Calendar.JANUARY, 1}, 1396 {2005, Calendar.JULY, 1}, 1397 {2010, Calendar.JANUARY, 1}, 1398 {2010, Calendar.JULY, 1}, 1399 }; 1400 1401 String[] TestZones = { 1402 tokyoTZ, 1403 finalOverlap, 1404 finalNonOverlap, 1405 }; 1406 1407 int[][] Expected = { 1408 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10 1409 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000}, 1410 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000}, 1411 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000}, 1412 }; 1413 1414 // Get test times 1415 long[] times = new long[TestDates.length]; 1416 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT")); 1417 for (int i = 0; i < TestDates.length; i++) { 1418 cal.clear(); 1419 cal.set(TestDates[i][0], TestDates[i][1], TestDates[i][2]); 1420 times[i] = cal.getTimeInMillis(); 1421 } 1422 1423 for (int i = 0; i < TestZones.length; i++) { 1424 try { 1425 VTimeZone vtz = VTimeZone.create(new StringReader(TestZones[i])); 1426 for (int j = 0; j < times.length; j++) { 1427 int offset = vtz.getOffset(times[j]); 1428 if (offset != Expected[i][j]) { 1429 errln("FAIL: Invalid offset at time(" + times[j] + "):" + offset + " Expected:" + Expected[i][j]); 1430 } 1431 } 1432 } catch (Exception e) { 1433 errln("FAIL: Failed to calculate the offset for VTIMEZONE data " + i); 1434 } 1435 } 1436 } 1437 1438 @Test TestT6669()1439 public void TestT6669() { 1440 // getNext/PreviousTransition implementation in SimpleTimeZone 1441 // used to use a bad condition for detecting if DST is enabled or not. 1442 1443 SimpleTimeZone stz = new SimpleTimeZone(0, "CustomID", 1444 Calendar.JANUARY, 1, Calendar.SUNDAY, 0, 1445 Calendar.JULY, 1, Calendar.SUNDAY, 0); 1446 1447 long t = 1230681600000L; //2008-12-31T00:00:00 1448 long expectedNext = 1231027200000L; //2009-01-04T00:00:00 1449 long expectedPrev = 1215298800000L; //2008-07-06T00:00:00 1450 1451 TimeZoneTransition tzt = stz.getNextTransition(t, false); 1452 if (tzt == null) { 1453 errln("FAIL: No transition returned by getNextTransition."); 1454 } else if (tzt.getTime() != expectedNext){ 1455 errln("FAIL: Wrong transition time returned by getNextTransition - " 1456 + tzt.getTime() + " Expected: " + expectedNext); 1457 } 1458 1459 tzt = stz.getPreviousTransition(t, true); 1460 if (tzt == null) { 1461 errln("FAIL: No transition returned by getPreviousTransition."); 1462 } else if (tzt.getTime() != expectedPrev){ 1463 errln("FAIL: Wrong transition time returned by getPreviousTransition - " 1464 + tzt.getTime() + " Expected: " + expectedPrev); 1465 } 1466 } 1467 1468 @Test TestBasicTimeZoneCoverage()1469 public void TestBasicTimeZoneCoverage() { 1470 TimeZone tz = TimeZone.getTimeZone("PST"); 1471 if (tz instanceof BasicTimeZone) { 1472 BasicTimeZone btz = (BasicTimeZone)tz; 1473 int []offsets = new int[2]; 1474 1475 btz.getOffsetFromLocal(Calendar.getInstance().getTimeInMillis(), BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets); 1476 if (offsets[0] > offsets[1]) { 1477 errln("Error calling getOffsetFromLocal()."); 1478 } 1479 } else { 1480 logln("Skipping TestBasicTimeZoneCoverage: ICU4J is configured to use JDK TimeZone"); 1481 } 1482 } 1483 1484 // Internal utility methods ----------------------------------------- 1485 1486 /* 1487 * Check if a time shift really happens on each transition returned by getNextTransition or 1488 * getPreviousTransition in the specified time range 1489 */ verifyTransitions(TimeZone tz, long start, long end)1490 private void verifyTransitions(TimeZone tz, long start, long end) { 1491 BasicTimeZone icutz = (BasicTimeZone)tz; 1492 long time; 1493 int[] before = new int[2]; 1494 int[] after = new int[2]; 1495 TimeZoneTransition tzt0; 1496 1497 // Ascending 1498 tzt0 = null; 1499 time = start; 1500 while(true) { 1501 TimeZoneTransition tzt = icutz.getNextTransition(time, false); 1502 1503 if (tzt == null) { 1504 break; 1505 } 1506 time = tzt.getTime(); 1507 if (time >= end) { 1508 break; 1509 } 1510 icutz.getOffset(time, false, after); 1511 icutz.getOffset(time - 1, false, before); 1512 1513 if (after[0] == before[0] && after[1] == before[1]) { 1514 errln("FAIL: False transition returned by getNextTransition for " + icutz.getID() + " at " + time); 1515 } 1516 if (tzt0 != null && 1517 (tzt0.getTo().getRawOffset() != tzt.getFrom().getRawOffset() 1518 || tzt0.getTo().getDSTSavings() != tzt.getFrom().getDSTSavings())) { 1519 errln("FAIL: TO rule of the previous transition does not match FROM rule of this transtion at " 1520 + time + " for " + icutz.getID()); 1521 } 1522 tzt0 = tzt; 1523 } 1524 1525 // Descending 1526 tzt0 = null; 1527 time = end; 1528 while(true) { 1529 TimeZoneTransition tzt = icutz.getPreviousTransition(time, false); 1530 if (tzt == null) { 1531 break; 1532 } 1533 time = tzt.getTime(); 1534 if (time <= start) { 1535 break; 1536 } 1537 icutz.getOffset(time, false, after); 1538 icutz.getOffset(time - 1, false, before); 1539 1540 if (after[0] == before[0] && after[1] == before[1]) { 1541 errln("FAIL: False transition returned by getPreviousTransition for " + icutz.getID() + " at " + time); 1542 } 1543 1544 if (tzt0 != null && 1545 (tzt0.getFrom().getRawOffset() != tzt.getTo().getRawOffset() 1546 || tzt0.getFrom().getDSTSavings() != tzt.getTo().getDSTSavings())) { 1547 errln("FAIL: TO rule of the next transition does not match FROM rule in this transtion at " 1548 + time + " for " + icutz.getID()); 1549 } 1550 tzt0 = tzt; 1551 } 1552 } 1553 1554 /* 1555 * Compare all time transitions in 2 time zones in the specified time range in ascending order 1556 */ compareTransitionsAscending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive)1557 private void compareTransitionsAscending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) { 1558 BasicTimeZone z1 = (BasicTimeZone)tz1; 1559 BasicTimeZone z2 = (BasicTimeZone)tz2; 1560 String zid1 = tz1.getID(); 1561 String zid2 = tz2.getID(); 1562 1563 long time = start; 1564 while(true) { 1565 TimeZoneTransition tzt1 = z1.getNextTransition(time, inclusive); 1566 TimeZoneTransition tzt2 = z2.getNextTransition(time, inclusive); 1567 boolean inRange1 = false; 1568 boolean inRange2 = false; 1569 if (tzt1 != null) { 1570 if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) { 1571 inRange1 = true; 1572 } 1573 } 1574 if (tzt2 != null) { 1575 if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) { 1576 inRange2 = true; 1577 } 1578 } 1579 if (!inRange1 && !inRange2) { 1580 // No more transition in the range 1581 break; 1582 } 1583 if (!inRange1) { 1584 errln("FAIL: " + zid1 + " does not have any transitions after " + time + " before " + end); 1585 break; 1586 } 1587 if (!inRange2) { 1588 errln("FAIL: " + zid2 + " does not have any transitions after " + time + " before " + end); 1589 break; 1590 } 1591 if (tzt1.getTime() != tzt2.getTime()) { 1592 errln("FAIL: First transition after " + time + " " 1593 + zid1 + "[" + tzt1.getTime() + "] " 1594 + zid2 + "[" + tzt2.getTime() + "]"); 1595 break; 1596 } 1597 time = tzt1.getTime(); 1598 if (inclusive) { 1599 time++; 1600 } 1601 } 1602 } 1603 1604 /* 1605 * Compare all time transitions in 2 time zones in the specified time range in descending order 1606 */ compareTransitionsDescending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive)1607 private void compareTransitionsDescending(TimeZone tz1, TimeZone tz2, long start, long end, boolean inclusive) { 1608 BasicTimeZone z1 = (BasicTimeZone)tz1; 1609 BasicTimeZone z2 = (BasicTimeZone)tz2; 1610 String zid1 = tz1.getID(); 1611 String zid2 = tz2.getID(); 1612 long time = end; 1613 while(true) { 1614 TimeZoneTransition tzt1 = z1.getPreviousTransition(time, inclusive); 1615 TimeZoneTransition tzt2 = z2.getPreviousTransition(time, inclusive); 1616 boolean inRange1 = false; 1617 boolean inRange2 = false; 1618 if (tzt1 != null) { 1619 if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) { 1620 inRange1 = true; 1621 } 1622 } 1623 if (tzt2 != null) { 1624 if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) { 1625 inRange2 = true; 1626 } 1627 } 1628 if (!inRange1 && !inRange2) { 1629 // No more transition in the range 1630 break; 1631 } 1632 if (!inRange1) { 1633 errln("FAIL: " + zid1 + " does not have any transitions before " + time + " after " + start); 1634 break; 1635 } 1636 if (!inRange2) { 1637 errln("FAIL: " + zid2 + " does not have any transitions before " + time + " after " + start); 1638 break; 1639 } 1640 if (tzt1.getTime() != tzt2.getTime()) { 1641 errln("FAIL: Last transition before " + time + " " 1642 + zid1 + "[" + tzt1.getTime() + "] " 1643 + zid2 + "[" + tzt2.getTime() + "]"); 1644 break; 1645 } 1646 time = tzt1.getTime(); 1647 if (inclusive) { 1648 time--; 1649 } 1650 } 1651 } 1652 1653 private static final String[] TESTZIDS = { 1654 "AGT", 1655 "America/New_York", 1656 "America/Los_Angeles", 1657 "America/Indiana/Indianapolis", 1658 "America/Havana", 1659 "Europe/Lisbon", 1660 "Europe/Paris", 1661 "Asia/Tokyo", 1662 "Asia/Sakhalin", 1663 "Africa/Cairo", 1664 "Africa/Windhoek", 1665 "Australia/Sydney", 1666 "Etc/GMT+8", 1667 "Asia/Amman", 1668 }; 1669 getTestZIDs()1670 private String[] getTestZIDs() { 1671 if (TestFmwk.getExhaustiveness() > 5) { 1672 return TimeZone.getAvailableIDs(); 1673 } 1674 return TESTZIDS; 1675 } 1676 1677 private static final int[][] TESTYEARS = { 1678 {1895, 1905}, // including int32 minimum second 1679 {1965, 1975}, // including the epoch 1680 {1995, 2015} // practical year range 1681 }; 1682 getTestTimeRange(int idx)1683 private long[] getTestTimeRange(int idx) { 1684 int loyear, hiyear; 1685 if (idx < TESTYEARS.length) { 1686 loyear = TESTYEARS[idx][0]; 1687 hiyear = TESTYEARS[idx][1]; 1688 } else if (idx == TESTYEARS.length && TestFmwk.getExhaustiveness() > 5) { 1689 loyear = 1850; 1690 hiyear = 2050; 1691 } else { 1692 return null; 1693 } 1694 1695 long[] times = new long[2]; 1696 times[0] = getUTCMillis(loyear, Calendar.JANUARY, 1); 1697 times[1] = getUTCMillis(hiyear + 1, Calendar.JANUARY, 1); 1698 1699 return times; 1700 } 1701 1702 private GregorianCalendar utcCal; 1703 getUTCMillis(int year, int month, int dayOfMonth)1704 private long getUTCMillis(int year, int month, int dayOfMonth) { 1705 if (utcCal == null) { 1706 utcCal = new GregorianCalendar(TimeZone.getTimeZone("UTC"), ULocale.ROOT); 1707 } 1708 utcCal.clear(); 1709 utcCal.set(year, month, dayOfMonth); 1710 return utcCal.getTimeInMillis(); 1711 } 1712 1713 /* 1714 * Slightly modified version of BasicTimeZone#hasEquivalentTransitions. 1715 * This version returns true if transition time delta is within the given 1716 * delta range. 1717 */ hasEquivalentTransitions(BasicTimeZone tz1, BasicTimeZone tz2, long start, long end, boolean ignoreDstAmount, int maxTransitionTimeDelta)1718 private static boolean hasEquivalentTransitions(BasicTimeZone tz1, BasicTimeZone tz2, 1719 long start, long end, 1720 boolean ignoreDstAmount, int maxTransitionTimeDelta) { 1721 if (tz1.hasSameRules(tz2)) { 1722 return true; 1723 } 1724 1725 // Check the offsets at the start time 1726 int[] offsets1 = new int[2]; 1727 int[] offsets2 = new int[2]; 1728 1729 tz1.getOffset(start, false, offsets1); 1730 tz2.getOffset(start, false, offsets2); 1731 1732 if (ignoreDstAmount) { 1733 if ((offsets1[0] + offsets1[1] != offsets2[0] + offsets2[1]) 1734 || (offsets1[1] != 0 && offsets2[1] == 0) 1735 || (offsets1[1] == 0 && offsets2[1] != 0)) { 1736 return false; 1737 } 1738 } else { 1739 if (offsets1[0] != offsets2[0] || offsets1[1] != offsets2[1]) { 1740 return false; 1741 } 1742 } 1743 1744 // Check transitions in the range 1745 long time = start; 1746 while (true) { 1747 TimeZoneTransition tr1 = tz1.getNextTransition(time, false); 1748 TimeZoneTransition tr2 = tz2.getNextTransition(time, false); 1749 1750 if (ignoreDstAmount) { 1751 // Skip a transition which only differ the amount of DST savings 1752 while (true) { 1753 if (tr1 != null 1754 && tr1.getTime() <= end 1755 && (tr1.getFrom().getRawOffset() + tr1.getFrom().getDSTSavings() 1756 == tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings()) 1757 && (tr1.getFrom().getDSTSavings() != 0 && tr1.getTo().getDSTSavings() != 0)) { 1758 tr1 = tz1.getNextTransition(tr1.getTime(), false); 1759 } else { 1760 break; 1761 } 1762 } 1763 while (true) { 1764 if (tr2 != null 1765 && tr2.getTime() <= end 1766 && (tr2.getFrom().getRawOffset() + tr2.getFrom().getDSTSavings() 1767 == tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings()) 1768 && (tr2.getFrom().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() != 0)) { 1769 tr2 = tz2.getNextTransition(tr2.getTime(), false); 1770 } else { 1771 break; 1772 } 1773 } } 1774 1775 boolean inRange1 = false; 1776 boolean inRange2 = false; 1777 if (tr1 != null) { 1778 if (tr1.getTime() <= end) { 1779 inRange1 = true; 1780 } 1781 } 1782 if (tr2 != null) { 1783 if (tr2.getTime() <= end) { 1784 inRange2 = true; 1785 } 1786 } 1787 if (!inRange1 && !inRange2) { 1788 // No more transition in the range 1789 break; 1790 } 1791 if (!inRange1 || !inRange2) { 1792 return false; 1793 } 1794 if (Math.abs(tr1.getTime() - tr2.getTime()) > maxTransitionTimeDelta) { 1795 return false; 1796 } 1797 if (ignoreDstAmount) { 1798 if (tr1.getTo().getRawOffset() + tr1.getTo().getDSTSavings() 1799 != tr2.getTo().getRawOffset() + tr2.getTo().getDSTSavings() 1800 || tr1.getTo().getDSTSavings() != 0 && tr2.getTo().getDSTSavings() == 0 1801 || tr1.getTo().getDSTSavings() == 0 && tr2.getTo().getDSTSavings() != 0) { 1802 return false; 1803 } 1804 } else { 1805 if (tr1.getTo().getRawOffset() != tr2.getTo().getRawOffset() || 1806 tr1.getTo().getDSTSavings() != tr2.getTo().getDSTSavings()) { 1807 return false; 1808 } 1809 } 1810 time = tr1.getTime() > tr2.getTime() ? tr1.getTime() : tr2.getTime(); 1811 } 1812 return true; 1813 } 1814 1815 // Test case for ticket#8943 1816 // RuleBasedTimeZone#getOffsets throws NPE 1817 @Test TestT8943()1818 public void TestT8943() { 1819 String id = "Ekaterinburg Time"; 1820 String stdName = "Ekaterinburg Standard Time"; 1821 String dstName = "Ekaterinburg Daylight Time"; 1822 1823 InitialTimeZoneRule initialRule = new InitialTimeZoneRule(stdName, 18000000, 0); 1824 RuleBasedTimeZone rbtz = new RuleBasedTimeZone(id, initialRule); 1825 1826 DateTimeRule dtRule = new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 10800000, DateTimeRule.WALL_TIME); 1827 AnnualTimeZoneRule atzRule = new AnnualTimeZoneRule(stdName, 18000000, 0, dtRule, 2000, 2010); 1828 rbtz.addTransitionRule(atzRule); 1829 1830 dtRule = new DateTimeRule(Calendar.MARCH, -1, Calendar.SUNDAY, 7200000, DateTimeRule.WALL_TIME); 1831 atzRule = new AnnualTimeZoneRule(dstName, 18000000, 3600000, dtRule, 2000, 2010); 1832 rbtz.addTransitionRule(atzRule); 1833 1834 dtRule = new DateTimeRule(Calendar.JANUARY, 1, 0, DateTimeRule.WALL_TIME); 1835 atzRule = new AnnualTimeZoneRule(stdName, 21600000, 0, dtRule, 2011, AnnualTimeZoneRule.MAX_YEAR); 1836 rbtz.addTransitionRule(atzRule); 1837 1838 dtRule = new DateTimeRule(Calendar.JANUARY, 1, 1, DateTimeRule.WALL_TIME); 1839 atzRule = new AnnualTimeZoneRule(dstName, 21600000, 0, dtRule, 2011, AnnualTimeZoneRule.MAX_YEAR); 1840 rbtz.addTransitionRule(atzRule); 1841 1842 int[] expected = {21600000, 0}; 1843 int[] offsets = new int[2]; 1844 try { 1845 rbtz.getOffset(1293822000000L /* 2010-12-31 19:00:00 UTC */, false, offsets); 1846 if (offsets[0] != expected[0] || offsets[1] != expected[1]) { 1847 errln("Fail: Wrong offsets: " + offsets[0] + "/" + offsets[1] + " Expected: " + expected[0] + "/" + expected[1]); 1848 } 1849 } catch (Exception e) { 1850 errln("Fail: Exception thrown - " + e.getMessage()); 1851 } 1852 } 1853 }