1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.text.format.cts; 18 19 import android.content.res.Configuration; 20 import android.content.res.Resources; 21 import android.test.AndroidTestCase; 22 import android.text.format.Time; 23 import android.util.Log; 24 import android.util.TimeFormatException; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Calendar; 29 import java.util.List; 30 import java.util.Locale; 31 import java.util.Objects; 32 import java.util.TimeZone; 33 34 public class TimeTest extends AndroidTestCase { 35 private static final String TAG = "TimeTest"; 36 37 private Locale originalLocale; 38 39 @Override 40 protected void setUp() throws Exception { 41 super.setUp(); 42 originalLocale = Locale.getDefault(); 43 } 44 45 @Override 46 public void tearDown() throws Exception { 47 // The Locale may be changed by tests. Revert to the original. 48 changeJavaAndAndroidLocale(originalLocale); 49 super.tearDown(); 50 } 51 52 public void testConstructor() { 53 Time time = new Time(); 54 new Time(Time.getCurrentTimezone()); 55 time.set(System.currentTimeMillis()); 56 Time anotherTime = new Time(time); 57 assertTime(time, anotherTime); 58 } 59 60 public void testNormalize() { 61 final int expectedMonth = 3; 62 final int expectedDate = 1; 63 Time time = new Time(); 64 // set date to March 32. 65 time.year = 2008; 66 time.month = 2; 67 time.monthDay = 32; 68 long timeMilliseconds = time.normalize(false); 69 Calendar cal = Calendar.getInstance(); 70 cal.setTimeInMillis(timeMilliseconds); 71 assertEquals(2008, cal.get(Calendar.YEAR)); 72 assertEquals(3, cal.get(Calendar.MONTH)); 73 assertEquals(1, cal.get(Calendar.DAY_OF_MONTH)); 74 assertEquals(expectedMonth, time.month); 75 assertEquals(expectedDate, time.monthDay); 76 77 // reset date to March 32. 78 time.month = 2; 79 time.monthDay = 32; 80 assertEquals(timeMilliseconds, time.normalize(true)); 81 assertEquals(expectedMonth, time.month); 82 assertEquals(expectedDate, time.monthDay); 83 } 84 85 public void testSwitchTimezone() { 86 String timeZone = "US/Pacific"; 87 String anotherTimeZone = "Asia/Chongqing"; 88 Time time = new Time(timeZone); 89 assertEquals(timeZone, time.timezone); 90 time.switchTimezone(anotherTimeZone); 91 assertEquals(anotherTimeZone, time.timezone); 92 } 93 94 public void testSet() { 95 final int year = 2008; 96 final int month = 5; 97 final int date = 10; 98 Time time = new Time(); 99 time.set(date, month, year); 100 assertEquals(year, time.year); 101 assertEquals(month, time.month); 102 assertEquals(date, time.monthDay); 103 104 Time anotherTime = new Time(); 105 anotherTime.set(time); 106 assertTime(time, anotherTime); 107 } 108 109 private void assertTime(Time time, Time anotherTime) { 110 assertEquals(time.timezone, anotherTime.timezone); 111 assertEquals(time.allDay, anotherTime.allDay); 112 assertEquals(time.second, anotherTime.second); 113 assertEquals(time.minute, anotherTime.minute); 114 assertEquals(time.hour, anotherTime.hour); 115 assertEquals(time.monthDay, anotherTime.monthDay); 116 assertEquals(time.month, anotherTime.month); 117 assertEquals(time.year, anotherTime.year); 118 assertEquals(time.weekDay, anotherTime.weekDay); 119 assertEquals(time.yearDay, anotherTime.yearDay); 120 assertEquals(time.isDst, anotherTime.isDst); 121 assertEquals(time.gmtoff, anotherTime.gmtoff); 122 } 123 124 public void testGetWeekNumber() { 125 Time time = new Time(); 126 time.normalize(false); 127 time.set(12, 10, 2008); 128 assertEquals(45, time.getWeekNumber()); 129 130 assertEquals("20081112", time.format2445()); 131 132 assertEquals("2008-11-12", time.format3339(true)); 133 assertEquals("2008-11-12T00:00:00.000+00:00", time.format3339(false)); 134 135 Time anotherTime = new Time(); 136 assertTrue(anotherTime.parse3339("2008-11-12T00:00:00.000+00:00")); 137 assertEquals(time.year, anotherTime.year); 138 assertEquals(time.month, anotherTime.month); 139 assertEquals(time.monthDay, anotherTime.monthDay); 140 assertEquals(Time.TIMEZONE_UTC, anotherTime.timezone); 141 142 try { 143 anotherTime.parse3339("2008-111-12T00:00:00.000+00:00"); 144 fail("should throw exception"); 145 } catch (TimeFormatException e) { 146 // expected 147 } 148 } 149 150 public void testParseNull() { 151 Time t = new Time(); 152 try { 153 t.parse(null); 154 fail(); 155 } catch (NullPointerException expected) { 156 } 157 158 try { 159 t.parse3339(null); 160 fail(); 161 } catch (NullPointerException expected) { 162 } 163 } 164 165 // http://code.google.com/p/android/issues/detail?id=16002 166 // We'd leak one JNI global reference each time parsing failed. 167 // This would cause a crash when we filled the global reference table. 168 public void testBug16002() { 169 Time t = new Time(); 170 for (int i = 0; i < 8192; ++i) { 171 try { 172 t.parse3339("xxx"); 173 fail(); 174 } catch (TimeFormatException expected) { 175 } 176 } 177 } 178 179 // http://code.google.com/p/android/issues/detail?id=22225 180 // We'd leak one JNI global reference each time parsing failed. 181 // This would cause a crash when we filled the global reference table. 182 public void testBug22225() { 183 Time t = new Time(); 184 for (int i = 0; i < 8192; ++i) { 185 try { 186 t.parse("xxx"); 187 fail(); 188 } catch (TimeFormatException expected) { 189 } 190 } 191 } 192 193 public void testIsEpoch() { 194 Time time = new Time(); 195 assertTrue(Time.isEpoch(time)); 196 time.set(1, 2, 1970); 197 time.normalize(false); 198 assertFalse(Time.isEpoch(time)); 199 } 200 201 public void testAfterBefore() { 202 Time a = new Time(Time.TIMEZONE_UTC); 203 Time b = new Time("America/Los_Angeles"); 204 assertFalse(a.after(b)); 205 assertTrue(b.after(a)); 206 assertFalse(b.before(a)); 207 assertTrue(a.before(b)); 208 } 209 210 // Below are tests merged from Google 211 private static class DateTest { 212 public int year1; 213 public int month1; 214 public int day1; 215 public int hour1; 216 public int minute1; 217 public int dst1; 218 219 public int delta; 220 221 public int year2; 222 public int month2; 223 public int day2; 224 public int hour2; 225 public int minute2; 226 public int dst2; 227 228 public DateTest(int year1, int month1, int day1, int hour1, int minute1, int dst1, 229 int delta, int year2, int month2, int day2, int hour2, int minute2, 230 int dst2) { 231 this.year1 = year1; 232 this.month1 = month1; 233 this.day1 = day1; 234 this.hour1 = hour1; 235 this.minute1 = minute1; 236 this.dst1 = dst1; 237 this.delta = delta; 238 this.year2 = year2; 239 this.month2 = month2; 240 this.day2 = day2; 241 this.hour2 = hour2; 242 this.minute2 = minute2; 243 this.dst2 = dst2; 244 } 245 246 public DateTest(int year1, int month1, int day1, int hour1, int minute1, 247 int delta, int year2, int month2, int day2, int hour2, int minute2) { 248 this.year1 = year1; 249 this.month1 = month1; 250 this.day1 = day1; 251 this.hour1 = hour1; 252 this.minute1 = minute1; 253 this.dst1 = -1; 254 this.delta = delta; 255 this.year2 = year2; 256 this.month2 = month2; 257 this.day2 = day2; 258 this.hour2 = hour2; 259 this.minute2 = minute2; 260 this.dst2 = -1; 261 } 262 } 263 264 // These tests assume that DST changes on Nov 4, 2007 at 2am (to 1am). 265 266 // The "offset" field in "dayTests" represents days. 267 // Use normalize(true) with these tests to change the date by 1 day. 268 private DateTest[] dayTests = { 269 // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11 270 271 // Nov 4, 12am + 0 day = Nov 4, 12am 272 // Nov 5, 12am + 0 day = Nov 5, 12am 273 new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0), 274 new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0), 275 276 // Nov 3, 12am + 1 day = Nov 4, 12am 277 // Nov 4, 12am + 1 day = Nov 5, 12am 278 // Nov 5, 12am + 1 day = Nov 6, 12am 279 new DateTest(2007, 10, 3, 0, 0, 1, 2007, 10, 4, 0, 0), 280 new DateTest(2007, 10, 4, 0, 0, 1, 2007, 10, 5, 0, 0), 281 new DateTest(2007, 10, 5, 0, 0, 1, 2007, 10, 6, 0, 0), 282 283 // Nov 3, 1am + 1 day = Nov 4, 1am 284 // Nov 4, 1am + 1 day = Nov 5, 1am 285 // Nov 5, 1am + 1 day = Nov 6, 1am 286 new DateTest(2007, 10, 3, 1, 0, 1, 2007, 10, 4, 1, 0), 287 new DateTest(2007, 10, 4, 1, 0, 1, 2007, 10, 5, 1, 0), 288 new DateTest(2007, 10, 5, 1, 0, 1, 2007, 10, 6, 1, 0), 289 290 // Nov 3, 2am + 1 day = Nov 4, 2am 291 // Nov 4, 2am + 1 day = Nov 5, 2am 292 // Nov 5, 2am + 1 day = Nov 6, 2am 293 new DateTest(2007, 10, 3, 2, 0, 1, 2007, 10, 4, 2, 0), 294 new DateTest(2007, 10, 4, 2, 0, 1, 2007, 10, 5, 2, 0), 295 new DateTest(2007, 10, 5, 2, 0, 1, 2007, 10, 6, 2, 0), 296 }; 297 298 // The "offset" field in "minuteTests" represents minutes. 299 // Use normalize(false) with these tests. 300 private DateTest[] minuteTests = { 301 // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11 302 303 // Nov 4, 12am + 0 minutes = Nov 4, 12am 304 // Nov 5, 12am + 0 minutes = Nov 5, 12am 305 new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0), 306 new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0), 307 308 // Nov 3, 12am + 60 minutes = Nov 3, 1am 309 // Nov 4, 12am + 60 minutes = Nov 4, 1am 310 // Nov 5, 12am + 60 minutes = Nov 5, 1am 311 new DateTest(2007, 10, 3, 0, 0, 60, 2007, 10, 3, 1, 0), 312 new DateTest(2007, 10, 4, 0, 0, 60, 2007, 10, 4, 1, 0), 313 new DateTest(2007, 10, 5, 0, 0, 60, 2007, 10, 5, 1, 0), 314 315 // Nov 3, 1am + 60 minutes = Nov 3, 2am 316 // Nov 4, 1am (PDT) + 30 minutes = Nov 4, 1:30am (PDT) 317 // Nov 4, 1am (PDT) + 60 minutes = Nov 4, 1am (PST) 318 new DateTest(2007, 10, 3, 1, 0, 60, 2007, 10, 3, 2, 0), 319 new DateTest(2007, 10, 4, 1, 0, 1, 30, 2007, 10, 4, 1, 30, 1), 320 new DateTest(2007, 10, 4, 1, 0, 1, 60, 2007, 10, 4, 1, 0, 0), 321 322 // Nov 4, 1:30am (PDT) + 15 minutes = Nov 4, 1:45am (PDT) 323 // Nov 4, 1:30am (PDT) + 30 minutes = Nov 4, 1:00am (PST) 324 // Nov 4, 1:30am (PDT) + 60 minutes = Nov 4, 1:30am (PST) 325 new DateTest(2007, 10, 4, 1, 30, 1, 15, 2007, 10, 4, 1, 45, 1), 326 new DateTest(2007, 10, 4, 1, 30, 1, 30, 2007, 10, 4, 1, 0, 0), 327 new DateTest(2007, 10, 4, 1, 30, 1, 60, 2007, 10, 4, 1, 30, 0), 328 329 // Nov 4, 1:30am (PST) + 15 minutes = Nov 4, 1:45am (PST) 330 // Nov 4, 1:30am (PST) + 30 minutes = Nov 4, 2:00am (PST) 331 // Nov 5, 1am + 60 minutes = Nov 5, 2am 332 new DateTest(2007, 10, 4, 1, 30, 0, 15, 2007, 10, 4, 1, 45, 0), 333 new DateTest(2007, 10, 4, 1, 30, 0, 30, 2007, 10, 4, 2, 0, 0), 334 new DateTest(2007, 10, 5, 1, 0, 60, 2007, 10, 5, 2, 0), 335 336 // Nov 3, 2am + 60 minutes = Nov 3, 3am 337 // Nov 4, 2am + 30 minutes = Nov 4, 2:30am 338 // Nov 4, 2am + 60 minutes = Nov 4, 3am 339 // Nov 5, 2am + 60 minutes = Nov 5, 3am 340 new DateTest(2007, 10, 3, 2, 0, 60, 2007, 10, 3, 3, 0), 341 new DateTest(2007, 10, 4, 2, 0, 30, 2007, 10, 4, 2, 30), 342 new DateTest(2007, 10, 4, 2, 0, 60, 2007, 10, 4, 3, 0), 343 new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0), 344 }; 345 346 public void testNormalize1() throws Exception { 347 String tz = "America/Los_Angeles"; 348 Time local = new Time(tz); 349 350 int len = dayTests.length; 351 for (int index = 0; index < len; index++) { 352 DateTest test = dayTests[index]; 353 local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); 354 // call normalize() to make sure that isDst is set 355 local.normalize(false /* use isDst */); 356 local.monthDay += test.delta; 357 local.normalize(true /* ignore isDst */); 358 359 Time expected = new Time(tz); 360 Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2, 361 test.minute2, 0); 362 Fields.assertTimeEquals("day test index " + index + ", normalize():", 363 Fields.MAIN_DATE_TIME, expected, local); 364 365 local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); 366 // call normalize() to make sure that isDst is set 367 local.normalize(false /* use isDst */); 368 local.monthDay += test.delta; 369 long millis = local.toMillis(true /* ignore isDst */); 370 local.set(millis); 371 372 expected = new Time(tz); 373 Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2, 374 test.minute2, 0); 375 Fields.assertTimeEquals("day test index " + index + ", toMillis():", 376 Fields.MAIN_DATE_TIME, expected, local); 377 } 378 379 len = minuteTests.length; 380 for (int index = 0; index < len; index++) { 381 DateTest test = minuteTests[index]; 382 local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); 383 local.isDst = test.dst1; 384 // call normalize() to make sure that isDst is set 385 local.normalize(false /* use isDst */); 386 if (test.dst2 == -1) test.dst2 = local.isDst; 387 local.minute += test.delta; 388 local.normalize(false /* use isDst */); 389 390 Time expected = new Time(tz); 391 Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2, 392 test.minute2, 0); 393 Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2)); 394 Fields.assertTimeEquals("minute test index " + index + ", normalize():", 395 Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local); 396 397 local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); 398 local.isDst = test.dst1; 399 // call normalize() to make sure that isDst is set 400 local.normalize(false /* use isDst */); 401 if (test.dst2 == -1) test.dst2 = local.isDst; 402 local.minute += test.delta; 403 long millis = local.toMillis(false /* use isDst */); 404 local.set(millis); 405 406 expected = new Time(tz); 407 Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2, 408 test.minute2, 0); 409 Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2)); 410 Fields.assertTimeEquals("minute test index " + index + ", toMillis():", 411 Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local); 412 } 413 } 414 415 public void testSwitchTimezone_simpleUtc() throws Exception { 416 String originalTz = Time.TIMEZONE_UTC; 417 Time t = new Time(originalTz); 418 Fields.set(t, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 419 420 String newTz = "America/Los_Angeles"; 421 t.switchTimezone(newTz); 422 423 Time expected1 = new Time(newTz); 424 Fields.set(expected1, 2006, 9, 5, 5, 0, 0, 1 /* isDst */, -25200, 277, 4); 425 Fields.assertTimeEquals(expected1, t); 426 427 t.switchTimezone(originalTz); 428 429 Time expected2 = new Time(originalTz); 430 Fields.set(expected2, 2006, 9, 5, 12, 0, 0, 0 /* isDst */, 0, 277, 4); 431 Fields.assertTimeEquals(expected2, t); 432 } 433 434 public void testSwitchTimezone_standardToStandardTime() throws Exception { 435 String zone1 = "Europe/London"; 436 String zone2 = "America/Los_Angeles"; 437 438 // A time unambiguously in standard time in both zones. 439 Time t = new Time(zone1); 440 Fields.set(t, 2007, 2, 10, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 441 442 t.switchTimezone(zone2); 443 444 Time expected1 = new Time(zone2); 445 Fields.set(expected1, 2007, 2, 10, 4, 0, 0, 0 /* isDst */, -28800, 68, 6); 446 Fields.assertTimeEquals(expected1, t); 447 448 t.switchTimezone(zone1); 449 450 Time expected2 = new Time(zone1); 451 Fields.set(expected2, 2007, 2, 10, 12, 0, 0, 0 /* isDst */, 0, 68, 6); 452 Fields.assertTimeEquals(expected2, t); 453 } 454 455 public void testSwitchTimezone_dstToDstTime() throws Exception { 456 String zone1 = "Europe/London"; 457 String zone2 = "America/Los_Angeles"; 458 459 // A time unambiguously in DST in both zones. 460 Time t = new Time(zone1); 461 Fields.set(t, 2007, 2, 26, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 462 463 t.switchTimezone(zone2); 464 465 Time expected1 = new Time(zone2); 466 Fields.set(expected1, 2007, 2, 26, 4, 0, 0, 1 /* isDst */, -25200, 84, 1); 467 Fields.assertTimeEquals(expected1, t); 468 469 t.switchTimezone(zone1); 470 471 Time expected2 = new Time(zone1); 472 Fields.set(expected2, 2007, 2, 26, 12, 0, 0, 1 /* isDst */, 3600, 84, 1); 473 Fields.assertTimeEquals(expected2, t); 474 } 475 476 public void testSwitchTimezone_standardToDstTime() throws Exception { 477 String zone1 = "Europe/London"; 478 String zone2 = "America/Los_Angeles"; 479 480 // A time that is in standard time in zone1, but in DST in zone2. 481 Time t = new Time(zone1); 482 Fields.set(t, 2007, 2, 24, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 483 484 t.switchTimezone(zone2); 485 486 Time expected1 = new Time(zone2); 487 Fields.set(expected1, 2007, 2, 24, 5, 0, 0, 1 /* isDst */, -25200, 82, 6); 488 Fields.assertTimeEquals(expected1, t); 489 490 t.switchTimezone(zone1); 491 492 Time expected2 = new Time(zone1); 493 Fields.set(expected2, 2007, 2, 24, 12, 0, 0, 0 /* isDst */, 0, 82, 6); 494 Fields.assertTimeEquals(expected2, t); 495 } 496 497 public void testSwitchTimezone_sourceDateInvalid() throws Exception { 498 String zone1 = "Europe/London"; 499 String zone2 = "America/Los_Angeles"; 500 501 // A source wall time known not to normalize because it doesn't "exist" locally. 502 Time t = new Time(zone1); 503 Fields.set(t, 2007, 2, 25, 1, 30, 0, -1 /* isDst */, 0, 0, 0); 504 assertEquals(-1, t.toMillis(false)); 505 506 t.switchTimezone(zone2); 507 508 // It is assumed a sad trombone noise is also emitted from the device at this point. 509 // This illustrates why using -1 to indicate a problem, when -1 is in range, is a poor idea. 510 Time expected1 = new Time(zone2); 511 Fields.set(expected1, 1969, 11, 31, 15, 59, 59, 0 /* isDst */, -28800, 364, 3); 512 Fields.assertTimeEquals(expected1, t); 513 } 514 515 public void testSwitchTimezone_dstToStandardTime() throws Exception { 516 String zone1 = "America/Los_Angeles"; 517 String zone2 = "Europe/London"; 518 519 // A time that is in DST in zone1, but in standard in zone2. 520 Time t = new Time(zone1); 521 Fields.set(t, 2007, 2, 12, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 522 523 t.switchTimezone(zone2); 524 525 Time expected1 = new Time(zone2); 526 Fields.set(expected1, 2007, 2, 12, 19, 0, 0, 0 /* isDst */, 0, 70, 1); 527 Fields.assertTimeEquals(expected1, t); 528 529 t.switchTimezone(zone1); 530 531 Time expected2 = new Time(zone1); 532 Fields.set(expected2, 2007, 2, 12, 12, 0, 0, 1 /* isDst */, -25200, 70, 1); 533 Fields.assertTimeEquals(expected2, t); 534 } 535 536 public void testCtor() throws Exception { 537 String tz = Time.TIMEZONE_UTC; 538 Time t = new Time(tz); 539 assertEquals(tz, t.timezone); 540 541 Time expected = new Time(tz); 542 Fields.set(expected, 1970, 0, 1, 0, 0, 0, -1 /* isDst */, 0, 0, 0); 543 Fields.assertTimeEquals(expected, t); 544 } 545 546 public void testGetActualMaximum() throws Exception { 547 Time t = new Time(Time.TIMEZONE_UTC); 548 assertEquals(59, t.getActualMaximum(Time.SECOND)); 549 assertEquals(59, t.getActualMaximum(Time.MINUTE)); 550 assertEquals(23, t.getActualMaximum(Time.HOUR)); 551 assertEquals(11, t.getActualMaximum(Time.MONTH)); 552 assertEquals(2037, t.getActualMaximum(Time.YEAR)); 553 assertEquals(6, t.getActualMaximum(Time.WEEK_DAY)); 554 assertEquals(364, t.getActualMaximum(Time.YEAR_DAY)); 555 t.year = 2000; 556 assertEquals(365, t.getActualMaximum(Time.YEAR_DAY)); 557 558 try { 559 t.getActualMaximum(Time.WEEK_NUM); 560 fail("should throw runtime exception"); 561 } catch (Exception e) { 562 // expected 563 } 564 final int noExistField = -1; 565 try { 566 t.getActualMaximum(noExistField); 567 } catch (Exception e) { 568 // expected 569 } 570 571 t.year = 2001; 572 final int[] DAYS_PER_MONTH = { 573 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 574 }; 575 assertMonth(t, DAYS_PER_MONTH); 576 577 t.year = 2000; 578 DAYS_PER_MONTH[1] = 29; 579 assertMonth(t, DAYS_PER_MONTH); 580 } 581 582 private void assertMonth(Time t, final int[] DAYS_PER_MONTH) { 583 for (int i = 0; i < t.getActualMaximum(Time.MONTH); i++) { 584 t.month = i; 585 assertEquals(DAYS_PER_MONTH[i], t.getActualMaximum(Time.MONTH_DAY)); 586 } 587 } 588 589 public void testClear0() throws Exception { 590 Time t = new Time(Time.getCurrentTimezone()); 591 t.clear(Time.TIMEZONE_UTC); 592 assertEquals(Time.TIMEZONE_UTC, t.timezone); 593 assertFalse(t.allDay); 594 assertEquals(0, t.second); 595 assertEquals(0, t.minute); 596 assertEquals(0, t.hour); 597 assertEquals(0, t.monthDay); 598 assertEquals(0, t.month); 599 assertEquals(0, t.year); 600 assertEquals(0, t.weekDay); 601 assertEquals(0, t.yearDay); 602 assertEquals(0, t.gmtoff); 603 assertEquals(-1, t.isDst); 604 } 605 606 public void testClear() throws Exception { 607 Time t = new Time("America/Los_Angeles"); 608 Fields.set(t, 1, 2, 3, 4, 5, 6, 7 /* isDst */, 8, 9, 10); 609 610 t.clear(Time.TIMEZONE_UTC); 611 612 Time expected = new Time(Time.TIMEZONE_UTC); 613 Fields.set(expected, 0, 0, 0, 0, 0, 0, -1 /* isDst */, 0, 0, 0); 614 Fields.assertTimeEquals(expected, t); 615 } 616 617 public void testCompare() throws Exception { 618 String timezone = "America/New_York"; 619 int[] aDateTimeFields = new int[] { 2005, 2, 3, 4, 5, 6 }; 620 621 Time a = new Time(timezone); 622 Fields.setDateTime(a, aDateTimeFields); 623 Fields.setDst(a, 7, 8); 624 Fields.setDerivedDateTime(a, 9, 10); 625 626 int[] bDateTimeFields = new int[aDateTimeFields.length]; 627 System.arraycopy(aDateTimeFields, 0, bDateTimeFields, 0, aDateTimeFields.length); 628 Time b = new Time(timezone); 629 Fields.setDateTime(b, bDateTimeFields); 630 Fields.setDst(b, 7, 8); 631 Fields.setDerivedDateTime(b, 9, 10); 632 633 // Confirm timezone behavior: When timezones differ the result depends on the millis time. 634 // This means that all date/time and the isDst field can impact compare() when timezones 635 // are different. The result is always -1, 0 or 1. 636 637 // East of New York. Millis goes down for a given wall time. 638 b.timezone = "Europe/London"; 639 assertEquals(1, Time.compare(a, b)); 640 assertEquals(-1, Time.compare(b, a)); 641 642 // West of New York. Millis goes up for a given wall time. 643 b.timezone = "America/Los_Angeles"; 644 assertEquals(-1, Time.compare(a, b)); 645 assertEquals(1, Time.compare(b, a)); 646 647 b.timezone = timezone; 648 assertEquals(0, Time.compare(a, b)); 649 assertEquals(0, Time.compare(b, a)); 650 651 // Now confirm behavior when timezones are the same: Only the date/time fields are checked 652 // and the result depends on the difference between the fields and the order in which they 653 // are checked. 654 655 // Check date/time fields 656 for (int i = 0; i < aDateTimeFields.length; i++) { 657 bDateTimeFields[i] = 99999; 658 Fields.setDateTime(b, bDateTimeFields); 659 660 assertEquals(aDateTimeFields[i] - bDateTimeFields[i], Time.compare(a, b)); 661 assertEquals(bDateTimeFields[i] - aDateTimeFields[i], Time.compare(b, a)); 662 663 bDateTimeFields[i] = -99999; 664 Fields.setDateTime(b, bDateTimeFields); 665 666 assertEquals(aDateTimeFields[i] - bDateTimeFields[i], Time.compare(a, b)); 667 assertEquals(bDateTimeFields[i] - aDateTimeFields[i], Time.compare(b, a)); 668 669 bDateTimeFields[i] = aDateTimeFields[i]; 670 Fields.setDateTime(b, bDateTimeFields); 671 672 assertEquals(0, Time.compare(a, b)); 673 assertEquals(0, Time.compare(b, a)); 674 } 675 676 // Show that the derived fields have no effect on compare when timezones are the same. 677 Fields.setDst(b, 999, 999); 678 Fields.setDerivedDateTime(b, 999, 999); 679 assertEquals(0, Time.compare(a, b)); 680 assertEquals(0, Time.compare(b, a)); 681 } 682 683 public void testCompareNullFailure() throws Exception { 684 Time a = new Time(Time.TIMEZONE_UTC); 685 686 try { 687 Time.compare(a, null); 688 fail("Should throw NullPointerException on second argument"); 689 } catch (NullPointerException e) { 690 // pass 691 } 692 693 try { 694 Time.compare(null, a); 695 fail("Should throw NullPointerException on first argument"); 696 } catch (NullPointerException e) { 697 // pass 698 } 699 700 try { 701 Time.compare(null, null); 702 fail("Should throw NullPointerException because both args are null"); 703 } catch (NullPointerException e) { 704 // pass 705 } 706 } 707 708 public void testCompare_invalidDatesAreEqualIfTimezoneDiffers() throws Exception { 709 String timezone = "America/New_York"; 710 // This date is outside of the valid set of dates that can be calculated so toMillis() 711 // returns -1. 712 int[] dateTimeFields = new int[] { 1, 2, 3, 4, 5, 6 }; 713 714 Time a = new Time(timezone); 715 Fields.setDateTime(a, dateTimeFields); 716 Fields.setDst(a, 7, 8); 717 Fields.setDerivedDateTime(a, 9, 10); 718 assertEquals(-1, a.toMillis(false)); 719 720 Time b = new Time(timezone); 721 Fields.setDateTime(b, dateTimeFields); 722 Fields.setDst(b, 11, 12); 723 Fields.setDerivedDateTime(b, 13, 14); 724 assertEquals(-1, b.toMillis(false)); 725 726 // DST and derived-date time fields are always ignored. 727 assertEquals(0, Time.compare(a, b)); 728 729 // Set a different invalid set of date fields. 730 Fields.setDateTime(b, new int[] { 6, 5, 4, 3, 2, 1 }); 731 assertEquals(-5, Time.compare(a, b)); 732 733 // Now change the timezone 734 b.timezone = Time.TIMEZONE_UTC; 735 736 // >:-( 737 assertEquals(0, Time.compare(a, b)); 738 } 739 740 public void testFormat() throws Exception { 741 Time t = new Time(Time.TIMEZONE_UTC); 742 String r = t.format("%Y%m%dT%H%M%S"); 743 assertEquals("19700101T000000", r); 744 } 745 746 public void testFormat_null() { 747 Time t = new Time(Time.TIMEZONE_UTC); 748 assertEquals(t.format("%c"), t.format(null)); 749 } 750 751 public void testFormat_badPatterns() throws Exception { 752 Time t = new Time(Time.TIMEZONE_UTC); 753 assertFormatEquals(t, "%~Y", "~Y"); 754 assertFormatEquals(t, "%", "%"); 755 } 756 757 public void testFormat_doesNotNormalize() throws Exception { 758 Time t = new Time(Time.TIMEZONE_UTC); 759 Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2); 760 761 Time tCopy = new Time(t); 762 Fields.assertTimeEquals(t, tCopy); 763 764 assertFormatEquals(t, "%Y%m%dT%H%M%S", "20051432T-1-1-1"); 765 766 Fields.assertTimeEquals(t, tCopy); 767 } 768 769 private static void assertFormatEquals(Time t, String formatArg, String expected) { 770 assertEquals(expected, t.format(formatArg)); 771 } 772 773 public void testFormat_tokensUkLocale() throws Exception { 774 changeJavaAndAndroidLocale(Locale.UK); 775 776 Time t = new Time("Europe/London"); 777 Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15); 778 779 // Prove the un-normalized fields are used. 780 assertFormatEquals(t, "%A", "Sunday"); 781 782 // Set fields like weekday. 783 t.normalize(true); 784 785 assertFormatEquals(t, "%A", "Wednesday"); 786 assertFormatEquals(t, "%a", "Wed"); 787 assertFormatEquals(t, "%B", "June"); 788 assertFormatEquals(t, "%b", "Jun"); 789 assertFormatEquals(t, "%C", "20"); 790 assertFormatEquals(t, "%c", "1 Jun 2005, 12:30:15"); 791 assertFormatEquals(t, "%D", "06/01/05"); 792 assertFormatEquals(t, "%d", "01"); 793 assertFormatEquals(t, "%E", "E"); 794 assertFormatEquals(t, "%e", " 1"); 795 assertFormatEquals(t, "%F", "2005-06-01"); 796 assertFormatEquals(t, "%G", "2005"); 797 assertFormatEquals(t, "%g", "05"); 798 assertFormatEquals(t, "%H", "12"); 799 assertFormatEquals(t, "%h", "Jun"); 800 assertFormatEquals(t, "%I", "12"); 801 assertFormatEquals(t, "%j", "152"); 802 assertFormatEquals(t, "%K", "K"); 803 assertFormatEquals(t, "%k", "12"); 804 assertFormatEquals(t, "%l", "12"); 805 assertFormatEquals(t, "%M", "30"); 806 assertFormatEquals(t, "%m", "06"); 807 assertFormatEquals(t, "%n", "\n"); 808 assertFormatEquals(t, "%O", "O"); 809 assertFormatEquals(t, "%p", "pm"); 810 assertFormatEquals(t, "%P", "pm"); 811 assertFormatEquals(t, "%R", "12:30"); 812 assertFormatEquals(t, "%r", "12:30:15 pm"); 813 assertFormatEquals(t, "%S", "15"); 814 // The original C implementation uses the (native) system default TZ, not the timezone of 815 // the Time to calculate this and was therefore not stable. This changed to use the Time's 816 // timezone when the Time class was re-written in Java. 817 assertFormatEquals(t, "%s", "1117625415"); 818 assertFormatEquals(t, "%T", "12:30:15"); 819 assertFormatEquals(t, "%t", "\t"); 820 assertFormatEquals(t, "%U", "22"); 821 assertFormatEquals(t, "%u", "3"); 822 assertFormatEquals(t, "%V", "22"); 823 assertFormatEquals(t, "%v", " 1-Jun-2005"); 824 assertFormatEquals(t, "%W", "22"); 825 assertFormatEquals(t, "%w", "3"); 826 assertFormatEquals(t, "%X", "12:30:15"); 827 assertFormatEquals(t, "%x", "1 June 2005"); 828 assertFormatEquals(t, "%y", "05"); 829 assertFormatEquals(t, "%Y", "2005"); 830 assertFormatEquals(t, "%Z", "BST"); 831 assertFormatEquals(t, "%z", "+0100"); 832 assertFormatEquals(t, "%+", "Wed Jun 1 12:30:15 BST 2005"); 833 assertFormatEquals(t, "%%", "%"); 834 835 // Modifiers 836 837 assertFormatEquals(t, "%EC", "20"); 838 assertFormatEquals(t, "%OC", "20"); 839 840 assertFormatEquals(t, "%_+", "Wed Jun 1 12:30:15 BST 2005"); 841 assertFormatEquals(t, "%-+", "Wed Jun 1 12:30:15 BST 2005"); 842 assertFormatEquals(t, "%0+", "Wed Jun 1 12:30:15 BST 2005"); 843 assertFormatEquals(t, "%^+", "Wed Jun 1 12:30:15 BST 2005"); 844 assertFormatEquals(t, "%#+", "Wed Jun 1 12:30:15 BST 2005"); 845 846 assertFormatEquals(t, "%_A", "Wednesday"); 847 assertFormatEquals(t, "%-A", "Wednesday"); 848 assertFormatEquals(t, "%0A", "Wednesday"); 849 assertFormatEquals(t, "%^A", "WEDNESDAY"); 850 assertFormatEquals(t, "%#A", "wEDNESDAY"); 851 852 assertFormatEquals(t, "%_Y", "20 5"); 853 assertFormatEquals(t, "%-Y", "205"); 854 assertFormatEquals(t, "%0Y", "2005"); 855 assertFormatEquals(t, "%^Y", "2005"); 856 assertFormatEquals(t, "%#Y", "2005"); 857 858 assertFormatEquals(t, "%_d", " 1"); 859 assertFormatEquals(t, "%-d", "1"); 860 assertFormatEquals(t, "%0d", "01"); 861 assertFormatEquals(t, "%^d", "01"); 862 assertFormatEquals(t, "%#d", "01"); 863 } 864 865 public void testFormat_tokensUsLocale() throws Exception { 866 changeJavaAndAndroidLocale(Locale.US); 867 868 Time t = new Time("America/New_York"); 869 Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15); 870 871 // Prove the un-normalized fields are used. 872 assertFormatEquals(t, "%A", "Sunday"); 873 874 // Set fields like weekday. 875 t.normalize(true); 876 877 assertFormatEquals(t, "%A", "Wednesday"); 878 assertFormatEquals(t, "%a", "Wed"); 879 assertFormatEquals(t, "%B", "June"); 880 assertFormatEquals(t, "%b", "Jun"); 881 assertFormatEquals(t, "%C", "20"); 882 assertFormatEquals(t, "%c", "Jun 1, 2005, 12:30:15 PM"); 883 assertFormatEquals(t, "%D", "06/01/05"); 884 assertFormatEquals(t, "%d", "01"); 885 assertFormatEquals(t, "%E", "E"); 886 assertFormatEquals(t, "%e", " 1"); 887 assertFormatEquals(t, "%F", "2005-06-01"); 888 assertFormatEquals(t, "%G", "2005"); 889 assertFormatEquals(t, "%g", "05"); 890 assertFormatEquals(t, "%H", "12"); 891 assertFormatEquals(t, "%h", "Jun"); 892 assertFormatEquals(t, "%I", "12"); 893 assertFormatEquals(t, "%j", "152"); 894 assertFormatEquals(t, "%K", "K"); 895 assertFormatEquals(t, "%k", "12"); 896 assertFormatEquals(t, "%l", "12"); 897 assertFormatEquals(t, "%M", "30"); 898 assertFormatEquals(t, "%m", "06"); 899 assertFormatEquals(t, "%n", "\n"); 900 assertFormatEquals(t, "%O", "O"); 901 assertFormatEquals(t, "%p", "PM"); 902 assertFormatEquals(t, "%P", "pm"); 903 assertFormatEquals(t, "%R", "12:30"); 904 assertFormatEquals(t, "%r", "12:30:15 PM"); 905 assertFormatEquals(t, "%S", "15"); 906 // The original C implementation uses the (native) system default TZ, not the timezone of 907 // the Time to calculate this and was therefore not stable. This changed to use the Time's 908 // timezone when the Time class was re-written in Java. 909 assertFormatEquals(t, "%s", "1117643415"); 910 assertFormatEquals(t, "%T", "12:30:15"); 911 assertFormatEquals(t, "%t", "\t"); 912 assertFormatEquals(t, "%U", "22"); 913 assertFormatEquals(t, "%u", "3"); 914 assertFormatEquals(t, "%V", "22"); 915 assertFormatEquals(t, "%v", " 1-Jun-2005"); 916 assertFormatEquals(t, "%W", "22"); 917 assertFormatEquals(t, "%w", "3"); 918 assertFormatEquals(t, "%X", "12:30:15 PM"); 919 assertFormatEquals(t, "%x", "June 1, 2005"); 920 assertFormatEquals(t, "%y", "05"); 921 assertFormatEquals(t, "%Y", "2005"); 922 assertFormatEquals(t, "%Z", "EDT"); 923 assertFormatEquals(t, "%z", "-0400"); 924 assertFormatEquals(t, "%+", "Wed Jun 1 12:30:15 EDT 2005"); 925 assertFormatEquals(t, "%%", "%"); 926 927 // Modifiers 928 929 assertFormatEquals(t, "%EC", "20"); 930 assertFormatEquals(t, "%OC", "20"); 931 932 assertFormatEquals(t, "%_+", "Wed Jun 1 12:30:15 EDT 2005"); 933 assertFormatEquals(t, "%-+", "Wed Jun 1 12:30:15 EDT 2005"); 934 assertFormatEquals(t, "%0+", "Wed Jun 1 12:30:15 EDT 2005"); 935 assertFormatEquals(t, "%^+", "Wed Jun 1 12:30:15 EDT 2005"); 936 assertFormatEquals(t, "%#+", "Wed Jun 1 12:30:15 EDT 2005"); 937 938 assertFormatEquals(t, "%_A", "Wednesday"); 939 assertFormatEquals(t, "%-A", "Wednesday"); 940 assertFormatEquals(t, "%0A", "Wednesday"); 941 assertFormatEquals(t, "%^A", "WEDNESDAY"); 942 assertFormatEquals(t, "%#A", "wEDNESDAY"); 943 944 assertFormatEquals(t, "%_Y", "20 5"); 945 assertFormatEquals(t, "%-Y", "205"); 946 assertFormatEquals(t, "%0Y", "2005"); 947 assertFormatEquals(t, "%^Y", "2005"); 948 assertFormatEquals(t, "%#Y", "2005"); 949 950 assertFormatEquals(t, "%_d", " 1"); 951 assertFormatEquals(t, "%-d", "1"); 952 assertFormatEquals(t, "%0d", "01"); 953 assertFormatEquals(t, "%^d", "01"); 954 assertFormatEquals(t, "%#d", "01"); 955 } 956 957 public void testFormat_tokensFranceLocale() throws Exception { 958 changeJavaAndAndroidLocale(Locale.FRANCE); 959 960 Time t = new Time("Europe/Paris"); 961 Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15); 962 963 // Prove the un-normalized fields are used. 964 assertFormatEquals(t, "%A", "dimanche"); 965 966 // Set fields like weekday. 967 t.normalize(true); 968 969 assertFormatEquals(t, "%A", "mercredi"); 970 assertFormatEquals(t, "%a", "mer."); 971 assertFormatEquals(t, "%B", "juin"); 972 assertFormatEquals(t, "%b", "juin"); 973 assertFormatEquals(t, "%C", "20"); 974 assertFormatEquals(t, "%c", "1 juin 2005 12:30:15"); 975 assertFormatEquals(t, "%D", "06/01/05"); 976 assertFormatEquals(t, "%d", "01"); 977 assertFormatEquals(t, "%E", "E"); 978 assertFormatEquals(t, "%e", " 1"); 979 assertFormatEquals(t, "%F", "2005-06-01"); 980 assertFormatEquals(t, "%G", "2005"); 981 assertFormatEquals(t, "%g", "05"); 982 assertFormatEquals(t, "%H", "12"); 983 assertFormatEquals(t, "%h", "juin"); 984 assertFormatEquals(t, "%I", "12"); 985 assertFormatEquals(t, "%j", "152"); 986 assertFormatEquals(t, "%K", "K"); 987 assertFormatEquals(t, "%k", "12"); 988 assertFormatEquals(t, "%l", "12"); 989 assertFormatEquals(t, "%M", "30"); 990 assertFormatEquals(t, "%m", "06"); 991 assertFormatEquals(t, "%n", "\n"); 992 assertFormatEquals(t, "%O", "O"); 993 assertFormatEquals(t, "%p", "PM"); 994 assertFormatEquals(t, "%P", "pm"); 995 assertFormatEquals(t, "%R", "12:30"); 996 assertFormatEquals(t, "%r", "12:30:15 PM"); 997 assertFormatEquals(t, "%S", "15"); 998 // The original C implementation uses the (native) system default TZ, not the timezone of 999 // the Time to calculate this and was therefore not stable. This changed to use the Time's 1000 // timezone when the Time class was re-written in Java. 1001 assertFormatEquals(t, "%s", "1117621815"); 1002 assertFormatEquals(t, "%T", "12:30:15"); 1003 assertFormatEquals(t, "%t", "\t"); 1004 assertFormatEquals(t, "%U", "22"); 1005 assertFormatEquals(t, "%u", "3"); 1006 assertFormatEquals(t, "%V", "22"); 1007 assertFormatEquals(t, "%v", " 1-juin-2005"); 1008 assertFormatEquals(t, "%W", "22"); 1009 assertFormatEquals(t, "%w", "3"); 1010 assertFormatEquals(t, "%X", "12:30:15"); 1011 assertFormatEquals(t, "%x", "1 juin 2005"); 1012 assertFormatEquals(t, "%y", "05"); 1013 assertFormatEquals(t, "%Y", "2005"); 1014 assertFormatEquals(t, "%Z", "GMT+02:00"); 1015 assertFormatEquals(t, "%z", "+0200"); 1016 assertFormatEquals(t, "%+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1017 assertFormatEquals(t, "%%", "%"); 1018 1019 // Modifiers 1020 1021 assertFormatEquals(t, "%EC", "20"); 1022 assertFormatEquals(t, "%OC", "20"); 1023 1024 assertFormatEquals(t, "%_+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1025 assertFormatEquals(t, "%-+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1026 assertFormatEquals(t, "%0+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1027 assertFormatEquals(t, "%^+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1028 assertFormatEquals(t, "%#+", "mer. juin 1 12:30:15 GMT+02:00 2005"); 1029 1030 assertFormatEquals(t, "%_A", "mercredi"); 1031 assertFormatEquals(t, "%-A", "mercredi"); 1032 assertFormatEquals(t, "%0A", "mercredi"); 1033 assertFormatEquals(t, "%^A", "MERCREDI"); 1034 assertFormatEquals(t, "%#A", "MERCREDI"); 1035 1036 assertFormatEquals(t, "%_Y", "20 5"); 1037 assertFormatEquals(t, "%-Y", "205"); 1038 assertFormatEquals(t, "%0Y", "2005"); 1039 assertFormatEquals(t, "%^Y", "2005"); 1040 assertFormatEquals(t, "%#Y", "2005"); 1041 1042 assertFormatEquals(t, "%_d", " 1"); 1043 assertFormatEquals(t, "%-d", "1"); 1044 assertFormatEquals(t, "%0d", "01"); 1045 assertFormatEquals(t, "%^d", "01"); 1046 assertFormatEquals(t, "%#d", "01"); 1047 } 1048 1049 public void testFormat_tokensJapanLocale() throws Exception { 1050 changeJavaAndAndroidLocale(Locale.JAPAN); 1051 1052 Time t = new Time("Asia/Tokyo"); 1053 Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15); 1054 1055 // Prove the un-normalized fields are used. 1056 assertFormatEquals(t, "%A", ""); 1057 1058 // Set fields like weekday. 1059 t.normalize(true); 1060 1061 assertFormatEquals(t, "%A", ""); 1062 assertFormatEquals(t, "%a", ""); 1063 assertFormatEquals(t, "%B", "6"); 1064 assertFormatEquals(t, "%b", "6"); 1065 assertFormatEquals(t, "%C", "20"); 1066 assertFormatEquals(t, "%c", "2005/06/01 12:30:15"); 1067 assertFormatEquals(t, "%D", "06/01/05"); 1068 assertFormatEquals(t, "%d", "01"); 1069 assertFormatEquals(t, "%E", "E"); 1070 assertFormatEquals(t, "%e", " 1"); 1071 assertFormatEquals(t, "%F", "2005-06-01"); 1072 assertFormatEquals(t, "%G", "2005"); 1073 assertFormatEquals(t, "%g", "05"); 1074 assertFormatEquals(t, "%H", "12"); 1075 assertFormatEquals(t, "%h", "6"); 1076 assertFormatEquals(t, "%I", "12"); 1077 assertFormatEquals(t, "%j", "152"); 1078 assertFormatEquals(t, "%k", "12"); 1079 assertFormatEquals(t, "%l", "12"); 1080 assertFormatEquals(t, "%M", "30"); 1081 assertFormatEquals(t, "%m", "06"); 1082 assertFormatEquals(t, "%n", "\n"); 1083 assertFormatEquals(t, "%O", "O"); 1084 assertFormatEquals(t, "%p", ""); 1085 assertFormatEquals(t, "%P", ""); 1086 assertFormatEquals(t, "%R", "12:30"); 1087 assertFormatEquals(t, "%r", "12:30:15 "); 1088 assertFormatEquals(t, "%S", "15"); 1089 // The original C implementation uses the (native) system default TZ, not the timezone of 1090 // the Time to calculate this and was therefore not stable. This changed to use the Time's 1091 // timezone when the Time class was re-written in Java. 1092 assertFormatEquals(t, "%s", "1117596615"); 1093 assertFormatEquals(t, "%T", "12:30:15"); 1094 assertFormatEquals(t, "%t", "\t"); 1095 assertFormatEquals(t, "%U", "22"); 1096 assertFormatEquals(t, "%u", "3"); 1097 assertFormatEquals(t, "%V", "22"); 1098 assertFormatEquals(t, "%v", " 1-6-2005"); 1099 assertFormatEquals(t, "%W", "22"); 1100 assertFormatEquals(t, "%w", "3"); 1101 assertFormatEquals(t, "%X", "12:30:15"); 1102 assertFormatEquals(t, "%x", "200561"); 1103 assertFormatEquals(t, "%y", "05"); 1104 assertFormatEquals(t, "%Y", "2005"); 1105 assertFormatEquals(t, "%Z", "JST"); 1106 assertFormatEquals(t, "%z", "+0900"); 1107 assertFormatEquals(t, "%+", " 6 1 12:30:15 JST 2005"); 1108 assertFormatEquals(t, "%%", "%"); 1109 1110 // Modifiers 1111 1112 assertFormatEquals(t, "%EC", "20"); 1113 assertFormatEquals(t, "%OC", "20"); 1114 1115 assertFormatEquals(t, "%_+", " 6 1 12:30:15 JST 2005"); 1116 assertFormatEquals(t, "%-+", " 6 1 12:30:15 JST 2005"); 1117 assertFormatEquals(t, "%0+", " 6 1 12:30:15 JST 2005"); 1118 assertFormatEquals(t, "%^+", " 6 1 12:30:15 JST 2005"); 1119 assertFormatEquals(t, "%#+", " 6 1 12:30:15 JST 2005"); 1120 1121 assertFormatEquals(t, "%_A", ""); 1122 assertFormatEquals(t, "%-A", ""); 1123 assertFormatEquals(t, "%0A", ""); 1124 assertFormatEquals(t, "%^A", ""); 1125 assertFormatEquals(t, "%#A", ""); 1126 1127 assertFormatEquals(t, "%_Y", "20 5"); 1128 assertFormatEquals(t, "%-Y", "205"); 1129 assertFormatEquals(t, "%0Y", "2005"); 1130 assertFormatEquals(t, "%^Y", "2005"); 1131 assertFormatEquals(t, "%#Y", "2005"); 1132 1133 assertFormatEquals(t, "%_d", " 1"); 1134 assertFormatEquals(t, "%-d", "1"); 1135 assertFormatEquals(t, "%0d", "01"); 1136 assertFormatEquals(t, "%^d", "01"); 1137 assertFormatEquals(t, "%#d", "01"); 1138 } 1139 1140 public void testFormat2445() throws Exception { 1141 Time t = new Time(Time.TIMEZONE_UTC); 1142 Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15); 1143 1144 // UTC behavior is to add a trailing Z. 1145 String expected = t.format("%Y%m%dT%H%M%SZ"); 1146 assertEquals(expected, t.format2445()); 1147 1148 // Only UTC includes the Z. 1149 t.timezone = "America/Los_Angeles"; 1150 expected = t.format("%Y%m%dT%H%M%S"); 1151 assertEquals(expected, t.format2445()); 1152 1153 // There is odd behavior around negative values. 1154 Fields.setDateTime(t, 2005, -1, -1, -1, -1, -1); 1155 assertEquals("2005000 T0 0 0 ", t.format2445()); 1156 } 1157 1158 public void testFormat2445_doesNotNormalize() throws Exception { 1159 Time t = new Time(Time.TIMEZONE_UTC); 1160 Fields.set(t, 2005, 13, 32, 25, 61, 61, -2, -2, -2, -2); 1161 1162 Time tCopy = new Time(t); 1163 Fields.assertTimeEquals(t, tCopy); 1164 1165 assertEquals("20051432T256161Z", t.format2445()); 1166 Fields.assertTimeEquals(t, tCopy); 1167 1168 t.timezone = tCopy.timezone = "America/Los_Angeles"; 1169 assertEquals("20051432T256161", t.format2445()); 1170 Fields.assertTimeEquals(t, tCopy); 1171 } 1172 1173 public void testToString() throws Exception { 1174 Time t = new Time(Time.TIMEZONE_UTC); 1175 assertEquals("19700101T000000UTC(0,0,0,-1,0)", t.toString()); 1176 1177 t.timezone = "America/Los_Angeles"; 1178 assertEquals("19700101T000000America/Los_Angeles(0,0,0,-1,28800)", t.toString()); 1179 } 1180 1181 public void testToString_doesNotNormalize() throws Exception { 1182 Time t = new Time(Time.TIMEZONE_UTC); 1183 Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2); 1184 1185 Time tCopy = new Time(t); 1186 Fields.assertTimeEquals(t, tCopy); 1187 1188 String r = t.toString(); 1189 assertEquals("20051432T-1-1-1UTC(-2,-2,-2,-2,1141426739)", r); 1190 1191 Fields.assertTimeEquals(t, tCopy); 1192 } 1193 1194 public void testGetCurrentTimezone() throws Exception { 1195 String r = Time.getCurrentTimezone(); 1196 assertEquals(TimeZone.getDefault().getID(), r); 1197 } 1198 1199 public void testSetToNow() throws Exception { 1200 Time t = new Time(Time.TIMEZONE_UTC); 1201 1202 // Time works in seconds so all millis values have to be divided by 1000, otherwise 1203 // the greater accuracy of System.currentTimeMillis() causes the test to fail. 1204 1205 long lowerBound = System.currentTimeMillis() / 1000; 1206 1207 t.setToNow(); 1208 1209 long upperBound = System.currentTimeMillis() / 1000; 1210 1211 long actual = t.toMillis(true /* ignore isDst */) / 1000; 1212 assertTrue(lowerBound <= actual && actual <= upperBound); 1213 } 1214 1215 public void testToMillis_utc() throws Exception { 1216 Time t = new Time(Time.TIMEZONE_UTC); 1217 1218 long winterTimeUtcMillis = 1167613323000L; 1219 1220 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9); 1221 long r = t.toMillis(true /* ignore isDst */); 1222 assertEquals(winterTimeUtcMillis, r); 1223 1224 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9); 1225 r = t.toMillis(true /* ignore isDst */); 1226 assertEquals(winterTimeUtcMillis, r); 1227 1228 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9); 1229 r = t.toMillis(true /* ignore isDst */); 1230 assertEquals(winterTimeUtcMillis, r); 1231 1232 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9); 1233 r = t.toMillis(false /* ignore isDst */); 1234 assertEquals(winterTimeUtcMillis, r); 1235 1236 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9); 1237 r = t.toMillis(false /* ignore isDst */); 1238 assertEquals(-1, r); 1239 1240 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9); 1241 r = t.toMillis(false /* ignore isDst */); 1242 assertEquals(winterTimeUtcMillis, r); 1243 1244 long summerTimeUtcMillis = 1180659723000L; 1245 1246 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9); 1247 r = t.toMillis(true /* ignore isDst */); 1248 assertEquals(summerTimeUtcMillis, r); 1249 1250 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9); 1251 r = t.toMillis(true /* ignore isDst */); 1252 assertEquals(summerTimeUtcMillis, r); 1253 1254 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9); 1255 r = t.toMillis(true /* ignore isDst */); 1256 assertEquals(summerTimeUtcMillis, r); 1257 1258 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 1, 9, 9); 1259 r = t.toMillis(false /* ignore isDst */); 1260 assertEquals(summerTimeUtcMillis, r); 1261 1262 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 1, 9, 9); 1263 r = t.toMillis(false /* ignore isDst */); 1264 assertEquals(-1, r); 1265 1266 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9); 1267 r = t.toMillis(false /* ignore isDst */); 1268 assertEquals(summerTimeUtcMillis, r); 1269 } 1270 1271 public void testToMillis_dstTz() throws Exception { 1272 Time t = new Time(PstPdt.ID); 1273 1274 // A STD time 1275 long stdTimeUtcMillis = 1167613323000L; 1276 long stdTimeMillis = stdTimeUtcMillis - PstPdt.getUtcOffsetMillis(false); 1277 1278 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1279 long r = t.toMillis(true /* ignore isDst */); 1280 assertEquals(stdTimeMillis, r); 1281 1282 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1283 assertToMillisResult(true, t, stdTimeMillis); 1284 1285 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1286 assertToMillisResult(true, t, stdTimeMillis); 1287 1288 long dstToStdCorrectionMillis = 1289 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true); 1290 1291 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1292 assertToMillisResult(false, t, stdTimeMillis); 1293 1294 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1295 assertToMillisResult(false, t, stdTimeMillis + dstToStdCorrectionMillis); 1296 1297 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1298 assertToMillisResult(false, t, stdTimeMillis); 1299 1300 // A DST time 1301 long dstTimeUtcMillis = 1180659723000L; 1302 long dstTimeMillis = dstTimeUtcMillis - PstPdt.getUtcOffsetMillis(true); 1303 1304 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1305 assertToMillisResult(true, t, dstTimeMillis); 1306 1307 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1308 assertToMillisResult(true, t, dstTimeMillis); 1309 1310 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1311 assertToMillisResult(true, t, dstTimeMillis); 1312 1313 long stdToDstCorrectionMillis = -dstToStdCorrectionMillis; 1314 1315 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1316 assertToMillisResult(false, t, dstTimeMillis + stdToDstCorrectionMillis); 1317 1318 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1319 assertToMillisResult(false, t, dstTimeMillis); 1320 1321 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1322 assertToMillisResult(false, t, dstTimeMillis); 1323 } 1324 1325 private static void assertToMillisResult(boolean toMillisArgument, Time t, long expectedResult) { 1326 long r = t.toMillis(toMillisArgument /* ignore isDst */); 1327 assertEquals(expectedResult, r); 1328 } 1329 1330 public void testToMillis_doesNotNormalize() { 1331 Time t = new Time(Time.TIMEZONE_UTC); 1332 1333 Fields.set(t, 2007, 13, 32, 25, 60, 60, -2 /* isDst */, Integer.MAX_VALUE, 367, 7); 1334 1335 Time originalTime = new Time(t); 1336 Fields.assertTimeEquals(t, originalTime); 1337 1338 t.toMillis(true); 1339 Fields.assertTimeEquals(originalTime, t); 1340 1341 t.toMillis(false); 1342 Fields.assertTimeEquals(originalTime, t); 1343 } 1344 1345 public void testToMillis_skippedTime() { 1346 // Tests behavior around a transition from STD to DST that introduces an hour of "skipped" 1347 // time from 01:00 to 01:59. 1348 String timezone = PstPdt.ID; 1349 long stdBaseTimeMillis = 1173607200000L; 1350 long dstBaseTimeMillis = 1173603600000L; 1351 1352 // Try each minute from one minute before the skipped hour until one after. 1353 for (int i = -1; i <= 60; i++) { 1354 int minutesInMillis = i * 60000; 1355 int[] timeFields = new int[] { 2007, 2, 11, 2, i, 0, -999 /* not used */, 9, 9, 9 }; 1356 1357 Time time = new Time(timezone); 1358 1359 // isDst = 0, toMillis(true) 1360 Fields.set(time, timeFields); 1361 time.isDst = 0; 1362 long expectedTimeMillis; 1363 if (i == -1) { 1364 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 1365 } else if (i == 60) { 1366 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 1367 } else { 1368 expectedTimeMillis = -1; 1369 } 1370 assertToMillisResult(true, time, expectedTimeMillis); 1371 1372 // isDst = 0, toMillis(false) 1373 Fields.set(time, timeFields); 1374 time.isDst = 0; 1375 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 1376 assertToMillisResult(false, time, expectedTimeMillis); 1377 1378 // isDst = 1, toMillis(true) 1379 Fields.set(time, timeFields); 1380 time.isDst = 1; 1381 if (i == -1) { 1382 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 1383 } else if (i == 60) { 1384 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 1385 } else { 1386 expectedTimeMillis = -1; 1387 } 1388 assertToMillisResult(true, time, expectedTimeMillis); 1389 1390 // isDst = 1, toMillis(false) 1391 Fields.set(time, timeFields); 1392 time.isDst = 1; 1393 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 1394 assertToMillisResult(false, time, expectedTimeMillis); 1395 1396 // isDst = -1, toMillis(true) 1397 Fields.set(time, timeFields); 1398 time.isDst = -1; 1399 1400 if (i == -1) { 1401 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 1402 } else if (i == 60) { 1403 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 1404 } else { 1405 expectedTimeMillis = -1; 1406 } 1407 assertToMillisResult(false, time, expectedTimeMillis); 1408 1409 // isDst = -1, toMillis(false) 1410 Fields.set(time, timeFields); 1411 time.isDst = -1; 1412 assertToMillisResult(false, time, expectedTimeMillis); 1413 } 1414 } 1415 1416 public void testToMillis_duplicateWallTime() { 1417 // 1:00 in standard / 2:00 in DST 1418 long timeBaseMillis = 1194163200000L; 1419 long dstCorrectionMillis = 3600000; 1420 1421 // Try each minute from one minute before the duplicated hour until one after. 1422 for (int i = -1; i <= 60; i++) { 1423 int minutesInMillis = i * 60000; 1424 1425 Time time = new Time(PstPdt.ID); 1426 int[] timeFields = new int[] { 2007, 10, 4, 1, i, 0, -999 /* not used */, 9, 9, 9}; 1427 1428 // isDst = 0, toMillis(true) 1429 Fields.set(time, timeFields); 1430 time.isDst = 0; 1431 long timeMillis = time.toMillis(true); 1432 if (i == -1) { 1433 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis); 1434 } else if (i == 60) { 1435 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis, 1436 timeMillis); 1437 } else { 1438 // When ignoreDst the choice between DST and STD is arbitrary when both are 1439 // possible. 1440 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis 1441 || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis); 1442 } 1443 1444 // isDst = 0, toMillis(false) 1445 Fields.set(time, timeFields); 1446 time.isDst = 0; 1447 assertToMillisResult(false, time, 1448 timeBaseMillis + minutesInMillis + dstCorrectionMillis); 1449 1450 // isDst = 1, toMillis(true) 1451 Fields.set(time, timeFields); 1452 time.isDst = 1; 1453 if (i == -1) { 1454 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis); 1455 } else if (i == 60) { 1456 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis, 1457 timeMillis); 1458 } else { 1459 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when 1460 // both are possible. 1461 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis 1462 || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis); 1463 } 1464 1465 // isDst = 1, toMillis(false) 1466 Fields.set(time, timeFields); 1467 time.isDst = 1; 1468 assertToMillisResult(false, time, timeBaseMillis + minutesInMillis); 1469 1470 // isDst = -1, toMillis(true) 1471 Fields.set(time, timeFields); 1472 time.isDst = -1; 1473 timeMillis = time.toMillis(true); 1474 if (i == -1) { 1475 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis); 1476 } else if (i == 60) { 1477 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis, 1478 timeMillis); 1479 } else { 1480 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when 1481 // both are possible. 1482 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis 1483 || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis); 1484 } 1485 1486 // isDst = -1, toMillis(false) 1487 Fields.set(time, timeFields); 1488 time.isDst = -1; 1489 timeMillis = time.toMillis(false); 1490 if (i == -1) { 1491 assertEquals("i = " + i, timeBaseMillis + minutesInMillis, timeMillis); 1492 } else if (i == 60) { 1493 assertEquals("i = " + i, timeBaseMillis + minutesInMillis + dstCorrectionMillis, 1494 timeMillis); 1495 } else { 1496 // When ignoreDst or isDst == -1 the choice between DST and STD is arbitrary when 1497 // both are possible. 1498 assertTrue("i = " + i, timeMillis == timeBaseMillis + minutesInMillis 1499 || timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis); 1500 } 1501 } 1502 } 1503 1504 public void testToMillis_beforeTzRecords() { 1505 int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 }; 1506 assertToMillisInvalid(timeFields, PstPdt.ID); 1507 assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC); 1508 } 1509 1510 private static void assertToMillisInvalid(int[] timeFields, String timezone) { 1511 Time time = new Time(timezone); 1512 1513 // isDst = 0, toMillis(true) 1514 Fields.set(time, timeFields); 1515 time.isDst = 0; 1516 assertToMillisResult(true, time, -1); 1517 1518 // isDst = 0, toMillis(false) 1519 Fields.set(time, timeFields); 1520 time.isDst = 0; 1521 assertToMillisResult(false, time, -1); 1522 1523 // isDst = 1, toMillis(true) 1524 Fields.set(time, timeFields); 1525 time.isDst = 1; 1526 assertToMillisResult(true, time, -1); 1527 1528 // isDst = 1, toMillis(false) 1529 Fields.set(time, timeFields); 1530 time.isDst = 1; 1531 assertToMillisResult(false, time, -1); 1532 1533 // isDst = -1, toMillis(true) 1534 Fields.set(time, timeFields); 1535 time.isDst = -1; 1536 assertToMillisResult(true, time, -1); 1537 1538 // isDst = -1, toMillis(false) 1539 Fields.set(time, timeFields); 1540 time.isDst = -1; 1541 assertToMillisResult(false, time, -1); 1542 } 1543 1544 public void testToMillis_afterTzRecords() { 1545 int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 }; 1546 assertToMillisInvalid(timeFields, PstPdt.ID); 1547 assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC); 1548 } 1549 1550 public void testToMillis_invalid() { 1551 int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 }; 1552 assertToMillisInvalid(timeFields, PstPdt.ID); 1553 assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC); 1554 } 1555 1556 public void testParse_date() throws Exception { 1557 String nonUtcTz = PstPdt.ID; 1558 Time t = new Time(nonUtcTz); 1559 assertFalse(t.parse("12345678")); 1560 Time expected = new Time(nonUtcTz); 1561 Fields.setAllDayDate(expected, 1234, 55, 78); 1562 Fields.setDst(expected, -1 /* isDst */, 0); 1563 Fields.setDerivedDateTime(expected, 0, 0); 1564 Fields.assertTimeEquals(expected, t); 1565 } 1566 1567 public void testParse_null() throws Exception { 1568 Time t = new Time(Time.TIMEZONE_UTC); 1569 try { 1570 t.parse(null); 1571 fail(); 1572 } catch (NullPointerException e) { 1573 } 1574 } 1575 1576 public void testParse() throws Exception { 1577 Time t = new Time(Time.TIMEZONE_UTC); 1578 t.parse("20061005T120000"); 1579 1580 Time expected = new Time(Time.TIMEZONE_UTC); 1581 Fields.set(expected, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0); 1582 Fields.assertTimeEquals(expected, t); 1583 } 1584 1585 public void testParse_dateTime() throws Exception { 1586 String nonUtcTz = PstPdt.ID; 1587 Time t = new Time(nonUtcTz); 1588 assertFalse(t.parse("12345678T901234")); 1589 Time expected = new Time(nonUtcTz); 1590 Fields.set(expected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0); 1591 Fields.assertTimeEquals(expected, t); 1592 1593 Time t2 = new Time(nonUtcTz); 1594 assertTrue(t2.parse("12345678T901234Z")); 1595 Time utcExpected = new Time(Time.TIMEZONE_UTC); 1596 Fields.set(utcExpected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0); 1597 Fields.assertTimeEquals(utcExpected, t2); 1598 } 1599 1600 public void testParse_errors() throws Exception { 1601 String nonUtcTz = PstPdt.ID; 1602 try { 1603 Time t = new Time(nonUtcTz); 1604 t.parse(null); 1605 fail(); 1606 } catch (NullPointerException e) { 1607 } 1608 1609 // Too short 1610 assertParseError(""); 1611 assertParseError("1"); 1612 assertParseError("12"); 1613 assertParseError("123"); 1614 assertParseError("1234"); 1615 assertParseError("12345"); 1616 assertParseError("123456"); 1617 assertParseError("1234567"); 1618 1619 // No "T" in the expected place 1620 assertParseError("12345678S"); 1621 1622 // Invalid character in the first 8 characters. 1623 assertParseError("12X45678"); 1624 1625 // Too short for a date/time (15 or 16 characters allowed) 1626 assertParseError("12345678T"); 1627 assertParseError("12345678T0"); 1628 assertParseError("12345678T01"); 1629 assertParseError("12345678T012"); 1630 assertParseError("12345678T0123"); 1631 assertParseError("12345678T01234"); 1632 1633 // Invalid character 1634 assertParseError("12345678T0X2345"); 1635 } 1636 1637 private static void assertParseError(String s) { 1638 Time t = new Time(Time.TIMEZONE_UTC); 1639 try { 1640 t.parse(s); 1641 fail(); 1642 } catch (TimeFormatException expected) { 1643 } 1644 } 1645 1646 public void testParse3339() throws Exception { 1647 String tz = Time.TIMEZONE_UTC; 1648 Time expected = new Time(tz); 1649 Fields.setAllDayDate(expected, 1980, 4, 23); 1650 Fields.setDst(expected, -1 /* isDst */, 0); 1651 Fields.setDerivedDateTime(expected, 0, 0); 1652 assertParse3339Succeeds(tz, "1980-05-23", expected); 1653 1654 Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50); 1655 Fields.setDst(expected, -1 /* isDst */, 0); 1656 Fields.setDerivedDateTime(expected, 0, 0); 1657 assertParse3339Succeeds(tz, "1980-05-23T09:50:50", expected); 1658 1659 Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50); 1660 Fields.setDst(expected, -1 /* isDst */, 0); 1661 Fields.setDerivedDateTime(expected, 0, 0); 1662 assertParse3339Succeeds(tz, "1980-05-23T09:50:50Z", expected); 1663 1664 Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50); 1665 Fields.setDst(expected, -1 /* isDst */, 0); 1666 Fields.setDerivedDateTime(expected, 0, 0); 1667 assertParse3339Succeeds(tz, "1980-05-23T09:50:50.0Z", expected); 1668 1669 Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50); 1670 Fields.setDst(expected, -1 /* isDst */, 0); 1671 Fields.setDerivedDateTime(expected, 0, 0); 1672 assertParse3339Succeeds(tz, "1980-05-23T09:50:50.12Z", expected); 1673 1674 Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50); 1675 Fields.setDst(expected, -1 /* isDst */, 0); 1676 Fields.setDerivedDateTime(expected, 0, 0); 1677 assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123Z", expected); 1678 1679 // The time should be normalized to UTC 1680 Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50); 1681 Fields.setDst(expected, -1 /* isDst */, 0); 1682 Fields.setDerivedDateTime(expected, 0, 0); 1683 assertParse3339Succeeds(tz, "1980-05-23T09:50:50-01:05", expected); 1684 1685 // The time should be normalized to UTC 1686 Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50); 1687 Fields.setDst(expected, -1 /* isDst */, 0); 1688 Fields.setDerivedDateTime(expected, 0, 0); 1689 assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123-01:05", expected); 1690 } 1691 1692 private static void assertParse3339Succeeds(String timeZone, String toParse, Time expected) { 1693 Time t = new Time(timeZone); 1694 t.parse3339(toParse); 1695 Fields.assertTimeEquals(expected, t); 1696 } 1697 1698 public void testParse3339_parseErrors() { 1699 // Too short 1700 assertParse3339Error("1980"); 1701 1702 // Timezone too short 1703 assertParse3339Error("1980-05-23T09:50:50.123+"); 1704 assertParse3339Error("1980-05-23T09:50:50.123+05:0"); 1705 } 1706 1707 public void testParse3339_null() { 1708 Time t = new Time(Time.TIMEZONE_UTC); 1709 try { 1710 t.parse3339(null); 1711 fail(); 1712 } catch (NullPointerException e) { 1713 } 1714 } 1715 1716 private void assertParse3339Error(String s) { 1717 String tz = Time.TIMEZONE_UTC; 1718 Time t = new Time(tz); 1719 try { 1720 t.parse3339(s); 1721 fail(); 1722 } catch (TimeFormatException expected) { 1723 } 1724 } 1725 1726 public void testSetMillis_utc() throws Exception { 1727 String tz = Time.TIMEZONE_UTC; 1728 Time t = new Time(tz); 1729 t.set(1000L); 1730 1731 Time expected = new Time(tz); 1732 Fields.set(expected, 1970, 0, 1, 0, 0, 1, 0 /* isDst */, 0, 0, 4); 1733 Fields.assertTimeEquals(expected, t); 1734 1735 t.set(2000L); 1736 Fields.set(expected, 1970, 0, 1, 0, 0, 2, 0 /* isDst */, 0, 0, 4); 1737 Fields.assertTimeEquals(expected, t); 1738 1739 t.set(1000L * 60); 1740 Fields.set(expected, 1970, 0, 1, 0, 1, 0, 0 /* isDst */, 0, 0, 4); 1741 Fields.assertTimeEquals(expected, t); 1742 1743 t.set((1000L * 60 * 60 * 24) + 1000L); 1744 Fields.set(expected, 1970, 0, 2, 0, 0, 1, 0 /* isDst */, 0, 1, 5); 1745 Fields.assertTimeEquals(expected, t); 1746 } 1747 1748 public void testSetMillis_utc_edgeCases() throws Exception { 1749 String tz = Time.TIMEZONE_UTC; 1750 Time t = new Time(tz); 1751 t.set(Integer.MAX_VALUE + 1L); 1752 1753 Time expected = new Time(tz); 1754 // This a 32-bit int overflow bug. 1755 Fields.set(expected, 1970, 0, 25, 20, 31, 23, 0 /* isDst */, 0, 24, 0); 1756 Fields.assertTimeEquals(expected, t); 1757 1758 t = new Time(tz); 1759 t.set(Integer.MIN_VALUE - 1L); 1760 // This a 32-bit int underflow bug. 1761 Fields.set(expected, 1969, 11, 7, 3, 28, 37, 0 /* isDst */, 0, 340, 0); 1762 Fields.assertTimeEquals(expected, t); 1763 } 1764 1765 public void testSetFields() throws Exception { 1766 String tz = Time.TIMEZONE_UTC; 1767 Time t = new Time(tz); 1768 Fields.set(t, 9, 9, 9, 9, 9, 9, 9 /* isDst */, 9, 9, 9); 1769 1770 t.set(1, 2, 3, 4, 5, 6); 1771 1772 Time expected = new Time(tz); 1773 Fields.set(expected, 6, 5, 4, 3, 2, 1, -1 /* isDst */, 0, 0, 0); 1774 Fields.assertTimeEquals(expected, t); 1775 } 1776 1777 // Timezones that cover the world. Some GMT offsets occur more than 1778 // once in case some cities decide to change their GMT offset. 1779 private static final String[] mTimeZones = { 1780 "UTC", 1781 "Pacific/Kiritimati", 1782 "Pacific/Enderbury", 1783 "Pacific/Fiji", 1784 "Antarctica/South_Pole", 1785 "Pacific/Norfolk", 1786 "Pacific/Ponape", 1787 "Asia/Magadan", 1788 "Australia/Lord_Howe", 1789 "Australia/Sydney", 1790 "Australia/Adelaide", 1791 "Asia/Tokyo", 1792 "Asia/Seoul", 1793 "Asia/Taipei", 1794 "Asia/Singapore", 1795 "Asia/Hong_Kong", 1796 "Asia/Saigon", 1797 "Asia/Bangkok", 1798 "Indian/Cocos", 1799 "Asia/Rangoon", 1800 "Asia/Omsk", 1801 "Antarctica/Mawson", 1802 "Asia/Colombo", 1803 "Asia/Calcutta", 1804 "Asia/Oral", 1805 "Asia/Kabul", 1806 "Asia/Dubai", 1807 "Asia/Tehran", 1808 "Europe/Moscow", 1809 "Asia/Baghdad", 1810 "Africa/Mogadishu", 1811 "Europe/Athens", 1812 "Africa/Cairo", 1813 "Europe/Rome", 1814 "Europe/Berlin", 1815 "Europe/Amsterdam", 1816 "Africa/Tunis", 1817 "Europe/London", 1818 "Europe/Dublin", 1819 "Atlantic/St_Helena", 1820 "Africa/Monrovia", 1821 "Africa/Accra", 1822 "Atlantic/Azores", 1823 "Atlantic/South_Georgia", 1824 "America/Noronha", 1825 "America/Sao_Paulo", 1826 "America/Cayenne", 1827 "America/St_Johns", 1828 "America/Puerto_Rico", 1829 "America/Aruba", 1830 "America/New_York", 1831 "America/Chicago", 1832 "America/Denver", 1833 "America/Los_Angeles", 1834 "America/Anchorage", 1835 "Pacific/Marquesas", 1836 "America/Adak", 1837 "Pacific/Honolulu", 1838 "Pacific/Midway", 1839 }; 1840 1841 public void testGetJulianDay() throws Exception { 1842 Time time = new Time(); 1843 1844 // For every 15th day of 2008, and for each of the timezones listed above, 1845 // get the Julian day for 12am and then check that if we change the time we get the 1846 // same Julian day. Note that one of the many problems with the Time class 1847 // is its lack of error handling. If we accidentally hit a time that doesn't 1848 // exist (because it was skipped by a daylight savings transition), rather than 1849 // an error, you'll silently get 1970-01-01. We should @deprecate Time. 1850 for (int monthDay = 1; monthDay <= 366; monthDay += 15) { 1851 for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) { 1852 // We leave the "month" as zero because we are changing the 1853 // "monthDay" from 1 to 366. The call to normalize() will 1854 // then change the "month" (but we don't really care). 1855 time.set(0, 0, 12, monthDay, 0, 2008); 1856 time.timezone = mTimeZones[zoneIndex]; 1857 long millis = time.normalize(true); 1858 if (zoneIndex == 0) { 1859 Log.i(TAG, time.format("%B %d, %Y")); 1860 } 1861 1862 // This is the Julian day for 12pm for this day of the year 1863 int julianDay = Time.getJulianDay(millis, time.gmtoff); 1864 1865 // Change the time during the day and check that we get the same 1866 // Julian day. 1867 for (int hour = 0; hour < 24; hour++) { 1868 for (int minute = 0; minute < 60; minute += 15) { 1869 time.set(0, minute, hour, monthDay, 0, 2008); 1870 millis = time.normalize(true); 1871 if (millis == -1) { 1872 // millis == -1 means the wall time does not exist in the chosen 1873 // timezone due to a DST change. We cannot calculate a JulianDay for -1. 1874 continue; 1875 } 1876 1877 int day = Time.getJulianDay(millis, time.gmtoff); 1878 assertEquals("Julian day: " + day + " at time " 1879 + time.hour + ":" + time.minute 1880 + " != today's Julian day: " + julianDay 1881 + " timezone: " + time.timezone, day, julianDay); 1882 } 1883 } 1884 } 1885 } 1886 } 1887 1888 public void testSetJulianDay() throws Exception { 1889 Time time = new Time(); 1890 1891 // For each day of the year in 2008, and for each timezone, 1892 // test that we can set the Julian day correctly. 1893 for (int monthDay = 1; monthDay <= 366; monthDay += 20) { 1894 for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) { 1895 // We leave the "month" as zero because we are changing the 1896 // "monthDay" from 1 to 366. The call to normalize() will 1897 // then change the "month" (but we don't really care). 1898 time.set(0, 0, 12, monthDay, 0, 2008); 1899 time.timezone = mTimeZones[zoneIndex]; 1900 long millis = time.normalize(true); 1901 if (zoneIndex == 0) { 1902 Log.i(TAG, time.format("%B %d, %Y")); 1903 } 1904 // This is the Julian day for 12pm for this day of the year 1905 int julianDay = Time.getJulianDay(millis, time.gmtoff); 1906 1907 time.setJulianDay(julianDay); 1908 1909 // Some places change daylight saving time at 12am and so there 1910 // is no 12am on some days in some timezones. In those cases, 1911 // the time is set to 1am. 1912 // Examples: Africa/Cairo on April 25, 2008 1913 // America/Sao_Paulo on October 12, 2008 1914 // Atlantic/Azores on March 30, 2008 1915 assertTrue(time.hour == 0 || time.hour == 1); 1916 assertEquals(0, time.minute); 1917 assertEquals(0, time.second); 1918 1919 millis = time.toMillis(false); 1920 if (millis == -1) { 1921 // millis == -1 means the wall time does not exist in the chosen 1922 // timezone due to a DST change. We cannot calculate a JulianDay for -1. 1923 continue; 1924 } 1925 int day = Time.getJulianDay(millis, time.gmtoff); 1926 assertEquals("Error: gmtoff " + (time.gmtoff / 3600.0) + " day " + julianDay 1927 + " millis " + millis+ " " + time.format("%B %d, %Y") 1928 + " " + time.timezone, 1929 day, julianDay); 1930 } 1931 } 1932 } 1933 1934 public void testNormalize_utc() throws Exception { 1935 Time t = new Time(Time.TIMEZONE_UTC); 1936 Time expected = new Time(Time.TIMEZONE_UTC); 1937 1938 long winterTimeUtcMillis = 1167613323000L; 1939 1940 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1941 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1); 1942 assertNormalizeResult(true, t, expected, winterTimeUtcMillis); 1943 1944 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1945 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1); 1946 assertNormalizeResult(true, t, expected, winterTimeUtcMillis); 1947 1948 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1949 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1); 1950 assertNormalizeResult(true, t, expected, winterTimeUtcMillis); 1951 1952 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1953 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1); 1954 assertNormalizeResult(false, t, expected, winterTimeUtcMillis); 1955 1956 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1957 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1958 assertNormalizeResult(false, t, expected, -1); 1959 1960 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1961 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1); 1962 assertNormalizeResult(false, t, expected, winterTimeUtcMillis); 1963 1964 long summerTimeUtcMillis = 1180659723000L; 1965 1966 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1967 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 1968 assertNormalizeResult(true, t, expected, summerTimeUtcMillis); 1969 1970 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1971 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 1972 assertNormalizeResult(true, t, expected, summerTimeUtcMillis); 1973 1974 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 1975 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 1976 assertNormalizeResult(true, t, expected, summerTimeUtcMillis); 1977 1978 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 1979 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 1980 assertNormalizeResult(false, t, expected, summerTimeUtcMillis); 1981 1982 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1983 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 1984 assertNormalizeResult(false, t, expected, -1); 1985 1986 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9); 1987 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 1988 assertNormalizeResult(false, t, expected, summerTimeUtcMillis); 1989 } 1990 1991 public void testNormalize_dstTz() throws Exception { 1992 Time t = new Time(PstPdt.ID); 1993 Time expected = new Time(PstPdt.ID); 1994 1995 // A STD time 1996 long stdTimeUtcMillis = 1167613323000L; 1997 long stdTimeMillis = stdTimeUtcMillis - PstPdt.getUtcOffsetMillis(false); 1998 1999 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 2000 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1); 2001 assertNormalizeResult(true, t, expected, stdTimeMillis); 2002 2003 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 2004 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1); 2005 assertNormalizeResult(true, t, expected, stdTimeMillis); 2006 2007 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 2008 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1); 2009 assertNormalizeResult(true, t, expected, stdTimeMillis); 2010 2011 long dstToStdCorrectionMillis = 2012 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true); 2013 2014 Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 2015 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1); 2016 assertNormalizeResult(false, t, expected, stdTimeMillis); 2017 2018 Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 2019 Fields.set(expected, 2007, 0, 1, 0, 2, 3, 0 /* isDst */, -28800, 0, 1); 2020 assertNormalizeResult(false, t, expected, stdTimeMillis + dstToStdCorrectionMillis); 2021 2022 Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 2023 Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1); 2024 assertNormalizeResult(false, t, expected, stdTimeMillis); 2025 2026 // A DST time 2027 long dstTimeUtcMillis = 1180659723000L; 2028 long dstTimeMillis = dstTimeUtcMillis - PstPdt.getUtcOffsetMillis(true); 2029 2030 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 2031 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2032 assertNormalizeResult(true, t, expected, dstTimeMillis); 2033 2034 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9); 2035 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2036 assertNormalizeResult(true, t, expected, dstTimeMillis); 2037 2038 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 2039 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2040 assertNormalizeResult(true, t, expected, dstTimeMillis); 2041 2042 long stdToDstCorrectionMillis = -dstToStdCorrectionMillis; 2043 2044 Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9); 2045 Fields.set(expected, 2007, 5, 1, 2, 2, 3, 1 /* isDst */, -25200, 151, 5); 2046 assertNormalizeResult(false, t, expected, dstTimeMillis + stdToDstCorrectionMillis); 2047 2048 Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2049 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2050 assertNormalizeResult(false, t, expected, dstTimeMillis); 2051 2052 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, -25200, 151, 5); 2053 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5); 2054 assertNormalizeResult(false, t, expected, dstTimeMillis); 2055 } 2056 2057 public void testNormalize_skippedTime() { 2058 // Tests behavior around a transition from STD to DST that introduces an hour of "skipped" 2059 // time from 01:00 to 01:59. 2060 String timezone = PstPdt.ID; 2061 long stdBaseTimeMillis = 1173607200000L; 2062 long dstBaseTimeMillis = 1173603600000L; 2063 2064 // Try each minute from one minute before the skipped hour until one after. 2065 for (int i = -1; i <= 60; i++) { 2066 int minutesInMillis = i * 60000; 2067 int[] dateTimeArgs = new int[] { 2007, 2, 11, 2, i, 0 }; 2068 2069 int[] normalizedAdjustedBackwardDateTimeArgs; 2070 int[] normalizedDateTimeArgs; 2071 int[] normalizedAdjustedForwardDateTimeArgs; 2072 if (i == -1) { 2073 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 2, 11, 0, 59, 0 }; 2074 normalizedDateTimeArgs = new int[] { 2007, 2, 11, 1, 59, 0 }; 2075 normalizedAdjustedForwardDateTimeArgs = null; 2076 } else if (i == 60) { 2077 normalizedAdjustedBackwardDateTimeArgs = null; 2078 normalizedDateTimeArgs = new int[] { 2007, 2, 11, 3, 0, 0 }; 2079 normalizedAdjustedForwardDateTimeArgs = new int[] { 2007, 2, 11, 4, 0, 0 }; 2080 } else { 2081 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 2, 11, 1, i, 0 }; 2082 normalizedDateTimeArgs = null; 2083 normalizedAdjustedForwardDateTimeArgs = new int[] { 2007, 2, 11, 3, i, 0 }; 2084 } 2085 2086 Time time = new Time(timezone); 2087 Time expected = new Time(timezone); 2088 2089 // isDst = 0, normalize(true) 2090 Fields.setDateTime(time, dateTimeArgs); 2091 Fields.setDst(time, 0 /* isDst */, 9); 2092 Fields.setDerivedDateTime(time, 9, 9); 2093 2094 long timeMillis = time.normalize(true); 2095 long expectedTimeMillis; 2096 if (i == -1) { 2097 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 2098 Fields.setDateTime(expected, normalizedDateTimeArgs); 2099 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2100 Fields.setDerivedDateTime(expected, 69, 0); 2101 } else if (i == 60) { 2102 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 2103 Fields.setDateTime(expected, normalizedDateTimeArgs); 2104 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2105 Fields.setDerivedDateTime(expected, 69, 0); 2106 } else { 2107 expectedTimeMillis = -1; 2108 Fields.setDateTime(expected, dateTimeArgs); 2109 Fields.setDst(expected, -1, 9); 2110 Fields.setDerivedDateTime(expected, 9, 9); 2111 } 2112 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2113 Fields.assertTimeEquals("i = " + i, expected, time); 2114 2115 // isDst = 0, normalize(false) 2116 Fields.setDateTime(time, dateTimeArgs); 2117 Fields.setDst(time, 0 /* isDst */, 9); 2118 Fields.setDerivedDateTime(time, 9, 9); 2119 2120 timeMillis = time.normalize(false); 2121 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 2122 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2123 if (i == -1) { 2124 Fields.setDateTime(expected, normalizedDateTimeArgs); 2125 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2126 } else { 2127 Fields.setDateTime(expected, normalizedAdjustedForwardDateTimeArgs); 2128 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2129 } 2130 Fields.setDerivedDateTime(expected, 69, 0); 2131 Fields.assertTimeEquals("i = " + i, expected, time); 2132 2133 // isDst = 1, normalize(true) 2134 Fields.setDateTime(time, dateTimeArgs); 2135 Fields.setDst(time, 1 /* isDst */, 9); 2136 Fields.setDerivedDateTime(time, 9, 9); 2137 2138 timeMillis = time.normalize(true); 2139 if (i == -1) { 2140 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 2141 Fields.setDateTime(expected, normalizedDateTimeArgs); 2142 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2143 Fields.setDerivedDateTime(expected, 69, 0); 2144 } else if (i == 60) { 2145 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 2146 Fields.setDateTime(expected, normalizedDateTimeArgs); 2147 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2148 Fields.setDerivedDateTime(expected, 69, 0); 2149 } else { 2150 expectedTimeMillis = -1; 2151 Fields.setDateTime(expected, dateTimeArgs); 2152 Fields.setDst(expected, -1, 9); 2153 Fields.setDerivedDateTime(expected, 9, 9); 2154 } 2155 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2156 Fields.assertTimeEquals("i = " + i, expected, time); 2157 2158 // isDst = 1, normalize(false) 2159 Fields.setDateTime(time, dateTimeArgs); 2160 Fields.setDst(time, 1 /* isDst */, 9); 2161 Fields.setDerivedDateTime(time, 9, 9); 2162 2163 timeMillis = time.normalize(false); 2164 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 2165 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2166 if (i == 60) { 2167 Fields.setDateTime(expected, normalizedDateTimeArgs); 2168 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2169 } else { 2170 Fields.setDateTime(expected, normalizedAdjustedBackwardDateTimeArgs); 2171 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2172 } 2173 Fields.setDerivedDateTime(expected, 69, 0); 2174 Fields.assertTimeEquals("i = " + i, expected, time); 2175 2176 // isDst = -1, normalize(true) 2177 Fields.setDateTime(time, dateTimeArgs); 2178 Fields.setDst(time, -1 /* isDst */, 9); 2179 Fields.setDerivedDateTime(time, 9, 9); 2180 2181 timeMillis = time.normalize(true); 2182 if (i == -1) { 2183 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 2184 Fields.setDateTime(expected, normalizedDateTimeArgs); 2185 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2186 Fields.setDerivedDateTime(expected, 69, 0); 2187 } else if (i == 60) { 2188 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 2189 Fields.setDateTime(expected, normalizedDateTimeArgs); 2190 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2191 Fields.setDerivedDateTime(expected, 69, 0); 2192 } else { 2193 expectedTimeMillis = -1; 2194 Fields.setDateTime(expected, dateTimeArgs); 2195 Fields.setDst(expected, -1, 9); 2196 Fields.setDerivedDateTime(expected, 9, 9); 2197 } 2198 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2199 Fields.assertTimeEquals("i = " + i, expected, time); 2200 2201 // isDst = -1, normalize(false) 2202 Fields.setDateTime(time, dateTimeArgs); 2203 Fields.setDst(time, -1 /* isDst */, 9); 2204 Fields.setDerivedDateTime(time, 9, 9); 2205 2206 timeMillis = time.normalize(false); 2207 if (i == -1) { 2208 expectedTimeMillis = stdBaseTimeMillis + minutesInMillis; 2209 Fields.setDateTime(expected, normalizedDateTimeArgs); 2210 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0)); 2211 Fields.setDerivedDateTime(expected, 69, 0); 2212 } else if (i == 60) { 2213 expectedTimeMillis = dstBaseTimeMillis + minutesInMillis; 2214 Fields.setDateTime(expected, normalizedDateTimeArgs); 2215 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1)); 2216 Fields.setDerivedDateTime(expected, 69, 0); 2217 } else { 2218 expectedTimeMillis = -1; 2219 Fields.setDateTime(expected, dateTimeArgs); 2220 Fields.setDst(expected, -1, 9); 2221 Fields.setDerivedDateTime(expected, 9, 9); 2222 } 2223 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2224 Fields.assertTimeEquals("i = " + i, expected, time); 2225 } 2226 } 2227 2228 public void testNormalize_duplicateWallTime() { 2229 // 1:00 in standard / 2:00 in DST 2230 long timeBaseMillis = 1194163200000L; 2231 long dstCorrectionMillis = 3600000; 2232 2233 // Try each minute from one minute before the duplicated hour until one after. 2234 for (int i = -1; i <= 60; i++) { 2235 Time time = new Time(PstPdt.ID); 2236 Time expected = new Time(PstPdt.ID); 2237 2238 int[] dateTimeArgs = new int[] { 2007, 10, 4, 1, i, 0 }; 2239 int[] normalizedAdjustedBackwardDateTimeArgs; 2240 int[] normalizedDateTimeArgs; 2241 int[] normalizedAdjustedForwardDateTimeArgs; 2242 if (i == -1) { 2243 normalizedAdjustedBackwardDateTimeArgs = null; 2244 normalizedDateTimeArgs = new int[] { 2007, 10, 4, 0, 59, 0 }; 2245 normalizedAdjustedForwardDateTimeArgs = new int[] { 2007, 10, 4, 1, 59, 0 }; 2246 } else if (i == 60) { 2247 normalizedAdjustedBackwardDateTimeArgs = new int[] { 2007, 10, 4, 1, 0, 0 }; 2248 normalizedDateTimeArgs = new int[] { 2007, 10, 4, 2, 0, 0 }; 2249 normalizedAdjustedForwardDateTimeArgs = null; 2250 } else { 2251 normalizedAdjustedBackwardDateTimeArgs = null; 2252 normalizedDateTimeArgs = dateTimeArgs; 2253 normalizedAdjustedForwardDateTimeArgs = null; 2254 } 2255 2256 int minutesInMillis = i * 60000; 2257 2258 // isDst = 0, normalize(true) 2259 Fields.setDateTime(time, dateTimeArgs); 2260 Fields.setDst(time, 0 /* isDst */, 9); 2261 Fields.setDerivedDateTime(time, 9, 9); 2262 2263 long timeMillis = time.normalize(true); 2264 2265 Fields.setDateTime(expected, normalizedDateTimeArgs); 2266 // When ignoreDst == true the choice between DST and STD is arbitrary when both answers 2267 // are possible. 2268 if (timeMillis == timeBaseMillis + minutesInMillis) { 2269 // i == 60 is unambiguous 2270 assertTrue("i =" + i, i < 60); 2271 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2272 } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) { 2273 // i == -1 is unambiguous 2274 assertTrue("i =" + i, i > -1); 2275 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2276 } else { 2277 fail("i =" + i); 2278 } 2279 Fields.setDerivedDateTime(expected, 307, 0); 2280 Fields.assertTimeEquals("i = " + i, expected, time); 2281 2282 // isDst = 0, normalize(false) 2283 Fields.setDateTime(time, dateTimeArgs); 2284 Fields.setDst(time, 0 /* isDst */, 9); 2285 Fields.setDerivedDateTime(time, 9, 9); 2286 2287 timeMillis = time.normalize(false); 2288 long expectedTimeMillis = timeBaseMillis + minutesInMillis + dstCorrectionMillis; 2289 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2290 if (i == -1) { 2291 Fields.setDateTime(expected, normalizedAdjustedForwardDateTimeArgs); 2292 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2293 } else { 2294 Fields.setDateTime(expected, normalizedDateTimeArgs); 2295 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2296 } 2297 Fields.setDerivedDateTime(expected, 307, 0); 2298 Fields.assertTimeEquals("i = " + i, expected, time); 2299 2300 // isDst = 1, normalize(true) 2301 Fields.setDateTime(time, dateTimeArgs); 2302 Fields.setDst(time, 1 /* isDst */, 9); 2303 Fields.setDerivedDateTime(time, 9, 9); 2304 2305 timeMillis = time.normalize(true); 2306 Fields.setDateTime(expected, normalizedDateTimeArgs); 2307 // When ignoreDst == true the choice between DST and STD is arbitrary when both answers 2308 // are possible. 2309 if (timeMillis == timeBaseMillis + minutesInMillis) { 2310 // i == 60 is unambiguous 2311 assertTrue("i =" + i, i < 60); 2312 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2313 } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) { 2314 // i == -1 is unambiguous 2315 assertTrue("i =" + i, i > -1); 2316 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2317 } else { 2318 fail("i =" + i); 2319 } 2320 Fields.setDerivedDateTime(expected, 307, 0); 2321 Fields.assertTimeEquals("i = " + i, expected, time); 2322 2323 // isDst = 1, normalize(false) 2324 Fields.setDateTime(time, dateTimeArgs); 2325 Fields.setDst(time, 1 /* isDst */, 9); 2326 Fields.setDerivedDateTime(time, 9, 9); 2327 2328 timeMillis = time.normalize(false); 2329 expectedTimeMillis = timeBaseMillis + minutesInMillis; 2330 if (i == 60) { 2331 Fields.setDateTime(expected, normalizedAdjustedBackwardDateTimeArgs); 2332 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2333 } else { 2334 Fields.setDateTime(expected, normalizedDateTimeArgs); 2335 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2336 } 2337 Fields.setDerivedDateTime(expected, 307, 0); 2338 assertEquals("i = " + i, expectedTimeMillis, timeMillis); 2339 Fields.assertTimeEquals("i = " + i, expected, time); 2340 2341 // isDst = -1, normalize(true) 2342 Fields.setDateTime(time, dateTimeArgs); 2343 Fields.setDst(time, -1 /* isDst */, 9); 2344 Fields.setDerivedDateTime(time, 9, 9); 2345 2346 timeMillis = time.normalize(true); 2347 Fields.setDateTime(expected, normalizedDateTimeArgs); 2348 // When isDst == -1 the choice between DST and STD is arbitrary when both answers 2349 // are possible. 2350 if (timeMillis == timeBaseMillis + minutesInMillis) { 2351 // i == 60 is unambiguous 2352 assertTrue("i =" + i, i < 60); 2353 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2354 } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) { 2355 // i == -1 is unambiguous 2356 assertTrue("i =" + i, i > -1); 2357 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2358 } else { 2359 fail("i =" + i); 2360 } 2361 Fields.setDerivedDateTime(expected, 307, 0); 2362 Fields.assertTimeEquals("i = " + i, expected, time); 2363 2364 // isDst = -1, normalize(false) 2365 Fields.setDateTime(time, dateTimeArgs); 2366 Fields.setDst(time, -1 /* isDst */, 9); 2367 Fields.setDerivedDateTime(time, 9, 9); 2368 2369 timeMillis = time.normalize(false); 2370 // When isDst == -1 the choice between DST and STD is arbitrary when both answers 2371 // are possible. 2372 if (timeMillis == timeBaseMillis + minutesInMillis) { 2373 // i == 60 is unambiguous 2374 assertTrue("i =" + i, i < 60); 2375 Fields.setDst(expected, 1 /* isDst */, PstPdt.getUtcOffsetSeconds(1)); 2376 } else if (timeMillis == timeBaseMillis + minutesInMillis + dstCorrectionMillis) { 2377 // i == -1 is unambiguous 2378 assertTrue("i =" + i, i > -1); 2379 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0)); 2380 } else { 2381 fail("i =" + i); 2382 } 2383 Fields.setDerivedDateTime(expected, 307, 0); 2384 Fields.assertTimeEquals("i = " + i, expected, time); 2385 } 2386 } 2387 2388 public void testNormalize_beforeTzRecords() { 2389 int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 }; 2390 assertNormalizeInvalid(timeFields, PstPdt.ID); 2391 assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC); 2392 } 2393 2394 private static void assertNormalizeInvalid(int[] timeFields, String timezone) { 2395 Time time = new Time(timezone); 2396 Time expected = new Time(timezone); 2397 2398 // isDst = 0, normalize(true) 2399 Fields.set(time, timeFields); 2400 time.isDst = 0; 2401 Fields.set(expected, timeFields); 2402 expected.isDst = -1; 2403 assertNormalizeResult(true, time, expected, -1); 2404 2405 // isDst = 0, normalize(false) 2406 Fields.set(time, timeFields); 2407 time.isDst = 0; 2408 Fields.set(expected, timeFields); 2409 expected.isDst = 0; 2410 assertNormalizeResult(false, time, expected, -1); 2411 2412 // isDst = 1, normalize(true) 2413 Fields.set(time, timeFields); 2414 time.isDst = 1; 2415 Fields.set(expected, timeFields); 2416 expected.isDst = -1; 2417 assertNormalizeResult(true, time, expected, -1); 2418 2419 // isDst = 1, normalize(false) 2420 Fields.set(time, timeFields); 2421 time.isDst = 1; 2422 Fields.set(expected, timeFields); 2423 expected.isDst = 1; 2424 assertNormalizeResult(false, time, expected, -1); 2425 2426 // isDst = -1, normalize(true) 2427 Fields.set(time, timeFields); 2428 time.isDst = -1; 2429 Fields.set(expected, timeFields); 2430 expected.isDst = -1; 2431 assertNormalizeResult(true, time, expected, -1); 2432 2433 // isDst = -1, normalize(false) 2434 Fields.set(time, timeFields); 2435 time.isDst = -1; 2436 Fields.set(expected, timeFields); 2437 expected.isDst = -1; 2438 assertNormalizeResult(false, time, expected, -1); 2439 } 2440 2441 public void testNormalize_afterTzRecords() { 2442 int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 }; 2443 assertNormalizeInvalid(timeFields, PstPdt.ID); 2444 assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC); 2445 } 2446 2447 public void testNormalize_invalid() { 2448 int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 }; 2449 assertNormalizeInvalid(timeFields, PstPdt.ID); 2450 assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC); 2451 } 2452 2453 public void testNormalize_dstToDstSkip() { 2454 // In London, 4th May 1941 02:00 - 03:00 was a skip from DST -> DST (+1 hour -> +2 hours) 2455 String timezone = "Europe/London"; 2456 Time t = new Time(timezone); 2457 Time expected = new Time(timezone); 2458 2459 // Demonstrate the data we expect either side of the skipped interval: 01:59 2460 Fields.set(t, 1941, 4, 4, 1, 59, 0, -1 /* isDst */, 9, 9, 9); 2461 Fields.set(expected, 1941, 4, 4, 1, 59, 0, 1 /* isDst */, 3600, 123, 0); 2462 assertNormalizeResult(true, t, expected, -904518060000L); 2463 2464 // Demonstrate the data we expect either side of the skipped interval: 03:00 2465 Fields.set(t, 1941, 4, 4, 3, 0, 0, -1 /* isDst */, 9, 9, 9); 2466 Fields.set(expected, 1941, 4, 4, 3, 0, 0, 1 /* isDst */, 7200, 123, 0); 2467 assertNormalizeResult(true, t, expected, -904518000000L); 2468 2469 // isDst = 1, normalize(false) 2470 Fields.set(t, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9); 2471 Fields.set(expected, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9); 2472 assertNormalizeResult(false, t, expected, -1); 2473 2474 // isDst = -1, normalize(false) 2475 Fields.set(t, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9); 2476 Fields.set(expected, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9); 2477 assertNormalizeResult(false, t, expected, -1); 2478 2479 // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard 2480 // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a 2481 // date / time. 2482 2483 // isDst = 0, normalize(false) @ 01:30 2484 Fields.set(t, 1941, 4, 4, 1, 30, 0, 0 /* isDst */, 9, 9, 9); 2485 Fields.set(expected, 1941, 4, 4, 3, 30, 0, 1 /* isDst */, 7200, 123, 0); 2486 assertNormalizeResult(false, t, expected, -904516200000L); 2487 2488 // isDst = 0, normalize(false) @ 02:30 2489 Fields.set(t, 1941, 4, 4, 2, 30, 0, 0 /* isDst */, 9, 9, 9); 2490 long timeMillis = t.normalize(false); 2491 2492 if (timeMillis == -904516200000L) { 2493 // The original C implementation chooses this one. 2494 Fields.set(expected, 1941, 4, 4, 3, 30, 0, 1 /* isDst */, 7200, 123, 0); 2495 } else if (timeMillis == -904512600000L) { 2496 Fields.set(expected, 1941, 4, 4, 4, 30, 0, 1 /* isDst */, 7200, 123, 0); 2497 } else { 2498 fail(); 2499 } 2500 Fields.assertTimeEquals(expected, t); 2501 } 2502 2503 public void testNormalize_dstToDstRepeat() { 2504 // In London, 10th August 1941 02:00 - 03:00 was a repeat from DST -> DST 2505 // (+2 hour -> +1 hour) 2506 String timezone = "Europe/London"; 2507 Time t = new Time(timezone); 2508 Time expected = new Time(timezone); 2509 2510 // Demonstrate the data we expect during the repeated interval: 02:30 (first) 2511 t.set(-896052600000L); 2512 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 7200, 221, 0); 2513 Fields.assertTimeEquals(expected, t); 2514 2515 // Demonstrate the data we expect during the repeated interval: 02:30 (second) 2516 t.set(-896049000000L); 2517 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0); 2518 Fields.assertTimeEquals(expected, t); 2519 2520 // Now check times in the repeated hour with different isDst assertions... 2521 2522 // isDst = 1, normalize(false) @ 02:30 2523 Fields.set(t, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 9, 9, 9); 2524 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0); 2525 assertNormalizeResult(false, t, expected, -896049000000L); 2526 2527 // isDst = -1, normalize(false) @ 02:30 2528 Fields.set(t, 1941, 7, 10, 2, 30, 0, -1 /* isDst */, 9, 9, 9); 2529 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0); 2530 assertNormalizeResult(false, t, expected, -896049000000L); 2531 2532 // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard 2533 // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a 2534 // date / time. 2535 2536 // isDst = 0, normalize(false) @ 01:30 2537 Fields.set(t, 1941, 7, 10, 1, 30, 0, 0 /* isDst */, 9, 9, 9); 2538 long timeMillis = t.normalize(false); 2539 if (timeMillis == -896052600000L) { 2540 // The original C implementation chooses this one. 2541 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 7200, 221, 0); 2542 } else if (timeMillis == -896049000000L) { 2543 Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0); 2544 } else { 2545 fail(); 2546 } 2547 Fields.assertTimeEquals(expected, t); 2548 2549 // isDst = 0, normalize(false) @ 02:30 2550 Fields.set(t, 1941, 7, 10, 2, 30, 0, 0 /* isDst */, 9, 9, 9); 2551 Fields.set(expected, 1941, 7, 10, 3, 30, 0, 1 /* isDst */, 3600, 221, 0); 2552 assertNormalizeResult(false, t, expected, -896045400000L); 2553 } 2554 2555 public void testNormalize_stdToStdRepeat() { 2556 // In London, 31st October 1971 02:00 - 03:00 was a repeat from STD -> STD 2557 String timezone = "Europe/London"; 2558 Time t = new Time(timezone); 2559 Time expected = new Time(timezone); 2560 2561 // Demonstrate the data we expect during the repeated interval: 02:30 (first) 2562 t.set(57720600000L); 2563 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0); 2564 Fields.assertTimeEquals(expected, t); 2565 2566 // Demonstrate the data we expect during the repeated interval: 02:30 (second) 2567 t.set(57724200000L); 2568 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0); 2569 Fields.assertTimeEquals(expected, t); 2570 2571 // isDst = 0, normalize(false) @ 02:30 2572 Fields.set(t, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 9, 9, 9); 2573 2574 long timeMillis = t.normalize(false); 2575 2576 // Either answer is valid: the choice is arbitrary. 2577 if (57720600000L == timeMillis) { 2578 // The original C implementation chooses this one. 2579 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0); 2580 } else if (57724200000L == timeMillis) { 2581 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0); 2582 } else { 2583 fail(); 2584 } 2585 Fields.assertTimeEquals(expected, t); 2586 2587 // isDst = -1, normalize(false) @ 02:30 2588 Fields.set(t, 1971, 9, 31, 2, 30, 0, -1 /* isDst */, 9, 9, 9); 2589 2590 timeMillis = t.normalize(false); 2591 2592 Fields.setDateTime(expected, 1971, 9, 31, 2, 30, 0); 2593 // Either answer is valid: the choice is arbitrary. 2594 if (57720600000L == timeMillis) { 2595 // The original C implementation chooses this one. 2596 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0); 2597 } else if (57724200000L == timeMillis) { 2598 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0); 2599 } else { 2600 fail(); 2601 } 2602 Fields.assertTimeEquals(expected, t); 2603 2604 // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid DST 2605 // so normalize() must apply one of the possible STD -> DST adjustments to arrive at a 2606 // date / time. 2607 2608 // isDst = 1, normalize(false) @ 01:30 2609 Fields.set(t, 1971, 9, 31, 1, 30, 0, 1 /* isDst */, 9, 9, 9); 2610 2611 timeMillis = t.normalize(false); 2612 2613 if (timeMillis == 57713400000L) { 2614 // Original C implementation chooses this one. 2615 Fields.set(expected, 1971, 9, 31, 0, 30, 0, 0 /* isDst */, 3600, 303, 0); 2616 } else if (timeMillis == 57717000000L) { 2617 Fields.set(expected, 1971, 9, 31, 1, 30, 0, 0 /* isDst */, 3600, 303, 0); 2618 } else { 2619 fail(); 2620 } 2621 Fields.assertTimeEquals(expected, t); 2622 2623 // isDst = 1, normalize(false) @ 02:30 2624 Fields.set(t, 1971, 9, 31, 2, 30, 0, 1 /* isDst */, 9, 9, 9); 2625 timeMillis = t.normalize(false); 2626 if (timeMillis == 57717000000L) { 2627 // The original C implementation chooses this one. 2628 Fields.set(expected, 1971, 9, 31, 1, 30, 0, 0 /* isDst */, 3600, 303, 0); 2629 } else if (timeMillis == 57720600000L) { 2630 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0); 2631 } else { 2632 fail(); 2633 } 2634 Fields.assertTimeEquals(expected, t); 2635 2636 // isDst = 1, normalize(false) @ 03:30 2637 Fields.set(t, 1971, 9, 31, 3, 30, 0, 1 /* isDst */, 9, 9, 9); 2638 Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0); 2639 assertNormalizeResult(false, t, expected, 57724200000L); 2640 } 2641 2642 public void testNormalize_stdToStdSkip() { 2643 // In Kiritimati, 1st Jan 1995 10:00 - 10:40 was a skip from STD -> STD (plus they do not 2644 // observe DST). 2645 String timezone = "Pacific/Kiritimati"; 2646 Time t = new Time(timezone); 2647 Time expected = new Time(timezone); 2648 2649 // isDst = 0, normalize(false) 2650 Fields.set(t, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9); 2651 Fields.set(expected, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9); 2652 assertNormalizeResult(false, t, expected, -1); 2653 2654 // isDst = 1, normalize(false) 2655 Fields.set(t, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9); 2656 Fields.set(expected, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9); 2657 assertNormalizeResult(false, t, expected, -1); 2658 2659 // isDst = -1, normalize(false) 2660 Fields.set(t, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9); 2661 Fields.set(expected, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9); 2662 assertNormalizeResult(false, t, expected, -1); 2663 } 2664 2665 public void testNormalize_utcWithDst() { 2666 // In UTC (or other zone without DST), what happens when a DST time is specified and there 2667 // is no DST offset available in the timezone data. 2668 Time t = new Time(Time.TIMEZONE_UTC); 2669 Time expected = new Time(Time.TIMEZONE_UTC); 2670 2671 // isDst = 1, normalize(false) 2672 Fields.set(t, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9); 2673 Fields.set(expected, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9); 2674 assertNormalizeResult(false, t, expected, -1); 2675 2676 // isDst = -1, normalize(false) 2677 Fields.set(t, 2005, 6, 22, 1, 30, 0, -1 /* isDst */, 9, 9, 9); 2678 Fields.set(expected, 2005, 6, 22, 1, 30, 0, 0 /* isDst */, 0, 202, 5); 2679 assertNormalizeResult(false, t, expected, 1121995800000L); 2680 } 2681 2682 public void testUnknownTz() { 2683 // Historically the code used UTC if the timezone is unrecognized. 2684 2685 String unknownTimezoneId = "THIS_ID_IS_NOT_A_VALID_TZ"; 2686 Time t = new Time(unknownTimezoneId); 2687 assertEquals(unknownTimezoneId, t.timezone); 2688 Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9); 2689 2690 // We can't know for sure which time zone is being used, but we assume it is UTC if the date 2691 // normalizes to isDst == 0 and with an offset of 0 during the summer months. 2692 2693 long timeMillis = t.normalize(true); 2694 assertEquals(unknownTimezoneId, t.timezone); 2695 assertEquals(1180659723000L, timeMillis); 2696 2697 Time expected = new Time(unknownTimezoneId); 2698 Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5); 2699 Fields.assertTimeEquals(expected, t); 2700 } 2701 2702 private static void assertNormalizeResult(boolean normalizeArgument, Time toNormalize, 2703 Time expectedTime, long expectedTimeMillis) { 2704 long actualTimeMillis = toNormalize.normalize(normalizeArgument /* ignore isDst */); 2705 assertEquals(expectedTimeMillis, actualTimeMillis); 2706 Fields.assertTimeEquals(expectedTime, toNormalize); 2707 } 2708 2709 /** A helper class for manipulating / testing fields on Time objects. */ 2710 private static class Fields { 2711 final static int MAIN_DATE_TIME = 1; 2712 final static int DST_FIELDS = 2; 2713 final static int DERIVED_DATE_TIME = 4; 2714 2715 final static int ALL = MAIN_DATE_TIME | DST_FIELDS | DERIVED_DATE_TIME; 2716 2717 public static void assertTimeEquals(Time expected, Time actual) { 2718 assertTimeEquals("", ALL, expected, actual); 2719 } 2720 2721 public static void assertTimeEquals(int fields, Time expected, Time actual) { 2722 assertTimeEquals("", fields, expected, actual); 2723 } 2724 2725 public static void assertTimeEquals(String message, Time expected, Time actual) { 2726 assertTimeEquals(message, Fields.ALL, expected, actual); 2727 } 2728 2729 public static void assertTimeEquals(String message, int fields, Time expected, 2730 Time actual) { 2731 boolean mainDateTimeOk = (fields & Fields.MAIN_DATE_TIME) == 0 2732 || (Objects.equals(expected.timezone, actual.timezone) 2733 && expected.year == actual.year 2734 && expected.month == actual.month 2735 && expected.monthDay == actual.monthDay 2736 && expected.hour == actual.hour 2737 && expected.minute == actual.minute 2738 && expected.second == actual.second 2739 && expected.allDay == actual.allDay); 2740 2741 boolean dstFieldsOk = (fields & Fields.DST_FIELDS) == 0 2742 || (expected.isDst == actual.isDst && expected.gmtoff == actual.gmtoff); 2743 2744 boolean derivedDateTimeOk = (fields & Fields.DERIVED_DATE_TIME) == 0 2745 || (expected.yearDay == actual.yearDay && expected.weekDay == actual.weekDay); 2746 2747 if (!mainDateTimeOk || !dstFieldsOk || !derivedDateTimeOk) { 2748 String expectedTime = timeToString(fields, expected); 2749 String actualTime = timeToString(fields, actual); 2750 fail(message + " [Time fields differed. Expected: " + expectedTime + "Actual: " 2751 + actualTime + "]"); 2752 } 2753 } 2754 2755 private static String timeToString(int fields, Time time) { 2756 List<Object> values = new ArrayList<Object>(); 2757 StringBuilder format = new StringBuilder(); 2758 if ((fields & Fields.MAIN_DATE_TIME) > 0) { 2759 format.append("%d-%02d-%02d %02d:%02d:%02d allDay=%b timezone=%s "); 2760 values.addAll( 2761 Arrays.asList(time.year, time.month, time.monthDay, time.hour, time.minute, 2762 time.second, time.allDay, time.timezone)); 2763 } 2764 if ((fields & Fields.DST_FIELDS) > 0) { 2765 format.append("isDst=%d, gmtoff=%d "); 2766 values.add(time.isDst); 2767 values.add(time.gmtoff); 2768 } 2769 if ((fields & Fields.DERIVED_DATE_TIME) > 0) { 2770 format.append("yearDay=%d, weekDay=%d "); 2771 values.add(time.yearDay); 2772 values.add(time.weekDay); 2773 2774 } 2775 return String.format(format.toString(), values.toArray()); 2776 } 2777 2778 public static void setDateTime(Time t, int year, int month, int monthDay, int hour, 2779 int minute, int second) { 2780 t.year = year; 2781 t.month = month; 2782 t.monthDay = monthDay; 2783 t.hour = hour; 2784 t.minute = minute; 2785 t.second = second; 2786 t.allDay = false; 2787 } 2788 2789 public static void setDateTime(Time t, int[] args) { 2790 assertEquals(6, args.length); 2791 setDateTime(t, args[0], args[1], args[2], args[3], args[4], args[5]); 2792 } 2793 2794 public static void setDst(Time t, int isDst, int gmtoff) { 2795 t.isDst = isDst; 2796 t.gmtoff = gmtoff; 2797 } 2798 2799 public static void setDerivedDateTime(Time t, int yearDay, int weekDay) { 2800 t.yearDay = yearDay; 2801 t.weekDay = weekDay; 2802 } 2803 2804 public static void setAllDayDate(Time t, int year, int month, int monthDay) { 2805 t.year = year; 2806 t.month = month; 2807 t.monthDay = monthDay; 2808 t.allDay = true; 2809 } 2810 2811 public static void set(Time t, int[] args) { 2812 assertEquals(10, args.length); 2813 set(t, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 2814 args[9]); 2815 } 2816 2817 public static void set(Time t, int year, int month, int monthDay, int hour, int minute, 2818 int second, int isDst, int gmtoff, int yearDay, int weekDay) { 2819 setDateTime(t, year, month, monthDay, hour, minute, second); 2820 setDst(t, isDst, gmtoff); 2821 setDerivedDateTime(t, yearDay, weekDay); 2822 } 2823 } 2824 2825 private static class PstPdt { 2826 public static final String ID = "America/Los_Angeles"; 2827 2828 public static int getUtcOffsetSeconds(int isDst) { 2829 if (isDst == 0) { 2830 return -28800; 2831 } else if (isDst == 1) { 2832 return -25200; 2833 } 2834 throw new IllegalArgumentException(); 2835 } 2836 2837 public static int getUtcOffsetSeconds(boolean isDst) { 2838 return getUtcOffsetSeconds(isDst ? 1 : 0); 2839 } 2840 2841 public static int getUtcOffsetMillis(boolean isDst) { 2842 return getUtcOffsetSeconds(isDst) * 1000; 2843 } 2844 } 2845 2846 private static void changeJavaAndAndroidLocale(Locale locale) { 2847 // The Time class uses the Android-managed locale for string resources containing format 2848 // patterns and the Java-managed locale for other things (e.g. month names, week days names) 2849 // that are placed into those patterns. For example the format "%c" expands to include 2850 // a pattern that includes month names. 2851 // Changing the Java-managed Locale does not affect the Android-managed locale. 2852 // Changing the Android-managed locale does not affect the Java-managed locale. 2853 // 2854 // In order to ensure consistent behavior in the tests the device Locale must not be 2855 // assumed. To simulate the most common behavior (i.e. when the Java and the Android-managed 2856 // locales agree), when the Java-managed locale is changed during this test the locale in 2857 // the runtime-local copy of the system resources is modified as well. 2858 2859 // Change the Java-managed locale. 2860 Locale.setDefault(locale); 2861 2862 // Change the local copy of the Android system configuration: this simulates the device 2863 // being set to the locale and forces a reload of the string resources. 2864 Configuration configuration = Resources.getSystem().getConfiguration(); 2865 configuration.locale = locale; 2866 Resources.getSystem().updateConfiguration(configuration, null); 2867 } 2868 } 2869