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