1/* GENERATED SOURCE. DO NOT MODIFY. */ 2// © 2016 and later: Unicode, Inc. and others. 3// License & terms of use: http://www.unicode.org/copyright.html#License 4/* 5 ******************************************************************************* 6 * Copyright (C) 2000-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10package android.icu.dev.test.calendar; 11 12import java.text.FieldPosition; 13import java.text.ParseException; 14import java.util.Date; 15import java.util.Locale; 16import java.util.Set; 17 18import org.junit.Test; 19import org.junit.runner.RunWith; 20import org.junit.runners.JUnit4; 21 22import android.icu.impl.CalendarAstronomer; 23import android.icu.impl.LocaleUtility; 24import android.icu.impl.ZoneMeta; 25import android.icu.text.DateFormat; 26import android.icu.text.DateFormatSymbols; 27import android.icu.text.SimpleDateFormat; 28import android.icu.util.BuddhistCalendar; 29import android.icu.util.Calendar; 30import android.icu.util.ChineseCalendar; 31import android.icu.util.GregorianCalendar; 32import android.icu.util.JapaneseCalendar; 33import android.icu.util.TaiwanCalendar; 34import android.icu.util.TimeZone; 35import android.icu.util.TimeZone.SystemTimeZoneType; 36import android.icu.util.ULocale; 37import android.icu.testsharding.MainTestShard; 38 39/** 40 * @summary Tests of new functionality in IBMCalendar 41 */ 42@MainTestShard 43@RunWith(JUnit4.class) 44public class IBMCalendarTest extends CalendarTestFmwk { 45 /** 46 * Test weekend support in IBMCalendar. 47 * 48 * NOTE: This test will have to be updated when the isWeekend() etc. 49 * API is finalized later. 50 * 51 * In particular, the test will have to be rewritten to instantiate 52 * a Calendar in the given locale (using getInstance()) and call 53 * that Calendar's isWeekend() etc. methods. 54 */ 55 @Test 56 public void TestWeekend() { 57 SimpleDateFormat fmt = new SimpleDateFormat("EEE MMM dd yyyy G HH:mm:ss.SSS"); 58 59 // NOTE 60 // This test tests for specific locale data. This is probably okay 61 // as far as US data is concerned, but if the Arabic/Yemen data 62 // changes, this test will have to be updated. 63 64 // Test specific days 65 Object[] DATA1 = { 66 Locale.US, new int[] { // Saturday:Sunday 67 2000, Calendar.MARCH, 17, 23, 0, 0, // Fri 23:00 68 2000, Calendar.MARCH, 18, 0, -1, 0, // Fri 23:59:59.999 69 2000, Calendar.MARCH, 18, 0, 0, 1, // Sat 00:00 70 2000, Calendar.MARCH, 18, 15, 0, 1, // Sat 15:00 71 2000, Calendar.MARCH, 19, 23, 0, 1, // Sun 23:00 72 2000, Calendar.MARCH, 20, 0, -1, 1, // Sun 23:59:59.999 73 2000, Calendar.MARCH, 20, 0, 0, 0, // Mon 00:00 74 2000, Calendar.MARCH, 20, 8, 0, 0, // Mon 08:00 75 }, 76 new Locale("ar", "OM"), new int[] { // Friday:Saturday 77 2000, Calendar.MARCH, 15, 23, 0, 0, // Wed 23:00 78 2000, Calendar.MARCH, 16, 0, -1, 0, // Wed 23:59:59.999 79 2000, Calendar.MARCH, 16, 0, 0, 0, // Thu 00:00 80 2000, Calendar.MARCH, 16, 15, 0, 0, // Thu 15:00 81 2000, Calendar.MARCH, 17, 23, 0, 1, // Fri 23:00 82 2000, Calendar.MARCH, 18, 0, -1, 1, // Fri 23:59:59.999 83 2000, Calendar.MARCH, 18, 0, 0, 1, // Sat 00:00 84 2000, Calendar.MARCH, 18, 8, 0, 1, // Sat 08:00 85 }, 86 }; 87 88 // Test days of the week 89 Object[] DATA2 = { 90 Locale.US, new int[] { 91 Calendar.MONDAY, Calendar.WEEKDAY, 92 Calendar.FRIDAY, Calendar.WEEKDAY, 93 Calendar.SATURDAY, Calendar.WEEKEND, 94 Calendar.SUNDAY, Calendar.WEEKEND, 95 }, 96 new Locale("ar", "OM"), new int[] { // Friday:Saturday 97 Calendar.WEDNESDAY,Calendar.WEEKDAY, 98 Calendar.THURSDAY, Calendar.WEEKDAY, 99 Calendar.FRIDAY, Calendar.WEEKEND, 100 Calendar.SATURDAY, Calendar.WEEKEND, 101 }, 102 new Locale("hi", "IN"), new int[] { // Sunday only 103 Calendar.MONDAY, Calendar.WEEKDAY, 104 Calendar.FRIDAY, Calendar.WEEKDAY, 105 Calendar.SATURDAY, Calendar.WEEKDAY, 106 Calendar.SUNDAY, Calendar.WEEKEND, 107 }, 108 }; 109 110 // We only test the getDayOfWeekType() and isWeekend() APIs. 111 // The getWeekendTransition() API is tested indirectly via the 112 // isWeekend() API, which calls it. 113 114 for (int i1=0; i1<DATA1.length; i1+=2) { 115 Locale loc = (Locale)DATA1[i1]; 116 int[] data = (int[]) DATA1[i1+1]; 117 Calendar cal = Calendar.getInstance(loc); 118 logln("Locale: " + loc); 119 for (int i=0; i<data.length; i+=6) { 120 cal.clear(); 121 cal.set(data[i], data[i+1], data[i+2], data[i+3], 0, 0); 122 if (data[i+4] != 0) { 123 cal.setTime(new Date(cal.getTime().getTime() + data[i+4])); 124 } 125 boolean isWeekend = cal.isWeekend(); 126 boolean ok = isWeekend == (data[i+5] != 0); 127 if (ok) { 128 logln("Ok: " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend); 129 } else { 130 errln("FAIL: " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend + 131 ", expected=" + (!isWeekend)); 132 } 133 } 134 } 135 136 for (int i2=0; i2<DATA2.length; i2+=2) { 137 Locale loc = (Locale)DATA2[i2]; 138 int[] data = (int[]) DATA2[i2+1]; 139 logln("Locale: " + loc); 140 Calendar cal = Calendar.getInstance(loc); 141 for (int i=0; i<data.length; i+=2) { 142 int type = cal.getDayOfWeekType(data[i]); 143 int exp = data[i+1]; 144 if (type == exp) { 145 logln("Ok: DOW " + data[i] + " type=" + type); 146 } else { 147 errln("FAIL: DOW " + data[i] + " type=" + type + 148 ", expected=" + exp); 149 } 150 } 151 } 152 } 153 154 /** 155 * Run a test of a quasi-Gregorian calendar. This is a calendar 156 * that behaves like a Gregorian but has different year/era mappings. 157 * The int[] data array should have the format: 158 * 159 * { era, year, gregorianYear, month, dayOfMonth, ... } 160 */ 161 void quasiGregorianTest(Calendar cal, int[] data) { 162 // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as 163 // a reference throws us off by one hour. This is most likely 164 // due to the JDK 1.4 incorporation of historical time zones. 165 //java.util.Calendar grego = java.util.Calendar.getInstance(); 166 Calendar grego = Calendar.getInstance(); 167 for (int i=0; i<data.length; ) { 168 int era = data[i++]; 169 int year = data[i++]; 170 int gregorianYear = data[i++]; 171 int month = data[i++]; 172 int dayOfMonth = data[i++]; 173 174 grego.clear(); 175 grego.set(gregorianYear, month, dayOfMonth); 176 Date D = grego.getTime(); 177 178 cal.clear(); 179 cal.set(Calendar.ERA, era); 180 cal.set(year, month, dayOfMonth); 181 Date d = cal.getTime(); 182 if (d.equals(D)) { 183 logln("OK: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + 184 " => " + d); 185 } else { 186 errln("Fail: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + 187 " => " + d + ", expected " + D); 188 } 189 190 cal.clear(); 191 cal.setTime(D); 192 int e = cal.get(Calendar.ERA); 193 int y = cal.get(Calendar.YEAR); 194 if (y == year && e == era) { 195 logln("OK: " + D + " => " + cal.get(Calendar.ERA) + ":" + 196 cal.get(Calendar.YEAR) + "/" + 197 (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE)); 198 } else { 199 logln("Fail: " + D + " => " + cal.get(Calendar.ERA) + ":" + 200 cal.get(Calendar.YEAR) + "/" + 201 (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE) + 202 ", expected " + era + ":" + year + "/" + (month+1) + "/" + 203 dayOfMonth); 204 } 205 } 206 } 207 208 /** 209 * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise 210 * behaves like GregorianCalendar. 211 */ 212 @Test 213 public void TestBuddhist() { 214 quasiGregorianTest(new BuddhistCalendar(), 215 new int[] { 216 // BE 2542 == 1999 CE 217 0, 2542, 1999, Calendar.JUNE, 4 218 }); 219 } 220 221 @Test 222 public void TestBuddhistCoverage() { 223 { 224 // new BuddhistCalendar(ULocale) 225 BuddhistCalendar cal = new BuddhistCalendar(ULocale.getDefault()); 226 if(cal == null){ 227 errln("could not create BuddhistCalendar with ULocale"); 228 } 229 } 230 231 { 232 // new BuddhistCalendar(TimeZone,ULocale) 233 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(),ULocale.getDefault()); 234 if(cal == null){ 235 errln("could not create BuddhistCalendar with TimeZone ULocale"); 236 } 237 } 238 239 { 240 // new BuddhistCalendar(TimeZone) 241 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault()); 242 if(cal == null){ 243 errln("could not create BuddhistCalendar with TimeZone"); 244 } 245 } 246 247 { 248 // new BuddhistCalendar(Locale) 249 BuddhistCalendar cal = new BuddhistCalendar(Locale.getDefault()); 250 if(cal == null){ 251 errln("could not create BuddhistCalendar with Locale"); 252 } 253 } 254 255 { 256 // new BuddhistCalendar(TimeZone, Locale) 257 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(), Locale.getDefault()); 258 if(cal == null){ 259 errln("could not create BuddhistCalendar with TimeZone and Locale"); 260 } 261 } 262 263 { 264 // new BuddhistCalendar(Date) 265 BuddhistCalendar cal = new BuddhistCalendar(new Date()); 266 if(cal == null){ 267 errln("could not create BuddhistCalendar with Date"); 268 } 269 } 270 271 { 272 // new BuddhistCalendar(int year, int month, int date) 273 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22); 274 if(cal == null){ 275 errln("could not create BuddhistCalendar with year,month,data"); 276 } 277 } 278 279 { 280 // new BuddhistCalendar(int year, int month, int date, int hour, int minute, int second) 281 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22, 1, 1, 1); 282 if(cal == null){ 283 errln("could not create BuddhistCalendar with year,month,date,hour,minute,second"); 284 } 285 } 286 287 { 288 // data 289 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22); 290 Date time = cal.getTime(); 291 292 String[] calendarLocales = { 293 "th_TH" 294 }; 295 296 String[] formatLocales = { 297 "en", "ar", "hu", "th" 298 }; 299 300 for (int i = 0; i < calendarLocales.length; ++i) { 301 String calLocName = calendarLocales[i]; 302 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName); 303 cal = new BuddhistCalendar(calLocale); 304 305 for (int j = 0; j < formatLocales.length; ++j) { 306 String locName = formatLocales[j]; 307 Locale formatLocale = LocaleUtility.getLocaleFromName(locName); 308 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale); 309 logln(calLocName + "/" + locName + " --> " + format.format(time)); 310 } 311 } 312 } 313 } 314 315 /** 316 * Test limits of the Buddhist calendar. 317 */ 318 @Test 319 public void TestBuddhistLimits() { 320 // Final parameter is either number of days, if > 0, or test 321 // duration in seconds, if < 0. 322 Calendar cal = Calendar.getInstance(); 323 cal.set(2007, Calendar.JANUARY, 1); 324 BuddhistCalendar buddhist = new BuddhistCalendar(); 325 doLimitsTest(buddhist, null, cal.getTime()); 326 doTheoreticalLimitsTest(buddhist, false); 327 } 328 329 /** 330 * Default calendar for Thai (Ticket#6302) 331 */ 332 @Test 333 public void TestThaiDefault() { 334 // Buddhist calendar is used as the default calendar for 335 // Thai locale 336 Calendar cal = Calendar.getInstance(new ULocale("th_TH")); 337 String type = cal.getType(); 338 // Android patch: Force default Gregorian calendar. 339 if (!type.equals("gregorian")) { 340 errln("FAIL: Gregorian calendar is not returned for locale " + cal.toString()); 341 } 342 // Android patch end. 343 } 344 345 /** 346 * Verify that TaiwanCalendar shifts years to Minguo Era but otherwise 347 * behaves like GregorianCalendar. 348 */ 349 @Test 350 public void TestTaiwan() { 351 quasiGregorianTest(new TaiwanCalendar(), 352 new int[] { 353 TaiwanCalendar.BEFORE_MINGUO, 8, 1904, Calendar.FEBRUARY, 29, 354 TaiwanCalendar.MINGUO, 1, 1912, Calendar.JUNE, 4, 355 TaiwanCalendar.MINGUO, 3, 1914, Calendar.FEBRUARY, 12, 356 TaiwanCalendar.MINGUO, 96,2007, Calendar.FEBRUARY, 12, 357 }); 358 } 359 360 /** 361 * Test limits of the Taiwan calendar. 362 */ 363 @Test 364 public void TestTaiwanLimits() { 365 // Final parameter is either number of days, if > 0, or test 366 // duration in seconds, if < 0. 367 Calendar cal = Calendar.getInstance(); 368 cal.set(2007, Calendar.JANUARY, 1); 369 TaiwanCalendar taiwan = new TaiwanCalendar(); 370 doLimitsTest(taiwan, null, cal.getTime()); 371 doTheoreticalLimitsTest(taiwan, false); 372 } 373 374 @Test 375 public void TestTaiwanCoverage() { 376 { 377 // new TaiwanCalendar(ULocale) 378 TaiwanCalendar cal = new TaiwanCalendar(ULocale.getDefault()); 379 if(cal == null){ 380 errln("could not create TaiwanCalendar with ULocale"); 381 } 382 } 383 384 { 385 // new TaiwanCalendar(TimeZone,ULocale) 386 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(),ULocale.getDefault()); 387 if(cal == null){ 388 errln("could not create TaiwanCalendar with TimeZone ULocale"); 389 } 390 } 391 392 { 393 // new TaiwanCalendar(TimeZone) 394 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault()); 395 if(cal == null){ 396 errln("could not create TaiwanCalendar with TimeZone"); 397 } 398 } 399 400 { 401 // new TaiwanCalendar(Locale) 402 TaiwanCalendar cal = new TaiwanCalendar(Locale.getDefault()); 403 if(cal == null){ 404 errln("could not create TaiwanCalendar with Locale"); 405 } 406 } 407 408 { 409 // new TaiwanCalendar(TimeZone, Locale) 410 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(), Locale.getDefault()); 411 if(cal == null){ 412 errln("could not create TaiwanCalendar with TimeZone and Locale"); 413 } 414 } 415 416 { 417 // new TaiwanCalendar(Date) 418 TaiwanCalendar cal = new TaiwanCalendar(new Date()); 419 if(cal == null){ 420 errln("could not create TaiwanCalendar with Date"); 421 } 422 } 423 424 { 425 // new TaiwanCalendar(int year, int month, int date) 426 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22); 427 if(cal == null){ 428 errln("could not create TaiwanCalendar with year,month,data"); 429 } 430 } 431 432 { 433 // new TaiwanCalendar(int year, int month, int date, int hour, int minute, int second) 434 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22, 1, 1, 1); 435 if(cal == null){ 436 errln("could not create TaiwanCalendar with year,month,date,hour,minute,second"); 437 } 438 } 439 440 { 441 // data 442 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22); 443 Date time = cal.getTime(); 444 445 String[] calendarLocales = { 446 "en","zh" 447 }; 448 449 String[] formatLocales = { 450 "en", "ar", "hu", "th" 451 }; 452 453 for (int i = 0; i < calendarLocales.length; ++i) { 454 String calLocName = calendarLocales[i]; 455 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName); 456 cal = new TaiwanCalendar(calLocale); 457 458 for (int j = 0; j < formatLocales.length; ++j) { 459 String locName = formatLocales[j]; 460 Locale formatLocale = LocaleUtility.getLocaleFromName(locName); 461 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale); 462 logln(calLocName + "/" + locName + " --> " + format.format(time)); 463 } 464 } 465 } 466 } 467 468 /** 469 * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise 470 * behaves like GregorianCalendar. 471 */ 472 @Test 473 public void TestJapanese() { 474 // First make sure this test works for GregorianCalendar 475 int[] control = { 476 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 8, 477 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 9, 478 GregorianCalendar.AD, 1869, 1869, Calendar.JUNE, 4, 479 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 29, 480 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 30, 481 GregorianCalendar.AD, 1912, 1912, Calendar.AUGUST, 1, 482 }; 483 quasiGregorianTest(new GregorianCalendar(), control); 484 485 int[] data = { 486 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 8, 487 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 9, 488 JapaneseCalendar.MEIJI, 2, 1869, Calendar.JUNE, 4, 489 JapaneseCalendar.MEIJI, 45, 1912, Calendar.JULY, 29, 490 JapaneseCalendar.TAISHO, 1, 1912, Calendar.JULY, 30, 491 JapaneseCalendar.TAISHO, 1, 1912, Calendar.AUGUST, 1, 492 }; 493 quasiGregorianTest(new JapaneseCalendar(), data); 494 } 495 496 /** 497 * Test limits of the Gregorian calendar. 498 */ 499 @Test 500 public void TestGregorianLimits() { 501 // Final parameter is either number of days, if > 0, or test 502 // duration in seconds, if < 0. 503 Calendar cal = Calendar.getInstance(); 504 cal.set(2004, Calendar.JANUARY, 1); 505 GregorianCalendar gregorian = new GregorianCalendar(); 506 doLimitsTest(gregorian, null, cal.getTime()); 507 doTheoreticalLimitsTest(gregorian, false); 508 } 509 510 /** 511 * Test behavior of fieldDifference around leap years. Also test a large 512 * field difference to check binary search. 513 */ 514 @Test 515 public void TestLeapFieldDifference() { 516 Calendar cal = Calendar.getInstance(); 517 cal.set(2004, Calendar.FEBRUARY, 29); 518 Date date2004 = cal.getTime(); 519 cal.set(2000, Calendar.FEBRUARY, 29); 520 Date date2000 = cal.getTime(); 521 int y = cal.fieldDifference(date2004, Calendar.YEAR); 522 int d = cal.fieldDifference(date2004, Calendar.DAY_OF_YEAR); 523 if (d == 0) { 524 logln("Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days"); 525 } else { 526 errln("FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days"); 527 } 528 cal.setTime(date2004); 529 y = cal.fieldDifference(date2000, Calendar.YEAR); 530 d = cal.fieldDifference(date2000, Calendar.DAY_OF_YEAR); 531 if (d == 0) { 532 logln("Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days"); 533 } else { 534 errln("FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days"); 535 } 536 // Test large difference 537 cal.set(2001, Calendar.APRIL, 5); // 2452005 538 Date ayl = cal.getTime(); 539 cal.set(1964, Calendar.SEPTEMBER, 7); // 2438646 540 Date asl = cal.getTime(); 541 d = cal.fieldDifference(ayl, Calendar.DAY_OF_MONTH); 542 cal.setTime(ayl); 543 int d2 = cal.fieldDifference(asl, Calendar.DAY_OF_MONTH); 544 if (d == -d2 && d == 13359) { 545 logln("Ok: large field difference symmetrical " + d); 546 } else { 547 logln("FAIL: large field difference incorrect " + d + ", " + d2 + 548 ", expect +/- 13359"); 549 } 550 } 551 552 /** 553 * Test ms_MY "Malay (Malaysia)" locale. Bug 1543. 554 */ 555 @Test 556 public void TestMalaysianInstance() { 557 Locale loc = new Locale("ms", "MY"); // Malay (Malaysia) 558 Calendar cal = Calendar.getInstance(loc); 559 if(cal == null){ 560 errln("could not create Malaysian instance"); 561 } 562 } 563 564 /** 565 * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the 566 * field <=> time mapping, since they affect the interpretation of 567 * the WEEK_OF_MONTH or WEEK_OF_YEAR fields. 568 */ 569 @Test 570 public void TestWeekShift() { 571 Calendar cal = new GregorianCalendar( 572 TimeZone.getTimeZone("America/Los_Angeles"), 573 new Locale("en", "US")); 574 cal.setTime(new Date(997257600000L)); // Wed Aug 08 01:00:00 PDT 2001 575 // In pass one, change the first day of week so that the weeks 576 // shift in August 2001. In pass two, change the minimal days 577 // in the first week so that the weeks shift in August 2001. 578 // August 2001 579 // Su Mo Tu We Th Fr Sa 580 // 1 2 3 4 581 // 5 6 7 8 9 10 11 582 // 12 13 14 15 16 17 18 583 // 19 20 21 22 23 24 25 584 // 26 27 28 29 30 31 585 for (int pass=0; pass<2; ++pass) { 586 if (pass==0) { 587 cal.setFirstDayOfWeek(Calendar.WEDNESDAY); 588 cal.setMinimalDaysInFirstWeek(4); 589 } else { 590 cal.setFirstDayOfWeek(Calendar.SUNDAY); 591 cal.setMinimalDaysInFirstWeek(4); 592 } 593 cal.add(Calendar.DATE, 1); // Force recalc 594 cal.add(Calendar.DATE, -1); 595 596 Date time1 = cal.getTime(); // Get time -- should not change 597 598 // Now change a week parameter and then force a recalc. 599 // The bug is that the recalc should not be necessary -- 600 // calendar should do so automatically. 601 if (pass==0) { 602 cal.setFirstDayOfWeek(Calendar.THURSDAY); 603 } else { 604 cal.setMinimalDaysInFirstWeek(5); 605 } 606 607 int woy1 = cal.get(Calendar.WEEK_OF_YEAR); 608 int wom1 = cal.get(Calendar.WEEK_OF_MONTH); 609 610 cal.add(Calendar.DATE, 1); // Force recalc 611 cal.add(Calendar.DATE, -1); 612 613 int woy2 = cal.get(Calendar.WEEK_OF_YEAR); 614 int wom2 = cal.get(Calendar.WEEK_OF_MONTH); 615 616 Date time2 = cal.getTime(); 617 618 if (!time1.equals(time2)) { 619 errln("FAIL: shifting week should not alter time"); 620 } else { 621 logln(time1.toString()); 622 } 623 if (woy1 == woy2 && wom1 == wom2) { 624 logln("Ok: WEEK_OF_YEAR: " + woy1 + 625 ", WEEK_OF_MONTH: " + wom1); 626 } else { 627 errln("FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 + 628 ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 + 629 " after week shift"); 630 } 631 } 632 } 633 634 /** 635 * Make sure that when adding a day, we actually wind up in a 636 * different day. The DST adjustments we use to keep the hour 637 * constant across DST changes can backfire and change the day. 638 */ 639 @Test 640 public void TestTimeZoneTransitionAdd() { 641 Locale locale = Locale.US; // could also be CHINA 642 SimpleDateFormat dateFormat = 643 new SimpleDateFormat("MM/dd/yyyy HH:mm z", locale); 644 645 String tz[] = TimeZone.getAvailableIDs(); 646 647 for (int z=0; z<tz.length; ++z) { 648 TimeZone t = TimeZone.getTimeZone(tz[z]); 649 dateFormat.setTimeZone(t); 650 651 Calendar cal = Calendar.getInstance(t, locale); 652 cal.clear(); 653 // Scan the year 2003, overlapping the edges of the year 654 cal.set(Calendar.YEAR, 2002); 655 cal.set(Calendar.MONTH, Calendar.DECEMBER); 656 cal.set(Calendar.DAY_OF_MONTH, 25); 657 658 for (int i=0; i<365+10; ++i) { 659 Date yesterday = cal.getTime(); 660 int yesterday_day = cal.get(Calendar.DAY_OF_MONTH); 661 cal.add(Calendar.DAY_OF_MONTH, 1); 662 if (yesterday_day == cal.get(Calendar.DAY_OF_MONTH)) { 663 errln(tz[z] + " " + 664 dateFormat.format(yesterday) + " +1d= " + 665 dateFormat.format(cal.getTime())); 666 } 667 } 668 } 669 } 670 671 @Test 672 public void TestJB1684() { 673 class TestData { 674 int year; 675 int month; 676 int date; 677 int womyear; 678 int wommon; 679 int wom; 680 int dow; 681 String data; 682 String normalized; 683 684 public TestData(int year, int month, int date, 685 int womyear, int wommon, int wom, int dow, 686 String data, String normalized) { 687 this.year = year; 688 this.month = month-1; 689 this.date = date; 690 this.womyear = womyear; 691 this.wommon = wommon-1; 692 this.wom = wom; 693 this.dow = dow; 694 this.data = data; // year, month, week of month, day 695 this.normalized = data; 696 if (normalized != null) this.normalized = normalized; 697 } 698 } 699 700 // July 2001 August 2001 January 2002 701 // Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 702 // 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 5 703 // 8 9 10 11 12 13 14 5 6 7 8 9 10 11 6 7 8 9 10 11 12 704 // 15 16 17 18 19 20 21 12 13 14 15 16 17 18 13 14 15 16 17 18 19 705 // 22 23 24 25 26 27 28 19 20 21 22 23 24 25 20 21 22 23 24 25 26 706 // 29 30 31 26 27 28 29 30 31 27 28 29 30 31 707 TestData[] tests = { 708 new TestData(2001, 8, 6, 2001,8,2,Calendar.MONDAY, "2001 08 02 Mon", null), 709 new TestData(2001, 8, 7, 2001,8,2,Calendar.TUESDAY, "2001 08 02 Tue", null), 710 new TestData(2001, 8, 5,/*12,*/ 2001,8,2,Calendar.SUNDAY, "2001 08 02 Sun", null), 711 new TestData(2001, 8,6, /*7, 30,*/ 2001,7,6,Calendar.MONDAY, "2001 07 06 Mon", "2001 08 02 Mon"), 712 new TestData(2001, 8,7, /*7, 31,*/ 2001,7,6,Calendar.TUESDAY, "2001 07 06 Tue", "2001 08 02 Tue"), 713 new TestData(2001, 8, 5, 2001,7,6,Calendar.SUNDAY, "2001 07 06 Sun", "2001 08 02 Sun"), 714 new TestData(2001, 7, 30, 2001,8,1,Calendar.MONDAY, "2001 08 01 Mon", "2001 07 05 Mon"), 715 new TestData(2001, 7, 31, 2001,8,1,Calendar.TUESDAY, "2001 08 01 Tue", "2001 07 05 Tue"), 716 new TestData(2001, 7,29, /*8, 5,*/ 2001,8,1,Calendar.SUNDAY, "2001 08 01 Sun", "2001 07 05 Sun"), 717 new TestData(2001, 12, 31, 2001,12,6,Calendar.MONDAY, "2001 12 06 Mon", null), 718 new TestData(2002, 1, 1, 2002,1,1,Calendar.TUESDAY, "2002 01 01 Tue", null), 719 new TestData(2002, 1, 2, 2002,1,1,Calendar.WEDNESDAY, "2002 01 01 Wed", null), 720 new TestData(2002, 1, 3, 2002,1,1,Calendar.THURSDAY, "2002 01 01 Thu", null), 721 new TestData(2002, 1, 4, 2002,1,1,Calendar.FRIDAY, "2002 01 01 Fri", null), 722 new TestData(2002, 1, 5, 2002,1,1,Calendar.SATURDAY, "2002 01 01 Sat", null), 723 new TestData(2001,12,30, /*2002, 1, 6,*/ 2002,1,1,Calendar.SUNDAY, "2002 01 01 Sun", "2001 12 06 Sun"), 724 }; 725 726 int pass = 0, error = 0, warning = 0; 727 728 final String pattern = "yyyy MM WW EEE"; 729 GregorianCalendar cal = new GregorianCalendar(); 730 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 731 sdf.setCalendar(cal); 732 733 cal.setFirstDayOfWeek(Calendar.SUNDAY); 734 cal.setMinimalDaysInFirstWeek(1); 735 736 for (int i = 0; i < tests.length; ++i) { 737 TestData test = tests[i]; 738 log("\n-----\nTesting round trip of " + test.year + 739 " " + (test.month + 1) + 740 " " + test.date + 741 " (written as) " + test.data); 742 743 cal.clear(); 744 cal.set(test.year, test.month, test.date); 745 Date ms = cal.getTime(); 746 747 cal.clear(); 748 cal.set(Calendar.YEAR, test.womyear); 749 cal.set(Calendar.MONTH, test.wommon); 750 cal.set(Calendar.WEEK_OF_MONTH, test.wom); 751 cal.set(Calendar.DAY_OF_WEEK, test.dow); 752 Date ms2 = cal.getTime(); 753 754 if (!ms2.equals(ms)) { 755 log("\nError: GregorianCalendar.DOM gave " + ms + 756 "\n GregorianCalendar.WOM gave " + ms2); 757 error++; 758 } else { 759 pass++; 760 } 761 762 ms2 = null; 763 try { 764 ms2 = sdf.parse(test.data); 765 } 766 catch (ParseException e) { 767 errln("parse exception: " + e); 768 } 769 770 if (!ms2.equals(ms)) { 771 log("\nError: GregorianCalendar gave " + ms + 772 "\n SimpleDateFormat.parse gave " + ms2); 773 error++; 774 } else { 775 pass++; 776 } 777 778 String result = sdf.format(ms); 779 if (!result.equals(test.normalized)) { 780 log("\nWarning: format of '" + test.data + "' gave" + 781 "\n '" + result + "'" + 782 "\n expected '" + test.normalized + "'"); 783 warning++; 784 } else { 785 pass++; 786 } 787 788 Date ms3 = null; 789 try { 790 ms3 = sdf.parse(result); 791 } 792 catch (ParseException e) { 793 errln("parse exception 2: " + e); 794 } 795 796 if (!ms3.equals(ms)) { 797 error++; 798 log("\nError: Re-parse of '" + result + "' gave time of " + 799 "\n " + ms3 + 800 "\n not " + ms); 801 } else { 802 pass++; 803 } 804 } 805 String info = "\nPassed: " + pass + ", Warnings: " + warning + ", Errors: " + error; 806 if (error > 0) { 807 errln(info); 808 } else { 809 logln(info); 810 } 811 } 812 813 /** 814 * Test the ZoneMeta API. 815 */ 816 @Test 817 public void TestZoneMeta() { 818 // Test index by country API 819 820 // Format: {country, zone1, zone2, ..., zoneN} 821 String COUNTRY[][] = { {""}, 822 {"US", "America/Los_Angeles", "PST"} }; 823 StringBuffer buf = new StringBuffer(); 824 for (int i=0; i<COUNTRY.length; ++i) { 825 Set<String> a = ZoneMeta.getAvailableIDs(SystemTimeZoneType.ANY, COUNTRY[i][0], null); 826 buf.setLength(0); 827 buf.append("Country \"" + COUNTRY[i][0] + "\": ["); 828 // Use bitmask to track which of the expected zones we see 829 int mask = 0; 830 boolean first = true; 831 for (String z : a) { 832 if (first) { 833 first = false; 834 } else { 835 buf.append(", "); 836 } 837 buf.append(z); 838 for (int k = 1; k < COUNTRY[i].length; ++k) { 839 if ((mask & (1 << k)) == 0 && z.equals(COUNTRY[i][k])) { 840 mask |= (1 << k); 841 } 842 } 843 } 844 buf.append("]"); 845 mask >>= 1; 846 // Check bitmask to see if we saw all expected zones 847 if (mask == (1 << (COUNTRY[i].length-1))-1) { 848 logln(buf.toString()); 849 } else { 850 errln(buf.toString()); 851 } 852 } 853 854 // Test equivalent IDs API 855 856 int n = ZoneMeta.countEquivalentIDs("PST"); 857 boolean ok = false; 858 buf.setLength(0); 859 buf.append("Equivalent to PST: "); 860 for (int i=0; i<n; ++i) { 861 String id = ZoneMeta.getEquivalentID("PST", i); 862 if (id.equals("America/Los_Angeles")) { 863 ok = true; 864 } 865 if (i!=0) buf.append(", "); 866 buf.append(id); 867 } 868 if (ok) { 869 logln(buf.toString()); 870 } else { 871 errln(buf.toString()); 872 } 873 } 874 875 @Test 876 public void TestComparable() { 877 GregorianCalendar c0 = new GregorianCalendar(); 878 GregorianCalendar c1 = new GregorianCalendar(); 879 c1.add(Calendar.DAY_OF_MONTH, 1); 880 if (c0.compareTo(c1) >= 0) { 881 errln("calendar " + c0 + " not < " + c1); 882 } 883 c0.add(Calendar.MONTH, 1); 884 if (c0.compareTo(c1) <= 0) { 885 errln("calendar " + c0 + " not > " + c1); 886 } 887 888 c0.setTimeInMillis(c1.getTimeInMillis()); 889 if (c0.compareTo(c1) != 0) { 890 errln("calendar " + c0 + " not == " + c1); 891 } 892 893 } 894 895 /** 896 * Miscellaneous tests to increase coverage. 897 */ 898 @Test 899 public void TestCoverage() { 900 // BuddhistCalendar 901 BuddhistCalendar bcal = new BuddhistCalendar(); 902 /*int i =*/ bcal.getMinimum(Calendar.ERA); 903 bcal.add(Calendar.YEAR, 1); 904 bcal.add(Calendar.MONTH, 1); 905 /*Date d = */bcal.getTime(); 906 907 // CalendarAstronomer 908 // (This class should probably be made package-private.) 909 CalendarAstronomer astro = new CalendarAstronomer(); 910 /*String s = */astro.local(0); 911 912 // ChineseCalendar 913 ChineseCalendar ccal = new ChineseCalendar(TimeZone.getDefault(), 914 Locale.getDefault()); 915 ccal.add(Calendar.MONTH, 1); 916 ccal.add(Calendar.YEAR, 1); 917 ccal.roll(Calendar.MONTH, 1); 918 ccal.roll(Calendar.YEAR, 1); 919 ccal.getTime(); 920 921 // ICU 2.6 922 Calendar cal = Calendar.getInstance(Locale.US); 923 logln(cal.toString()); 924 logln(cal.getDisplayName(Locale.US)); 925 int weekendOnset=-1; 926 int weekendCease=-1; 927 for (int i=Calendar.SUNDAY; i<=Calendar.SATURDAY; ++i) { 928 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_ONSET) { 929 weekendOnset = i; 930 } 931 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_CEASE) { 932 weekendCease = i; 933 } 934 } 935 // can't call this unless we get a transition day (unusual), 936 // but make the call anyway for coverage reasons 937 try { 938 /*int x=*/ cal.getWeekendTransition(weekendOnset); 939 /*int x=*/ cal.getWeekendTransition(weekendCease); 940 } catch (IllegalArgumentException e) {} 941 /*int x=*/ cal.isWeekend(new Date()); 942 943 // new GregorianCalendar(ULocale) 944 GregorianCalendar gcal = new GregorianCalendar(ULocale.getDefault()); 945 if(gcal==null){ 946 errln("could not create GregorianCalendar with ULocale"); 947 } else { 948 logln("Calendar display name: " + gcal.getDisplayName(ULocale.getDefault())); 949 } 950 951 //cover getAvailableULocales 952 final ULocale[] locales = Calendar.getAvailableULocales(); 953 long count = locales.length; 954 if (count == 0) 955 errln("getAvailableULocales return empty list"); 956 logln("" + count + " available ulocales in Calendar."); 957 958 // Jitterbug 4451, for coverage 959 class StubCalendar extends Calendar{ 960 /** 961 * For serialization 962 */ 963 private static final long serialVersionUID = -4558903444622684759L; 964 965 @Override 966 protected int handleGetLimit(int field, int limitType) { 967 if (limitType == Calendar.LEAST_MAXIMUM) { 968 return 1; 969 } else if (limitType == Calendar.GREATEST_MINIMUM) { 970 return 7; 971 } 972 return -1; 973 } 974 @Override 975 protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) { 976 if (useMonth) { 977 return eyear * 365 + month * 31; 978 } else { 979 return eyear * 365; 980 } 981 } 982 @Override 983 protected int handleGetExtendedYear() {return 2017;} 984 985 public void run(){ 986 if (Calendar.gregorianPreviousMonthLength(2000,2) != 29){ 987 errln("Year 2000 Feb should have 29 days."); 988 } 989 long millis = Calendar.julianDayToMillis(Calendar.MAX_JULIAN); 990 if(millis != Calendar.MAX_MILLIS){ 991 errln("Did not get the expected value from julianDayToMillis. Got:" + millis); 992 } 993 DateFormat df = handleGetDateFormat("",Locale.getDefault()); 994 if (!df.equals(handleGetDateFormat("",ULocale.getDefault()))){ 995 errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)"); 996 } 997 if (!getType().equals("unknown")){ 998 errln ("Calendar.getType() should be 'unknown'"); 999 } 1000 1001 // Tests for complete coverage of Calendar functions. 1002 int julianDay = Calendar.millisToJulianDay(millis - 1); 1003 assertEquals("Julian max day -1", julianDay, Calendar.MAX_JULIAN - 1); 1004 1005 DateFormat df1 = handleGetDateFormat("GG yyyy-d:MM", "option=xyz", Locale.getDefault()); 1006 if (!df1.equals(handleGetDateFormat("GG yyyy-d:MM", "option=xyz", ULocale.getDefault()))){ 1007 errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)"); 1008 } 1009 1010 // Prove that the local overrides are used. 1011 int leastMsInDay = handleGetLimit(Calendar.MILLISECONDS_IN_DAY, Calendar.LEAST_MAXIMUM); 1012 assertEquals("getLimit test 1", leastMsInDay, 1); 1013 int maxMsInDay = handleGetLimit(Calendar.WEEK_OF_MONTH, Calendar.GREATEST_MINIMUM); 1014 assertEquals("getLimit test 2", 7, maxMsInDay); 1015 1016 int febLeapLength = handleGetMonthLength(2020, Calendar.FEBRUARY); 1017 assertEquals("handleMonthLength", 31, febLeapLength); 1018 int exYear = handleGetExtendedYear(); 1019 assertEquals("handleGetExtendeYear", exYear, 2017); 1020 int monthStart = handleComputeMonthStart(2016, 4, false); 1021 assertEquals("handleComputeMonthStart false", 735840, monthStart); 1022 monthStart = handleComputeMonthStart(2016, 4, true); 1023 assertEquals("handleComputeMonthStart true", 735964, monthStart); 1024 1025 Calendar cal = Calendar.getInstance(); 1026 cal.set(1980, 5, 2); 1027 this.setTime(cal.getTime()); 1028 assertEquals("handleComputeFields: year set", 1980, get(YEAR)); 1029 assertEquals("handleComputeFields: month set", 5, get(MONTH)); 1030 assertEquals("handleComputeFields: day set", 2, get(DAY_OF_MONTH)); 1031 } 1032 } 1033 StubCalendar stub = new StubCalendar(); 1034 stub.run(); 1035 } 1036 1037 // Tests for jb 4541 1038 @Test 1039 public void TestJB4541() { 1040 ULocale loc = new ULocale("en_US"); 1041 1042 // !!! Shouldn't we have an api like this? 1043 // !!! Question: should this reflect those actually available in this copy of ICU, or 1044 // the list of types we assume is available? 1045 // String[] calTypes = Calendar.getAvailableTypes(); 1046 final String[] calTypes = { 1047 "buddhist", "chinese", "coptic", "ethiopic", "gregorian", "hebrew", 1048 "islamic", "islamic-civil", "japanese", "roc" 1049 }; 1050 1051 // constructing a DateFormat with a locale indicating a calendar type should construct a 1052 // date format appropriate to that calendar 1053 final Date time = new Date(); 1054 for (int i = 0; i < calTypes.length; ++i) { 1055 ULocale aLoc = loc.setKeywordValue("calendar", calTypes[i]); 1056 logln("locale: " + aLoc); 1057 1058 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, 1059 DateFormat.FULL, 1060 aLoc); 1061 1062 logln("df type: " + df.getClass().getName() + " loc: " + df.getLocale(ULocale.VALID_LOCALE)); 1063 1064 Calendar cal = df.getCalendar(); 1065 assertEquals("calendar types", cal.getType(), calTypes[i]); 1066 DateFormat df2 = cal.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, ULocale.US); 1067 logln("df2 type: " + df2.getClass().getName() + " loc: " + df2.getLocale(ULocale.VALID_LOCALE)); 1068 assertEquals("format results", df.format(time), df2.format(time)); 1069 } 1070 1071 // dateFormat.setCalendar should throw exception if wrong format for calendar 1072 if (false) { 1073 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, 1074 DateFormat.FULL, 1075 new ULocale("en_US@calendar=chinese")); 1076 1077 logln("dateformat type: " + df.getClass().getName()); 1078 1079 Calendar cal = Calendar.getInstance(new ULocale("en_US@calendar=chinese")); 1080 1081 logln("calendar type: " + cal.getClass().getName()); 1082 } 1083 } 1084 1085 @Test 1086 public void TestTypes() { 1087 String[] locs = { 1088 "en_US_VALLEYGIRL", 1089 "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese", 1090 "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian", 1091 "ja_JP@calendar=japanese", 1092 "th_TH@calendar=buddhist", 1093 "th-TH-u-ca-gregory", 1094 "ja_JP_TRADITIONAL", 1095 "th_TH_TRADITIONAL", 1096 "th_TH_TRADITIONAL@calendar=gregorian", 1097 "en_US", 1098 "th_TH", // Default calendar for th_TH is buddhist 1099 "th", // th's default region is TH and buddhist is used as default for TH 1100 "en_TH", // Default calendar for any locales with region TH is buddhist 1101 "th_TH@calendar=iso8601", // iso8601 calendar type 1102 "fr_CH", 1103 "fr_SA", 1104 "fr_CH@rg=sazzzz", 1105 "fr_CH@calendar=japanese;rg=sazzzz", 1106 "fr_TH@rg=SA", // ignore malformed rg tag, use buddhist 1107 "th@rg=SA", // ignore malformed rg tag, use buddhist 1108 }; 1109 1110 // Android patch: Force default Gregorian calendar. 1111 String[] types = { 1112 "gregorian", 1113 "japanese", 1114 "gregorian", 1115 "japanese", 1116 "buddhist", 1117 "gregorian", 1118 "japanese", 1119 "buddhist", 1120 "gregorian", 1121 "gregorian", 1122 "gregorian", 1123 "gregorian", 1124 "gregorian", 1125 "gregorian", // iso8601 is a gregorian sub type 1126 "gregorian", 1127 "gregorian", 1128 "gregorian", 1129 "japanese", 1130 "gregorian", 1131 "gregorian", 1132 }; 1133 // Android patch end. 1134 1135 for (int i = 0; i < locs.length; i++) { 1136 Calendar cal = Calendar.getInstance(new ULocale(locs[i])); 1137 if (!cal.getType().equals(types[i])) { 1138 errln(locs[i] + " Calendar type " + cal.getType() + " instead of " + types[i]); 1139 } 1140 } 1141 } 1142 1143 @Test 1144 public void TestISO8601() { 1145 final ULocale[] TEST_LOCALES = { 1146 new ULocale("en_US@calendar=iso8601"), 1147 new ULocale("en_US@calendar=Iso8601"), 1148 new ULocale("th_TH@calendar=iso8601"), 1149 new ULocale("ar_EG@calendar=iso8601") 1150 }; 1151 1152 final int[][] TEST_DATA = { 1153 // {<year>, <week# of Jan 1>, <week# year of Jan 1>} 1154 {2008, 1, 2008}, 1155 {2009, 1, 2009}, 1156 {2010, 53, 2009}, 1157 {2011, 52, 2010}, 1158 {2012, 52, 2011}, 1159 {2013, 1, 2013}, 1160 {2014, 1, 2014}, 1161 }; 1162 1163 for (ULocale locale : TEST_LOCALES) { 1164 Calendar cal = Calendar.getInstance(locale); 1165 // No matter what locale is used, if calendar type is "iso8601", 1166 // calendar type must be Gregorian 1167 if (!cal.getType().equals("gregorian")) { 1168 errln("Error: Gregorian calendar is not used for locale: " + locale); 1169 } 1170 1171 for (int[] data : TEST_DATA) { 1172 cal.set(data[0], Calendar.JANUARY, 1); 1173 int weekNum = cal.get(Calendar.WEEK_OF_YEAR); 1174 int weekYear = cal.get(Calendar.YEAR_WOY); 1175 1176 if (weekNum != data[1] || weekYear != data[2]) { 1177 errln("Error: Incorrect week of year on January 1st, " + data[0] 1178 + " for locale " + locale 1179 + ": Returned [weekNum=" + weekNum + ", weekYear=" + weekYear 1180 + "], Expected [weekNum=" + data[1] + ", weekYear=" + data[2] + "]"); 1181 } 1182 } 1183 } 1184 } 1185 1186 private static class CalFields { 1187 private int year; 1188 private int month; 1189 private int day; 1190 private int hour; 1191 private int min; 1192 private int sec; 1193 private int ms; 1194 1195 CalFields(int year, int month, int day, int hour, int min, int sec) { 1196 this(year, month, day, hour, min, sec, 0); 1197 } 1198 1199 CalFields(int year, int month, int day, int hour, int min, int sec, int ms) { 1200 this.year = year; 1201 this.month = month; 1202 this.day = day; 1203 this.hour = hour; 1204 this.min = min; 1205 this.sec = sec; 1206 this.ms = ms; 1207 } 1208 1209 void setTo(Calendar cal) { 1210 cal.clear(); 1211 cal.set(year, month - 1, day, hour, min, sec); 1212 cal.set(Calendar.MILLISECOND, ms); 1213 } 1214 1215 @Override 1216 public String toString() { 1217 return String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms); 1218 } 1219 1220 @Override 1221 public boolean equals(Object other) { 1222 if (other instanceof CalFields) { 1223 CalFields otr = (CalFields)other; 1224 return (year == otr.year 1225 && month == otr.month 1226 && day == otr.day 1227 && hour == otr.hour 1228 && min == otr.min 1229 && sec == otr.sec 1230 && ms == otr.ms); 1231 } 1232 return false; 1233 } 1234 1235 boolean isEquivalentTo(Calendar cal) { 1236 return year == cal.get(Calendar.YEAR) 1237 && month == cal.get(Calendar.MONTH) + 1 1238 && day == cal.get(Calendar.DAY_OF_MONTH) 1239 && hour == cal.get(Calendar.HOUR_OF_DAY) 1240 && min == cal.get(Calendar.MINUTE) 1241 && sec == cal.get(Calendar.SECOND) 1242 && ms == cal.get(Calendar.MILLISECOND); 1243 } 1244 1245 static CalFields createFrom(Calendar cal) { 1246 int year = cal.get(Calendar.YEAR); 1247 int month = cal.get(Calendar.MONTH) + 1; 1248 int day = cal.get(Calendar.DAY_OF_MONTH); 1249 int hour = cal.get(Calendar.HOUR_OF_DAY); 1250 int min = cal.get(Calendar.MINUTE); 1251 int sec = cal.get(Calendar.SECOND); 1252 1253 return new CalFields(year, month, day, hour, min, sec); 1254 } 1255 } 1256 1257 @Test 1258 public void TestAmbiguousWallTimeAPIs() { 1259 Calendar cal = Calendar.getInstance(); 1260 1261 assertEquals("Default repeated wall time option", cal.getRepeatedWallTimeOption(), Calendar.WALLTIME_LAST); 1262 assertEquals("Default skipped wall time option", cal.getSkippedWallTimeOption(), Calendar.WALLTIME_LAST); 1263 1264 Calendar cal2 = (Calendar)cal.clone(); 1265 1266 assertTrue("Equality", cal2.equals(cal)); 1267 assertTrue("Hash code", cal.hashCode() == cal2.hashCode()); 1268 1269 cal2.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST); 1270 cal2.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST); 1271 1272 assertFalse("Equality after mod", cal2.equals(cal)); 1273 assertFalse("Hash code after mod", cal.hashCode() == cal2.hashCode()); 1274 1275 assertEquals("getRepeatedWallTimeOption after mod", cal2.getRepeatedWallTimeOption(), Calendar.WALLTIME_FIRST); 1276 assertEquals("getSkippedWallTimeOption after mod", cal2.getSkippedWallTimeOption(), Calendar.WALLTIME_FIRST); 1277 1278 try { 1279 cal.setRepeatedWallTimeOption(Calendar.WALLTIME_NEXT_VALID); 1280 errln("IAE expected on setRepeatedWallTimeOption(WALLTIME_NEXT_VALID"); 1281 } catch (IllegalArgumentException e) { 1282 // expected 1283 } 1284 } 1285 1286 @Test 1287 public void TestRepeatedWallTime() { 1288 final Object[][] TESTDATA = { 1289 // Time zone Input wall time WALLTIME_LAST in GMT WALLTIME_FIRST in GMT 1290 {"America/New_York", new CalFields(2011,11,6,0,59,59), new CalFields(2011,11,6,4,59,59), new CalFields(2011,11,6,4,59,59)}, 1291 {"America/New_York", new CalFields(2011,11,6,1,0,0), new CalFields(2011,11,6,6,0,0), new CalFields(2011,11,6,5,0,0)}, 1292 {"America/New_York", new CalFields(2011,11,6,1,0,1), new CalFields(2011,11,6,6,0,1), new CalFields(2011,11,6,5,0,1)}, 1293 {"America/New_York", new CalFields(2011,11,6,1,30,0), new CalFields(2011,11,6,6,30,0), new CalFields(2011,11,6,5,30,0)}, 1294 {"America/New_York", new CalFields(2011,11,6,1,59,59), new CalFields(2011,11,6,6,59,59), new CalFields(2011,11,6,5,59,59)}, 1295 {"America/New_York", new CalFields(2011,11,6,2,0,0), new CalFields(2011,11,6,7,0,0), new CalFields(2011,11,6,7,0,0)}, 1296 {"America/New_York", new CalFields(2011,11,6,2,0,1), new CalFields(2011,11,6,7,0,1), new CalFields(2011,11,6,7,0,1)}, 1297 1298 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,29,59), new CalFields(2011,4,2,14,29,59), new CalFields(2011,4,2,14,29,59)}, 1299 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,30,0), new CalFields(2011,4,2,15,0,0), new CalFields(2011,4,2,14,30,0)}, 1300 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,45,0), new CalFields(2011,4,2,15,15,0), new CalFields(2011,4,2,14,45,0)}, 1301 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,59,59), new CalFields(2011,4,2,15,29,59), new CalFields(2011,4,2,14,59,59)}, 1302 {"Australia/Lord_Howe", new CalFields(2011,4,3,2,0,0), new CalFields(2011,4,2,15,30,0), new CalFields(2011,4,2,15,30,0)}, 1303 {"Australia/Lord_Howe", new CalFields(2011,4,3,2,0,1), new CalFields(2011,4,2,15,30,1), new CalFields(2011,4,2,15,30,1)}, 1304 }; 1305 1306 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE); 1307 1308 Calendar calDefault = Calendar.getInstance(); 1309 Calendar calLast = Calendar.getInstance(); 1310 Calendar calFirst = Calendar.getInstance(); 1311 1312 calFirst.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST); 1313 calLast.setRepeatedWallTimeOption(Calendar.WALLTIME_LAST); 1314 1315 for (Object[] test : TESTDATA) { 1316 String tzid = (String)test[0]; 1317 TimeZone tz = TimeZone.getTimeZone(tzid); 1318 CalFields in = (CalFields)test[1]; 1319 CalFields expLastGMT = (CalFields)test[2]; 1320 CalFields expFirstGMT = (CalFields)test[3]; 1321 1322 // WALLTIME_LAST 1323 calLast.setTimeZone(tz); 1324 in.setTo(calLast); 1325 calGMT.setTimeInMillis(calLast.getTimeInMillis()); 1326 CalFields outLastGMT = CalFields.createFrom(calGMT); 1327 if (!outLastGMT.equals(expLastGMT)) { 1328 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1329 } 1330 1331 // default 1332 calDefault.setTimeZone(tz); 1333 in.setTo(calDefault); 1334 calGMT.setTimeInMillis(calDefault.getTimeInMillis()); 1335 CalFields outDefGMT = CalFields.createFrom(calGMT); 1336 if (!outDefGMT.equals(expLastGMT)) { 1337 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1338 } 1339 1340 // WALLTIME_FIRST 1341 calFirst.setTimeZone(tz); 1342 in.setTo(calFirst); 1343 calGMT.setTimeInMillis(calFirst.getTimeInMillis()); 1344 CalFields outFirstGMT = CalFields.createFrom(calGMT); 1345 if (!outFirstGMT.equals(expFirstGMT)) { 1346 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]"); 1347 } 1348 } 1349 } 1350 1351 @Test 1352 public void TestSkippedWallTime() { 1353 final Object[][] TESTDATA = { 1354 // Time zone Input wall time Valid wall time? 1355 {"America/New_York", new CalFields(2011,3,13,1,59,59), true, 1356 // WALLTIME_LAST in GMT WALLTIME_FIRST in GMT WALLTIME_NEXT_VALID in GMT 1357 new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59)}, 1358 1359 {"America/New_York", new CalFields(2011,3,13,2,0,0), false, 1360 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,6,0,0), new CalFields(2011,3,13,7,0,0)}, 1361 1362 {"America/New_York", new CalFields(2011,3,13,2,1,0), false, 1363 new CalFields(2011,3,13,7,1,0), new CalFields(2011,3,13,6,1,0), new CalFields(2011,3,13,7,0,0)}, 1364 1365 {"America/New_York", new CalFields(2011,3,13,2,30,0), false, 1366 new CalFields(2011,3,13,7,30,0), new CalFields(2011,3,13,6,30,0), new CalFields(2011,3,13,7,0,0)}, 1367 1368 {"America/New_York", new CalFields(2011,3,13,2,59,59), false, 1369 new CalFields(2011,3,13,7,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,7,0,0)}, 1370 1371 {"America/New_York", new CalFields(2011,3,13,3,0,0), true, 1372 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0)}, 1373 1374 {"Pacific/Apia", new CalFields(2011,12,29,23,59,59), true, 1375 new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59)}, 1376 1377 {"Pacific/Apia", new CalFields(2011,12,30,0,0,0), false, 1378 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,29,10,0,0), new CalFields(2011,12,30,10,0,0)}, 1379 1380 {"Pacific/Apia", new CalFields(2011,12,30,12,0,0), false, 1381 new CalFields(2011,12,30,22,0,0), new CalFields(2011,12,29,22,0,0), new CalFields(2011,12,30,10,0,0)}, 1382 1383 {"Pacific/Apia", new CalFields(2011,12,30,23,59,59), false, 1384 new CalFields(2011,12,31,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,10,0,0)}, 1385 1386 {"Pacific/Apia", new CalFields(2011,12,31,0,0,0), true, 1387 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0)}, 1388 }; 1389 1390 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE); 1391 1392 Calendar calDefault = Calendar.getInstance(); 1393 Calendar calLast = Calendar.getInstance(); 1394 Calendar calFirst = Calendar.getInstance(); 1395 Calendar calNextAvail = Calendar.getInstance(); 1396 1397 calLast.setSkippedWallTimeOption(Calendar.WALLTIME_LAST); 1398 calFirst.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST); 1399 calNextAvail.setSkippedWallTimeOption(Calendar.WALLTIME_NEXT_VALID); 1400 1401 for (Object[] test : TESTDATA) { 1402 String tzid = (String)test[0]; 1403 TimeZone tz = TimeZone.getTimeZone(tzid); 1404 CalFields in = (CalFields)test[1]; 1405 boolean isValid = (Boolean)test[2]; 1406 CalFields expLastGMT = (CalFields)test[3]; 1407 CalFields expFirstGMT = (CalFields)test[4]; 1408 CalFields expNextAvailGMT = (CalFields)test[5]; 1409 1410 for (int i = 0; i < 2; i++) { 1411 boolean bLenient = (i == 0); 1412 1413 // WALLTIME_LAST 1414 calLast.setLenient(bLenient); 1415 calLast.setTimeZone(tz); 1416 try { 1417 in.setTo(calLast); 1418 calGMT.setTimeInMillis(calLast.getTimeInMillis()); 1419 CalFields outLastGMT = CalFields.createFrom(calGMT); 1420 if (!bLenient && !isValid) { 1421 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_LAST)"); 1422 } else if (!outLastGMT.equals(expLastGMT)) { 1423 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1424 } 1425 } catch (IllegalArgumentException e) { 1426 if (bLenient || isValid) { 1427 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_LAST)"); 1428 } 1429 } 1430 1431 // default 1432 calDefault.setLenient(bLenient); 1433 calDefault.setTimeZone(tz); 1434 try { 1435 in.setTo(calDefault); 1436 calGMT.setTimeInMillis(calDefault.getTimeInMillis()); 1437 CalFields outDefGMT = CalFields.createFrom(calGMT); 1438 if (!bLenient && !isValid) { 1439 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (default)"); 1440 } else if (!outDefGMT.equals(expLastGMT)) { 1441 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1442 } 1443 } catch (IllegalArgumentException e) { 1444 if (bLenient || isValid) { 1445 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (default)"); 1446 } 1447 } 1448 1449 // WALLTIME_FIRST 1450 calFirst.setLenient(bLenient); 1451 calFirst.setTimeZone(tz); 1452 try { 1453 in.setTo(calFirst); 1454 calGMT.setTimeInMillis(calFirst.getTimeInMillis()); 1455 CalFields outFirstGMT = CalFields.createFrom(calGMT); 1456 if (!bLenient && !isValid) { 1457 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_FIRST)"); 1458 } else if (!outFirstGMT.equals(expFirstGMT)) { 1459 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]"); 1460 } 1461 } catch (IllegalArgumentException e) { 1462 if (bLenient || isValid) { 1463 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_FIRST)"); 1464 } 1465 } 1466 1467 // WALLTIME_NEXT_VALID 1468 calNextAvail.setLenient(bLenient); 1469 calNextAvail.setTimeZone(tz); 1470 try { 1471 in.setTo(calNextAvail); 1472 calGMT.setTimeInMillis(calNextAvail.getTimeInMillis()); 1473 CalFields outNextAvailGMT = CalFields.createFrom(calGMT); 1474 if (!bLenient && !isValid) { 1475 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)"); 1476 } else if (!outNextAvailGMT.equals(expNextAvailGMT)) { 1477 errln("Fail: WALLTIME_NEXT_VALID " + in + "[" + tzid + "] is parsed as " + outNextAvailGMT + "[GMT]. Expected: " + expNextAvailGMT + "[GMT]"); 1478 } 1479 } catch (IllegalArgumentException e) { 1480 if (bLenient || isValid) { 1481 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)"); 1482 } 1483 } 1484 } 1485 } 1486 } 1487 1488 @Test 1489 public void TestFieldDifference() { 1490 class TFDItem { 1491 public String tzname; 1492 public String locale; 1493 public long start; 1494 public long target; 1495 public boolean progressive; // true to compute progressive difference for each field, false to reset calendar after each call 1496 int yDiff; 1497 int MDiff; 1498 int dDiff; 1499 int HDiff; 1500 int mDiff; 1501 int sDiff; // 0x7FFFFFFF indicates overflow error expected 1502 // Simple constructor 1503 public TFDItem(String tz, String loc, long st, long tg, boolean prg, int yD, int MD, int dD, int HD, int mD, int sD ) { 1504 tzname = tz; 1505 locale = loc; 1506 start = st; 1507 target = tg; 1508 progressive = prg; 1509 yDiff = yD; 1510 MDiff = MD; 1511 dDiff = dD; 1512 HDiff = HD; 1513 mDiff = mD; 1514 sDiff = sD; 1515 } 1516 }; 1517 final TFDItem[] tfdItems = { 1518 // timezobe locale start target prog yDf MDf dDf HDf mDf sDf 1519 // For these we compute the progressive difference for each field - not resetting the calendar after each call 1520 new TFDItem( "US/Pacific", "en_US", 1267459800000L, 1277772600000L, true, 0, 3, 27, 9, 40, 0 ), // 2010-Mar-01 08:10 -> 2010-Jun-28 17:50 1521 new TFDItem( "US/Pacific", "en_US", 1267459800000L, 1299089280000L, true, 1, 0, 1, 1, 58, 0 ), // 2010-Mar-01 08:10 -> 2011-Mar-02 10:08 1522 // For these we compute the total difference for each field - resetting the calendar after each call 1523 new TFDItem( "GMT", "en_US", 0, 1073692800000L, false, 34, 408, 12427, 298248, 17894880, 1073692800 ), // 1970-Jan-01 00:00 -> 2004-Jan-10 00:00 1524 new TFDItem( "GMT", "en_US", 0, 1073779200000L, false, 34, 408, 12428, 298272, 17896320, 1073779200 ), // 1970-Jan-01 00:00 -> 2004-Jan-11 00:00 1525 new TFDItem( "GMT", "en_US", 0, 2147472000000L, false, 68, 816, 24855, 596520, 35791200, 2147472000 ), // 1970-Jan-01 00:00 -> 2038-Jan-19 00:00 1526// new TFDItem( "GMT", "en_US", 0, 2147558400000L, false, 68, 816, 24856, 596544, 35792640, 0x7FFFFFFF ), // 1970-Jan-01 00:00 -> 2038-Jan-20 00:00, seconds overflow => exception in ICU4J 1527 new TFDItem( "GMT", "en_US", 0, -1073692800000L, false, -34,-408,-12427,-298248,-17894880,-1073692800 ), // 1970-Jan-01 00:00 -> 1935-Dec-24 00:00 1528 new TFDItem( "GMT", "en_US", 0, -1073779200000L, false, -34,-408,-12428,-298272,-17896320,-1073779200 ), // 1970-Jan-01 00:00 -> 1935-Dec-23 00:00 1529 // check fwd/backward on either side of era boundary and across era boundary 1530 new TFDItem( "GMT", "en_US", -61978089600000L,-61820409600000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // CE 5-Dec-31 00:00 -> CE 10-Dec-30 00:00 1531 new TFDItem( "GMT", "en_US", -61820409600000L,-61978089600000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // CE 10-Dec-30 00:00 -> CE 5-Dec-31 00:00 1532 new TFDItem( "GMT", "en_US", -62451129600000L,-62293449600000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // BCE 10-Jan-04 00:00 -> BCE 5-Jan-03 00:00 1533 new TFDItem( "GMT", "en_US", -62293449600000L,-62451129600000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // BCE 5-Jan-03 00:00 -> BCE 10-Jan-04 00:00 1534 new TFDItem( "GMT", "en_US", -62293449600000L,-61978089600000L, false, 9, 119, 3650, 87600, 5256000, 315360000 ), // BCE 5-Jan-03 00:00 -> CE 5-Dec-31 00:00 1535 new TFDItem( "GMT", "en_US", -61978089600000L,-62293449600000L, false, -9,-119, -3650, -87600, -5256000, -315360000 ), // CE 5-Dec-31 00:00 -> BCE 5-Jan-03 00:00 1536 new TFDItem( "GMT", "en@calendar=roc", -1672704000000L, -1515024000000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // MG 5-Dec-30 00:00 -> MG 10-Dec-29 00:00 1537 new TFDItem( "GMT", "en@calendar=roc", -1515024000000L, -1672704000000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // MG 10-Dec-29 00:00 -> MG 5-Dec-30 00:00 1538 new TFDItem( "GMT", "en@calendar=roc", -2145744000000L, -1988064000000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // BMG 10-Jan-03 00:00 -> BMG 5-Jan-02 00:00 1539 new TFDItem( "GMT", "en@calendar=roc", -1988064000000L, -2145744000000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // BMG 5-Jan-02 00:00 -> BMG 10-Jan-03 00:00 1540 new TFDItem( "GMT", "en@calendar=roc", -1988064000000L, -1672704000000L, false, 9, 119, 3650, 87600, 5256000, 315360000 ), // BMG 5-Jan-02 00:00 -> MG 5-Dec-30 00:00 1541 new TFDItem( "GMT", "en@calendar=roc", -1672704000000L, -1988064000000L, false, -9,-119, -3650, -87600, -5256000, -315360000 ), // MG 5-Dec-30 00:00 -> BMG 5-Jan-02 00:00 1542 new TFDItem( "GMT", "en@calendar=coptic",-53026531200000L,-52868851200000L, false, 4, 64, 1825, 43800, 2628000, 157680000 ), // Er1 5-Nas-05 00:00 -> Er1 10-Nas-04 00:00 1543 new TFDItem( "GMT", "en@calendar=coptic",-52868851200000L,-53026531200000L, false, -4, -64, -1825, -43800, -2628000, -157680000 ), // Er1 10-Nas-04 00:00 -> Er1 5-Nas-05 00:00 1544 new TFDItem( "GMT", "en@calendar=coptic",-53499571200000L,-53341891200000L, false, 4, 64, 1825, 43800, 2628000, 157680000 ), // Er0 10-Tou-04 00:00 -> Er0 5-Tou-02 00:00 1545 new TFDItem( "GMT", "en@calendar=coptic",-53341891200000L,-53499571200000L, false, -4, -64, -1825, -43800, -2628000, -157680000 ), // Er0 5-Tou-02 00:00 -> Er0 10-Tou-04 00:00 1546 new TFDItem( "GMT", "en@calendar=coptic",-53341891200000L,-53026531200000L, false, 9, 129, 3650, 87600, 5256000, 315360000 ), // Er0 5-Tou-02 00:00 -> Er1 5-Nas-05 00:00 1547 new TFDItem( "GMT", "en@calendar=coptic",-53026531200000L,-53341891200000L, false, -9,-129, -3650, -87600, -5256000, -315360000 ), // Er1 5-Nas-05 00:00 -> Er0 5-Tou-02 00:00 1548 }; 1549 for (TFDItem tfdItem: tfdItems) { 1550 TimeZone timezone = TimeZone.getFrozenTimeZone(tfdItem.tzname); 1551 Calendar ucal = Calendar.getInstance(timezone, new ULocale(tfdItem.locale)); 1552 ucal.setTimeInMillis(tfdItem.target); 1553 Date targetDate = ucal.getTime(); 1554 int yDf, MDf, dDf, HDf, mDf, sDf; 1555 if (tfdItem.progressive) { 1556 ucal.setTimeInMillis(tfdItem.start); 1557 yDf = ucal.fieldDifference(targetDate, YEAR); 1558 MDf = ucal.fieldDifference(targetDate, MONTH); 1559 dDf = ucal.fieldDifference(targetDate, DATE); 1560 HDf = ucal.fieldDifference(targetDate, HOUR); 1561 mDf = ucal.fieldDifference(targetDate, MINUTE); 1562 sDf = ucal.fieldDifference(targetDate, SECOND); 1563 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff || sDf != tfdItem.sDiff ) { 1564 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m-s progressive diffs " + 1565 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff +","+ tfdItem.sDiff + ", got " + 1566 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf +","+ sDf); 1567 } 1568 } else { 1569 ucal.setTimeInMillis(tfdItem.start); 1570 yDf = ucal.fieldDifference(targetDate, YEAR); 1571 ucal.setTimeInMillis(tfdItem.start); 1572 MDf = ucal.fieldDifference(targetDate, MONTH); 1573 ucal.setTimeInMillis(tfdItem.start); 1574 dDf = ucal.fieldDifference(targetDate, DATE); 1575 ucal.setTimeInMillis(tfdItem.start); 1576 HDf = ucal.fieldDifference(targetDate, HOUR); 1577 ucal.setTimeInMillis(tfdItem.start); 1578 mDf = ucal.fieldDifference(targetDate, MINUTE); 1579 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff ) { 1580 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m total diffs " + 1581 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff + ", got " + 1582 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf); 1583 } 1584 ucal.setTimeInMillis(tfdItem.start); 1585 sDf = ucal.fieldDifference(targetDate, SECOND); 1586 if ( sDf != 0x7FFFFFFF && sDf != tfdItem.sDiff ) { 1587 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected seconds total diffs " + 1588 tfdItem.sDiff + ", got " + sDf); 1589 } 1590 } 1591 } 1592 } 1593 1594 @Test 1595 public void TestAddRollEra0AndEraBounds() { 1596 final String[] localeIDs = { 1597 // calendars with non-modern era 0 that goes backwards, max era == 1 1598 "en@calendar=gregorian", 1599 "en@calendar=roc", 1600 "en@calendar=coptic", 1601 // calendars with non-modern era 0 that goes forwards, max era > 1 1602 "en@calendar=japanese", 1603 "en@calendar=chinese", 1604 // calendars with non-modern era 0 that goes forwards, max era == 1 1605 "en@calendar=ethiopic", 1606 // calendars with only one era = 0, forwards 1607 "en@calendar=buddhist", 1608 "en@calendar=hebrew", 1609 "en@calendar=islamic", 1610 "en@calendar=indian", 1611 //"en@calendar=persian", // no persian calendar in ICU4J yet 1612 "en@calendar=ethiopic-amete-alem", 1613 }; 1614 TimeZone zoneGMT = TimeZone.getFrozenTimeZone("GMT"); 1615 for (String localeID : localeIDs) { 1616 Calendar ucalTest = Calendar.getInstance(zoneGMT, new ULocale(localeID)); 1617 String calType = ucalTest.getType(); 1618 boolean era0YearsGoBackwards = (calType.equals("gregorian") || calType.equals("roc") || calType.equals("coptic")); 1619 int yrBefore, yrAfter, yrMax, eraAfter, eraMax, eraNow; 1620 1621 ucalTest.clear(); 1622 ucalTest.set(Calendar.YEAR, 2); 1623 ucalTest.set(Calendar.ERA, 0); 1624 yrBefore = ucalTest.get(Calendar.YEAR); 1625 ucalTest.add(Calendar.YEAR, 1); 1626 yrAfter = ucalTest.get(Calendar.YEAR); 1627 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) { 1628 errln("Fail: era 0 add 1 year does not move forward in time for " + localeID); 1629 } 1630 1631 ucalTest.clear(); 1632 ucalTest.set(Calendar.YEAR, 2); 1633 ucalTest.set(Calendar.ERA, 0); 1634 yrBefore = ucalTest.get(Calendar.YEAR); 1635 ucalTest.roll(Calendar.YEAR, 1); 1636 yrAfter = ucalTest.get(Calendar.YEAR); 1637 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) { 1638 errln("Fail: era 0 roll 1 year does not move forward in time for " + localeID); 1639 } 1640 1641 ucalTest.clear(); 1642 ucalTest.set(Calendar.YEAR, 1); 1643 ucalTest.set(Calendar.ERA, 0); 1644 if (era0YearsGoBackwards) { 1645 ucalTest.roll(Calendar.YEAR, 1); 1646 yrAfter = ucalTest.get(Calendar.YEAR); 1647 eraAfter = ucalTest.get(Calendar.ERA); 1648 if (eraAfter != 0 || yrAfter != 1) { 1649 errln("Fail: era 0 roll 1 year from year 1 does not stay within era or pin to year 1 for " 1650 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1651 } 1652 } else { 1653 // roll backward in time to where era 0 years go negative, except for the Chinese 1654 // calendar, which uses negative eras instead of having years outside the range 1-60 1655 ucalTest.roll(Calendar.YEAR, -2); 1656 yrAfter = ucalTest.get(Calendar.YEAR); 1657 eraAfter = ucalTest.get(Calendar.ERA); 1658 if ( !calType.equals("chinese") && (eraAfter != 0 || yrAfter != -1) ) { 1659 errln("Fail: era 0 roll -2 years from year 1 does not stay within era or produce year -1 for " 1660 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1661 } 1662 } 1663 1664 ucalTest.clear(); 1665 { 1666 int eraMin = ucalTest.getMinimum(Calendar.ERA); 1667 if (eraMin != 0 && calType.compareTo("chinese") != 0) { 1668 errln("Fail: getMinimum returns minimum era " + eraMin + " (should be 0) for calType " + calType); 1669 } 1670 } 1671 1672 ucalTest.clear(); 1673 ucalTest.set(Calendar.YEAR, 1); 1674 ucalTest.set(Calendar.ERA, 0); 1675 eraMax = ucalTest.getMaximum(Calendar.ERA); 1676 if (eraMax > 0) { 1677 // try similar tests for era 1 (if calendar has it), in which years always go forward 1678 1679 ucalTest.clear(); 1680 ucalTest.set(Calendar.YEAR, 2); 1681 ucalTest.set(Calendar.ERA, 1); 1682 yrBefore = ucalTest.get(Calendar.YEAR); 1683 ucalTest.add(Calendar.YEAR, 1); 1684 yrAfter = ucalTest.get(Calendar.YEAR); 1685 if ( yrAfter<yrBefore ) { 1686 errln("Fail: era 1 add 1 year does not move forward in time for " + localeID); 1687 } 1688 1689 ucalTest.clear(); 1690 ucalTest.set(Calendar.YEAR, 2); 1691 ucalTest.set(Calendar.ERA, 1); 1692 yrBefore = ucalTest.get(Calendar.YEAR); 1693 ucalTest.roll(Calendar.YEAR, 1); 1694 yrAfter = ucalTest.get(Calendar.YEAR); 1695 if ( yrAfter<yrBefore ) { 1696 errln("Fail: era 1 roll 1 year does not move forward in time for " + localeID); 1697 } 1698 1699 ucalTest.clear(); 1700 ucalTest.set(Calendar.YEAR, 1); 1701 ucalTest.set(Calendar.ERA, 1); 1702 yrMax = ucalTest.getActualMaximum(Calendar.YEAR); 1703 ucalTest.roll(Calendar.YEAR, -1); // roll down which should pin or wrap to end 1704 yrAfter = ucalTest.get(Calendar.YEAR); 1705 eraAfter = ucalTest.get(Calendar.ERA); 1706 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1 1707 if (yrMax >= 32768) { 1708 if (eraAfter != 1 || yrAfter != 1) { 1709 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or pin to year 1 for " 1710 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1711 } 1712 } else if (eraAfter != 1 || yrAfter != yrMax) { 1713 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or wrap to year " 1714 + yrMax + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1715 } else { 1716 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning 1717 yrAfter = ucalTest.get(Calendar.YEAR); 1718 eraAfter = ucalTest.get(Calendar.ERA); 1719 if (eraAfter != 1 || yrAfter != 1) { 1720 errln("Fail: era 1 roll 1 year from year " + yrMax + 1721 " does not stay within era or wrap to year 1 for " 1722 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1723 } 1724 } 1725 1726 // if current era > 1, try the same roll tests for current era 1727 ucalTest.setTime(new Date()); 1728 eraNow = ucalTest.get(Calendar.ERA); 1729 if (eraNow > 1) { 1730 ucalTest.clear(); 1731 ucalTest.set(Calendar.YEAR, 1); 1732 ucalTest.set(Calendar.ERA, eraNow); 1733 yrMax = ucalTest.getActualMaximum(Calendar.YEAR); // max year value for this era 1734 ucalTest.roll(Calendar.YEAR, -1); 1735 yrAfter = ucalTest.get(Calendar.YEAR); 1736 eraAfter = ucalTest.get(Calendar.ERA); 1737 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1 1738 if (yrMax >= 32768) { 1739 if (eraAfter != eraNow || yrAfter != 1) { 1740 errln("Fail: era " + eraNow + 1741 " roll -1 year from year 1 does not stay within era or pin to year 1 for " 1742 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1743 } 1744 } else if (eraAfter != eraNow || yrAfter != yrMax) { 1745 errln("Fail: era " + eraNow + 1746 " roll -1 year from year 1 does not stay within era or wrap to year " + yrMax 1747 + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1748 } else { 1749 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning 1750 yrAfter = ucalTest.get(Calendar.YEAR); 1751 eraAfter = ucalTest.get(Calendar.ERA); 1752 if (eraAfter != eraNow || yrAfter != 1) { 1753 errln("Fail: era " + eraNow + " roll 1 year from year " + yrMax + 1754 " does not stay within era or wrap to year 1 for " 1755 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1756 } 1757 } 1758 } 1759 } 1760 } 1761 } 1762 1763 @Test 1764 public void TestWeekData() { 1765 // Each line contains two locales using the same set of week rule data. 1766 final String LOCALE_PAIRS[] = { 1767 "en", "en_US", 1768 "de", "de_DE", 1769 "de_DE", "en_DE", 1770 "en_GB", "und_GB", 1771 "ar_EG", "en_EG", 1772 "ar_SA", "fr_SA", 1773 }; 1774 1775 for (int i = 0; i < LOCALE_PAIRS.length; i += 2) { 1776 Calendar cal1 = Calendar.getInstance(new ULocale(LOCALE_PAIRS[i])); 1777 Calendar cal2 = Calendar.getInstance(new ULocale(LOCALE_PAIRS[i + 1])); 1778 1779 // First day of week 1780 int dow1 = cal1.getFirstDayOfWeek(); 1781 int dow2 = cal2.getFirstDayOfWeek(); 1782 if (dow1 != dow2) { 1783 errln("getFirstDayOfWeek: " + LOCALE_PAIRS[i] + "->" + dow1 + ", " + LOCALE_PAIRS[i + 1] + "->" + dow2); 1784 } 1785 1786 // Minimum days in first week 1787 int minDays1 = cal1.getMinimalDaysInFirstWeek(); 1788 int minDays2 = cal2.getMinimalDaysInFirstWeek(); 1789 if (minDays1 != minDays2) { 1790 errln("getMinimalDaysInFirstWeek: " + LOCALE_PAIRS[i] + "->" + minDays1 + ", " + LOCALE_PAIRS[i + 1] + "->" + minDays2); 1791 } 1792 1793 // Weekdays and Weekends 1794 for (int d = Calendar.SUNDAY; d <= Calendar.SATURDAY; d++) { 1795 int wdt1 = cal1.getDayOfWeekType(d); 1796 int wdt2 = cal2.getDayOfWeekType(d); 1797 if (wdt1 != wdt2) { 1798 errln("getDayOfWeekType(" + d + "): " + LOCALE_PAIRS[i] + "->" + wdt1 + ", " + LOCALE_PAIRS[i + 1] + "->" + wdt2); 1799 } 1800 } 1801 } 1802 } 1803 1804 @Test 1805 public void TestAddAcrossZoneTransition() { 1806 class TestData { 1807 String zone; 1808 CalFields base; 1809 int deltaDays; 1810 int skippedWTOpt; 1811 CalFields expected; 1812 1813 TestData(String zone, CalFields base, int deltaDays, int skippedWTOpt, CalFields expected) { 1814 this.zone = zone; 1815 this.base = base; 1816 this.deltaDays = deltaDays; 1817 this.skippedWTOpt = skippedWTOpt; 1818 this.expected = expected; 1819 } 1820 } 1821 1822 TestData[] data = new TestData[] { 1823 // Add 1 day, from the date before DST transition 1824 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_FIRST, 1825 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1826 1827 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_LAST, 1828 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1829 1830 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_NEXT_VALID, 1831 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1832 1833 1834 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 1835 new CalFields(2014, 3, 9, 1, 0, 0, 0)), 1836 1837 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 1838 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1839 1840 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1841 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1842 1843 1844 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_FIRST, 1845 new CalFields(2014, 3, 9, 1, 30, 0, 0)), 1846 1847 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_LAST, 1848 new CalFields(2014, 3, 9, 3, 30, 0, 0)), 1849 1850 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1851 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1852 1853 1854 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 1855 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1856 1857 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 1858 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1859 1860 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1861 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1862 1863 1864 // Subtract 1 day, from one day after DST transition 1865 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_FIRST, 1866 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1867 1868 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_LAST, 1869 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1870 1871 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_NEXT_VALID, 1872 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1873 1874 1875 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 1876 new CalFields(2014, 3, 9, 1, 0, 0, 0)), 1877 1878 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 1879 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1880 1881 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1882 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1883 1884 1885 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_FIRST, 1886 new CalFields(2014, 3, 9, 1, 30, 0, 0)), 1887 1888 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_LAST, 1889 new CalFields(2014, 3, 9, 3, 30, 0, 0)), 1890 1891 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1892 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1893 1894 1895 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 1896 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1897 1898 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 1899 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1900 1901 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1902 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1903 1904 1905 // Test case for ticket#10544 1906 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_FIRST, 1907 new CalFields(2013, 9, 7, 23, 0, 0, 0)), 1908 1909 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_LAST, 1910 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1911 1912 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID, 1913 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1914 1915 1916 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_FIRST, 1917 new CalFields(2013, 9, 7, 23, 30, 0, 0)), 1918 1919 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_LAST, 1920 new CalFields(2013, 9, 8, 1, 30, 0, 0)), 1921 1922 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID, 1923 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1924 1925 1926 // Extreme transition - Pacific/Apia completely skips 2011-12-30 1927 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 1928 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 1929 1930 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 1931 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 1932 1933 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1934 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 1935 1936 1937 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 1938 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 1939 1940 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 1941 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 1942 1943 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1944 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 1945 1946 1947 // 30 minutes DST - Australia/Lord_Howe 1948 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_FIRST, 1949 new CalFields(2013, 10, 6, 1, 45, 0, 0)), 1950 1951 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_LAST, 1952 new CalFields(2013, 10, 6, 2, 45, 0, 0)), 1953 1954 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1955 new CalFields(2013, 10, 6, 2, 30, 0, 0)), 1956 }; 1957 1958 Calendar cal = Calendar.getInstance(); 1959 for (TestData d : data) { 1960 cal.setTimeZone(TimeZone.getTimeZone(d.zone)); 1961 cal.setSkippedWallTimeOption(d.skippedWTOpt); 1962 d.base.setTo(cal); 1963 cal.add(Calendar.DATE, d.deltaDays); 1964 1965 if (!d.expected.isEquivalentTo(cal)) { 1966 CalFields res = CalFields.createFrom(cal); 1967 String optDisp = d.skippedWTOpt == Calendar.WALLTIME_FIRST ? "FIRST" : 1968 d.skippedWTOpt == Calendar.WALLTIME_LAST ? "LAST" : "NEXT_VALID"; 1969 errln("Error: base:" + d.base.toString() + ", tz:" + d.zone 1970 + ", delta:" + d.deltaDays + " day(s), opt:" + optDisp 1971 + ", result:" + res.toString() + " - expected:" + d.expected.toString()); 1972 } 1973 } 1974 } 1975 1976 @Test 1977 public void TestSimpleDateFormatCoverage() { 1978 1979 class StubSimpleDateFormat extends SimpleDateFormat { 1980 private static final long serialVersionUID = 1L; 1981 1982 public StubSimpleDateFormat(String pattern, Locale loc) { 1983 new SimpleDateFormat(pattern, loc); 1984 } 1985 1986 public void run(){ 1987 Calendar cal = Calendar.getInstance(Locale.US); 1988 cal.clear(); 1989 cal.set(2000, Calendar.MARCH, 18, 15, 0, 1); // Sat 15:00 1990 1991 DateFormatSymbols theseSymbols = this.getSymbols(); 1992 String shouldBeMonday = theseSymbols.getWeekdays()[Calendar.MONDAY]; 1993 assertEquals("Should be Monday", "Monday", shouldBeMonday); 1994 1995 String [] matchData = {"16", "2016", "2016AD", "Monday", "lunes"}; 1996 int matchIndex = matchString("Monday March 28, 2016", 0, Calendar.DAY_OF_WEEK, matchData, cal); 1997 assertEquals("matchData for Monday", 6, matchIndex); // Position of the pointer after the matched string. 1998 matchIndex = matchString("Monday March 28, 2016 AD", 17, Calendar.YEAR, matchData, cal); 1999 assertEquals("matchData for 2016", 21, matchIndex); // Position of the pointer after the matched string. 2000 2001 char ch = 'y'; 2002 int count = 4; 2003 int beginOffset = 0; 2004 cal.set(Calendar.YEAR, 2000); // Reset this 2005 assertEquals("calendar year reset", 2000, cal.get(Calendar.YEAR)); 2006 FieldPosition pos = new FieldPosition(java.text.DateFormat.YEAR_FIELD); 2007 String subFormatResult = subFormat(ch, count, beginOffset, 2008 pos, theseSymbols, cal); 2009 assertEquals("subFormat result", "2000", subFormatResult); 2010 2011 String testParseString = "some text with a date 2017-03-15"; 2012 int start = 22; 2013 boolean obeyCount = true; 2014 boolean allowNegative = false; 2015 boolean ambiguousYear[] = {true, false, true}; 2016 int subParseResult = subParse(testParseString, start, ch, count, 2017 obeyCount, allowNegative, ambiguousYear, cal); 2018 assertEquals("subParseResult result", 26, subParseResult); 2019 assertEquals("parsed year", 2017, cal.get(Calendar.YEAR)); 2020 } 2021 } 2022 StubSimpleDateFormat stub = new StubSimpleDateFormat("EEE MMM dd yyyy G HH:mm:ss.SSS", Locale.US); 2023 stub.run(); 2024 } 2025} 2026