1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2000-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.test.calendar; 10 11 import java.text.FieldPosition; 12 import java.text.ParseException; 13 import java.util.Date; 14 import java.util.Locale; 15 import java.util.Set; 16 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 import org.junit.runners.JUnit4; 20 21 import com.ibm.icu.impl.CalendarAstronomer; 22 import com.ibm.icu.impl.LocaleUtility; 23 import com.ibm.icu.impl.ZoneMeta; 24 import com.ibm.icu.text.DateFormat; 25 import com.ibm.icu.text.DateFormatSymbols; 26 import com.ibm.icu.text.SimpleDateFormat; 27 import com.ibm.icu.util.BuddhistCalendar; 28 import com.ibm.icu.util.Calendar; 29 import com.ibm.icu.util.ChineseCalendar; 30 import com.ibm.icu.util.GregorianCalendar; 31 import com.ibm.icu.util.HebrewCalendar; 32 import com.ibm.icu.util.IndianCalendar; 33 import com.ibm.icu.util.IslamicCalendar; 34 import com.ibm.icu.util.JapaneseCalendar; 35 import com.ibm.icu.util.TaiwanCalendar; 36 import com.ibm.icu.util.TimeZone; 37 import com.ibm.icu.util.TimeZone.SystemTimeZoneType; 38 import com.ibm.icu.util.ULocale; 39 40 /** 41 * @summary Tests of new functionality in IBMCalendar 42 */ 43 @RunWith(JUnit4.class) 44 public 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 TestWeekend()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 */ quasiGregorianTest(Calendar cal, int[] data)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 verifyFirstDayOfWeek(String l, int weekday)208 private void verifyFirstDayOfWeek(String l, int weekday) { 209 assertEquals(l, weekday, 210 Calendar.getInstance(Locale.forLanguageTag(l)).getFirstDayOfWeek()); 211 } 212 /** 213 * Test "First Day Overrides" behavior 214 * https://unicode.org/reports/tr35/tr35-dates.html#first-day-overrides 215 * And data in <firstDay> of 216 * https://github.com/unicode-org/cldr/blob/main/common/supplemental/supplementalData.xml 217 * 218 * Examples of region for First Day of a week 219 * Friday: MV 220 * Saturday: AE AF 221 * Sunday: US JP 222 * Monday: GB 223 */ 224 @Test TestFirstDayOfWeek()225 public void TestFirstDayOfWeek() { 226 String l; 227 // Test -u-fw- value 228 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-sun-rg-mvzzzz-sd-usca", Calendar.SUNDAY); 229 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-mon-rg-mvzzzz-sd-usca", Calendar.MONDAY); 230 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-tue-rg-mvzzzz-sd-usca", Calendar.TUESDAY); 231 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-wed-rg-mvzzzz-sd-usca", Calendar.WEDNESDAY); 232 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-thu-rg-mvzzzz-sd-usca", Calendar.THURSDAY); 233 verifyFirstDayOfWeek("en-AE-u-ca-iso8601-fw-fri-rg-aezzzz-sd-usca", Calendar.FRIDAY); 234 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-fw-sat-rg-mvzzzz-sd-usca", Calendar.SATURDAY); 235 236 // Test -u-rg- value 237 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-rg-mvzzzz-sd-usca", Calendar.FRIDAY); 238 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-rg-aezzzz-sd-usca", Calendar.SATURDAY); 239 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-rg-uszzzz-sd-usca", Calendar.SUNDAY); 240 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-rg-gbzzzz-sd-usca", Calendar.MONDAY); 241 242 // Test -u-ca-iso8601 243 verifyFirstDayOfWeek("en-MV-u-ca-iso8601-sd-mv00", Calendar.MONDAY); 244 verifyFirstDayOfWeek("en-AE-u-ca-iso8601-sd-aeaj", Calendar.MONDAY); 245 verifyFirstDayOfWeek("en-US-u-ca-iso8601-sd-usca", Calendar.MONDAY); 246 247 // Test Region Tags only 248 verifyFirstDayOfWeek("en-MV", Calendar.FRIDAY); 249 verifyFirstDayOfWeek("en-AE", Calendar.SATURDAY); 250 verifyFirstDayOfWeek("en-US", Calendar.SUNDAY); 251 verifyFirstDayOfWeek("dv-GB", Calendar.MONDAY); 252 253 // Test -u-sd- 254 //verifyFirstDayOfWeek("en-u-sd-mv00", Calendar.FRIDAY); 255 // verifyFirstDayOfWeek("en-u-sd-aeaj", Calendar.SATURDAY); 256 // verifyFirstDayOfWeek("en-u-sd-usca", Calendar.SUNDAY); 257 // verifyFirstDayOfWeek("dv-u-sd-gbsct", Calendar.MONDAY); 258 259 // Test Add Likely Subtags algorithm produces a region 260 // dv => dv_Thaa_MV => Friday 261 verifyFirstDayOfWeek("dv", Calendar.FRIDAY); 262 // und_Thaa => dv_Thaa_MV => Friday 263 verifyFirstDayOfWeek("und-Thaa", Calendar.FRIDAY); 264 265 // ssh => ssh_Arab_AE => Saturday 266 verifyFirstDayOfWeek("ssh", Calendar.SATURDAY); 267 // wbl_Arab => wbl_Arab_AF => Saturday 268 verifyFirstDayOfWeek("wbl-Arab", Calendar.SATURDAY); 269 270 // en => en_Latn_US => Sunday 271 verifyFirstDayOfWeek("en", Calendar.SUNDAY); 272 // und_Hira => ja_Hira_JP => Sunday 273 verifyFirstDayOfWeek("und-Hira", Calendar.SUNDAY); 274 275 verifyFirstDayOfWeek("zxx", Calendar.MONDAY); 276 } 277 278 /** 279 * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise 280 * behaves like GregorianCalendar. 281 */ 282 @Test TestBuddhist()283 public void TestBuddhist() { 284 quasiGregorianTest(new BuddhistCalendar(), 285 new int[] { 286 // BE 2542 == 1999 CE 287 0, 2542, 1999, Calendar.JUNE, 4 288 }); 289 } 290 291 @Test TestBuddhistCoverage()292 public void TestBuddhistCoverage() { 293 { 294 // new BuddhistCalendar(ULocale) 295 BuddhistCalendar cal = new BuddhistCalendar(ULocale.getDefault()); 296 if(cal == null){ 297 errln("could not create BuddhistCalendar with ULocale"); 298 } 299 } 300 301 { 302 // new BuddhistCalendar(TimeZone,ULocale) 303 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(),ULocale.getDefault()); 304 if(cal == null){ 305 errln("could not create BuddhistCalendar with TimeZone ULocale"); 306 } 307 } 308 309 { 310 // new BuddhistCalendar(TimeZone) 311 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault()); 312 if(cal == null){ 313 errln("could not create BuddhistCalendar with TimeZone"); 314 } 315 } 316 317 { 318 // new BuddhistCalendar(Locale) 319 BuddhistCalendar cal = new BuddhistCalendar(Locale.getDefault()); 320 if(cal == null){ 321 errln("could not create BuddhistCalendar with Locale"); 322 } 323 } 324 325 { 326 // new BuddhistCalendar(TimeZone, Locale) 327 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(), Locale.getDefault()); 328 if(cal == null){ 329 errln("could not create BuddhistCalendar with TimeZone and Locale"); 330 } 331 } 332 333 { 334 // new BuddhistCalendar(Date) 335 BuddhistCalendar cal = new BuddhistCalendar(new Date()); 336 if(cal == null){ 337 errln("could not create BuddhistCalendar with Date"); 338 } 339 } 340 341 { 342 // new BuddhistCalendar(int year, int month, int date) 343 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22); 344 if(cal == null){ 345 errln("could not create BuddhistCalendar with year,month,data"); 346 } 347 } 348 349 { 350 // new BuddhistCalendar(int year, int month, int date, int hour, int minute, int second) 351 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22, 1, 1, 1); 352 if(cal == null){ 353 errln("could not create BuddhistCalendar with year,month,date,hour,minute,second"); 354 } 355 } 356 357 { 358 // data 359 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22); 360 Date time = cal.getTime(); 361 362 String[] calendarLocales = { 363 "th_TH" 364 }; 365 366 String[] formatLocales = { 367 "en", "ar", "hu", "th" 368 }; 369 370 for (int i = 0; i < calendarLocales.length; ++i) { 371 String calLocName = calendarLocales[i]; 372 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName); 373 cal = new BuddhistCalendar(calLocale); 374 375 for (int j = 0; j < formatLocales.length; ++j) { 376 String locName = formatLocales[j]; 377 Locale formatLocale = LocaleUtility.getLocaleFromName(locName); 378 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale); 379 logln(calLocName + "/" + locName + " --> " + format.format(time)); 380 } 381 } 382 } 383 } 384 385 /** 386 * Test limits of the Buddhist calendar. 387 */ 388 @Test TestBuddhistLimits()389 public void TestBuddhistLimits() { 390 // Final parameter is either number of days, if > 0, or test 391 // duration in seconds, if < 0. 392 Calendar cal = Calendar.getInstance(); 393 cal.set(2007, Calendar.JANUARY, 1); 394 BuddhistCalendar buddhist = new BuddhistCalendar(); 395 doLimitsTest(buddhist, null, cal.getTime()); 396 doTheoreticalLimitsTest(buddhist, false); 397 } 398 399 /** 400 * Default calendar for Thai (Ticket#6302) 401 */ 402 @Test TestThaiDefault()403 public void TestThaiDefault() { 404 // Buddhist calendar is used as the default calendar for 405 // Thai locale 406 Calendar cal = Calendar.getInstance(new ULocale("th_TH")); 407 String type = cal.getType(); 408 // Android patch: Force default Gregorian calendar. 409 if (!type.equals("gregorian")) { 410 errln("FAIL: Gregorian calendar is not returned for locale " + cal.toString()); 411 } 412 // Android patch end. 413 } 414 415 /** 416 * Verify that TaiwanCalendar shifts years to Minguo Era but otherwise 417 * behaves like GregorianCalendar. 418 */ 419 @Test TestTaiwan()420 public void TestTaiwan() { 421 quasiGregorianTest(new TaiwanCalendar(), 422 new int[] { 423 TaiwanCalendar.BEFORE_MINGUO, 8, 1904, Calendar.FEBRUARY, 29, 424 TaiwanCalendar.MINGUO, 1, 1912, Calendar.JUNE, 4, 425 TaiwanCalendar.MINGUO, 3, 1914, Calendar.FEBRUARY, 12, 426 TaiwanCalendar.MINGUO, 96,2007, Calendar.FEBRUARY, 12, 427 }); 428 } 429 430 /** 431 * Test limits of the Taiwan calendar. 432 */ 433 @Test TestTaiwanLimits()434 public void TestTaiwanLimits() { 435 // Final parameter is either number of days, if > 0, or test 436 // duration in seconds, if < 0. 437 Calendar cal = Calendar.getInstance(); 438 cal.set(2007, Calendar.JANUARY, 1); 439 TaiwanCalendar taiwan = new TaiwanCalendar(); 440 doLimitsTest(taiwan, null, cal.getTime()); 441 doTheoreticalLimitsTest(taiwan, false); 442 } 443 444 @Test TestTaiwanCoverage()445 public void TestTaiwanCoverage() { 446 { 447 // new TaiwanCalendar(ULocale) 448 TaiwanCalendar cal = new TaiwanCalendar(ULocale.getDefault()); 449 if(cal == null){ 450 errln("could not create TaiwanCalendar with ULocale"); 451 } 452 } 453 454 { 455 // new TaiwanCalendar(TimeZone,ULocale) 456 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(),ULocale.getDefault()); 457 if(cal == null){ 458 errln("could not create TaiwanCalendar with TimeZone ULocale"); 459 } 460 } 461 462 { 463 // new TaiwanCalendar(TimeZone) 464 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault()); 465 if(cal == null){ 466 errln("could not create TaiwanCalendar with TimeZone"); 467 } 468 } 469 470 { 471 // new TaiwanCalendar(Locale) 472 TaiwanCalendar cal = new TaiwanCalendar(Locale.getDefault()); 473 if(cal == null){ 474 errln("could not create TaiwanCalendar with Locale"); 475 } 476 } 477 478 { 479 // new TaiwanCalendar(TimeZone, Locale) 480 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(), Locale.getDefault()); 481 if(cal == null){ 482 errln("could not create TaiwanCalendar with TimeZone and Locale"); 483 } 484 } 485 486 { 487 // new TaiwanCalendar(Date) 488 TaiwanCalendar cal = new TaiwanCalendar(new Date()); 489 if(cal == null){ 490 errln("could not create TaiwanCalendar with Date"); 491 } 492 } 493 494 { 495 // new TaiwanCalendar(int year, int month, int date) 496 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22); 497 if(cal == null){ 498 errln("could not create TaiwanCalendar with year,month,data"); 499 } 500 } 501 502 { 503 // new TaiwanCalendar(int year, int month, int date, int hour, int minute, int second) 504 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22, 1, 1, 1); 505 if(cal == null){ 506 errln("could not create TaiwanCalendar with year,month,date,hour,minute,second"); 507 } 508 } 509 510 { 511 // data 512 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22); 513 Date time = cal.getTime(); 514 515 String[] calendarLocales = { 516 "en","zh" 517 }; 518 519 String[] formatLocales = { 520 "en", "ar", "hu", "th" 521 }; 522 523 for (int i = 0; i < calendarLocales.length; ++i) { 524 String calLocName = calendarLocales[i]; 525 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName); 526 cal = new TaiwanCalendar(calLocale); 527 528 for (int j = 0; j < formatLocales.length; ++j) { 529 String locName = formatLocales[j]; 530 Locale formatLocale = LocaleUtility.getLocaleFromName(locName); 531 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale); 532 logln(calLocName + "/" + locName + " --> " + format.format(time)); 533 } 534 } 535 } 536 } 537 538 /** 539 * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise 540 * behaves like GregorianCalendar. 541 */ 542 @Test TestJapanese()543 public void TestJapanese() { 544 // First make sure this test works for GregorianCalendar 545 int[] control = { 546 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 8, 547 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 9, 548 GregorianCalendar.AD, 1869, 1869, Calendar.JUNE, 4, 549 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 29, 550 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 30, 551 GregorianCalendar.AD, 1912, 1912, Calendar.AUGUST, 1, 552 }; 553 quasiGregorianTest(new GregorianCalendar(), control); 554 555 int[] data = { 556 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 8, 557 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 9, 558 JapaneseCalendar.MEIJI, 2, 1869, Calendar.JUNE, 4, 559 JapaneseCalendar.MEIJI, 45, 1912, Calendar.JULY, 29, 560 JapaneseCalendar.TAISHO, 1, 1912, Calendar.JULY, 30, 561 JapaneseCalendar.TAISHO, 1, 1912, Calendar.AUGUST, 1, 562 }; 563 quasiGregorianTest(new JapaneseCalendar(), data); 564 } 565 566 /** 567 * Test limits of the Gregorian calendar. 568 */ 569 @Test TestGregorianLimits()570 public void TestGregorianLimits() { 571 // Final parameter is either number of days, if > 0, or test 572 // duration in seconds, if < 0. 573 Calendar cal = Calendar.getInstance(); 574 cal.set(2004, Calendar.JANUARY, 1); 575 GregorianCalendar gregorian = new GregorianCalendar(); 576 doLimitsTest(gregorian, null, cal.getTime()); 577 doTheoreticalLimitsTest(gregorian, false); 578 } 579 580 /** 581 * Test behavior of fieldDifference around leap years. Also test a large 582 * field difference to check binary search. 583 */ 584 @Test TestLeapFieldDifference()585 public void TestLeapFieldDifference() { 586 Calendar cal = Calendar.getInstance(); 587 cal.set(2004, Calendar.FEBRUARY, 29); 588 Date date2004 = cal.getTime(); 589 cal.set(2000, Calendar.FEBRUARY, 29); 590 Date date2000 = cal.getTime(); 591 int y = cal.fieldDifference(date2004, Calendar.YEAR); 592 int d = cal.fieldDifference(date2004, Calendar.DAY_OF_YEAR); 593 if (d == 0) { 594 logln("Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days"); 595 } else { 596 errln("FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days"); 597 } 598 cal.setTime(date2004); 599 y = cal.fieldDifference(date2000, Calendar.YEAR); 600 d = cal.fieldDifference(date2000, Calendar.DAY_OF_YEAR); 601 if (d == 0) { 602 logln("Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days"); 603 } else { 604 errln("FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days"); 605 } 606 // Test large difference 607 cal.set(2001, Calendar.APRIL, 5); // 2452005 608 Date ayl = cal.getTime(); 609 cal.set(1964, Calendar.SEPTEMBER, 7); // 2438646 610 Date asl = cal.getTime(); 611 d = cal.fieldDifference(ayl, Calendar.DAY_OF_MONTH); 612 cal.setTime(ayl); 613 int d2 = cal.fieldDifference(asl, Calendar.DAY_OF_MONTH); 614 if (d == -d2 && d == 13359) { 615 logln("Ok: large field difference symmetrical " + d); 616 } else { 617 logln("FAIL: large field difference incorrect " + d + ", " + d2 + 618 ", expect +/- 13359"); 619 } 620 } 621 622 /** 623 * Test ms_MY "Malay (Malaysia)" locale. Bug 1543. 624 */ 625 @Test TestMalaysianInstance()626 public void TestMalaysianInstance() { 627 Locale loc = new Locale("ms", "MY"); // Malay (Malaysia) 628 Calendar cal = Calendar.getInstance(loc); 629 if(cal == null){ 630 errln("could not create Malaysian instance"); 631 } 632 } 633 634 /** 635 * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the 636 * field <=> time mapping, since they affect the interpretation of 637 * the WEEK_OF_MONTH or WEEK_OF_YEAR fields. 638 */ 639 @Test TestWeekShift()640 public void TestWeekShift() { 641 Calendar cal = new GregorianCalendar( 642 TimeZone.getTimeZone("America/Los_Angeles"), 643 new Locale("en", "US")); 644 cal.setTime(new Date(997257600000L)); // Wed Aug 08 01:00:00 PDT 2001 645 // In pass one, change the first day of week so that the weeks 646 // shift in August 2001. In pass two, change the minimal days 647 // in the first week so that the weeks shift in August 2001. 648 // August 2001 649 // Su Mo Tu We Th Fr Sa 650 // 1 2 3 4 651 // 5 6 7 8 9 10 11 652 // 12 13 14 15 16 17 18 653 // 19 20 21 22 23 24 25 654 // 26 27 28 29 30 31 655 for (int pass=0; pass<2; ++pass) { 656 if (pass==0) { 657 cal.setFirstDayOfWeek(Calendar.WEDNESDAY); 658 cal.setMinimalDaysInFirstWeek(4); 659 } else { 660 cal.setFirstDayOfWeek(Calendar.SUNDAY); 661 cal.setMinimalDaysInFirstWeek(4); 662 } 663 cal.add(Calendar.DATE, 1); // Force recalc 664 cal.add(Calendar.DATE, -1); 665 666 Date time1 = cal.getTime(); // Get time -- should not change 667 668 // Now change a week parameter and then force a recalc. 669 // The bug is that the recalc should not be necessary -- 670 // calendar should do so automatically. 671 if (pass==0) { 672 cal.setFirstDayOfWeek(Calendar.THURSDAY); 673 } else { 674 cal.setMinimalDaysInFirstWeek(5); 675 } 676 677 int woy1 = cal.get(Calendar.WEEK_OF_YEAR); 678 int wom1 = cal.get(Calendar.WEEK_OF_MONTH); 679 680 cal.add(Calendar.DATE, 1); // Force recalc 681 cal.add(Calendar.DATE, -1); 682 683 int woy2 = cal.get(Calendar.WEEK_OF_YEAR); 684 int wom2 = cal.get(Calendar.WEEK_OF_MONTH); 685 686 Date time2 = cal.getTime(); 687 688 if (!time1.equals(time2)) { 689 errln("FAIL: shifting week should not alter time"); 690 } else { 691 logln(time1.toString()); 692 } 693 if (woy1 == woy2 && wom1 == wom2) { 694 logln("Ok: WEEK_OF_YEAR: " + woy1 + 695 ", WEEK_OF_MONTH: " + wom1); 696 } else { 697 errln("FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 + 698 ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 + 699 " after week shift"); 700 } 701 } 702 } 703 704 /** 705 * Make sure that when adding a day, we actually wind up in a 706 * different day. The DST adjustments we use to keep the hour 707 * constant across DST changes can backfire and change the day. 708 */ 709 @Test TestTimeZoneTransitionAdd()710 public void TestTimeZoneTransitionAdd() { 711 Locale locale = Locale.US; // could also be CHINA 712 SimpleDateFormat dateFormat = 713 new SimpleDateFormat("MM/dd/yyyy HH:mm z", locale); 714 715 String tz[] = TimeZone.getAvailableIDs(); 716 717 for (int z=0; z<tz.length; ++z) { 718 TimeZone t = TimeZone.getTimeZone(tz[z]); 719 dateFormat.setTimeZone(t); 720 721 Calendar cal = Calendar.getInstance(t, locale); 722 cal.clear(); 723 // Scan the year 2003, overlapping the edges of the year 724 cal.set(Calendar.YEAR, 2002); 725 cal.set(Calendar.MONTH, Calendar.DECEMBER); 726 cal.set(Calendar.DAY_OF_MONTH, 25); 727 728 for (int i=0; i<365+10; ++i) { 729 Date yesterday = cal.getTime(); 730 int yesterday_day = cal.get(Calendar.DAY_OF_MONTH); 731 cal.add(Calendar.DAY_OF_MONTH, 1); 732 if (yesterday_day == cal.get(Calendar.DAY_OF_MONTH)) { 733 errln(tz[z] + " " + 734 dateFormat.format(yesterday) + " +1d= " + 735 dateFormat.format(cal.getTime())); 736 } 737 } 738 } 739 } 740 741 @Test TestJB1684()742 public void TestJB1684() { 743 class TestData { 744 int year; 745 int month; 746 int date; 747 int womyear; 748 int wommon; 749 int wom; 750 int dow; 751 String data; 752 String normalized; 753 754 public TestData(int year, int month, int date, 755 int womyear, int wommon, int wom, int dow, 756 String data, String normalized) { 757 this.year = year; 758 this.month = month-1; 759 this.date = date; 760 this.womyear = womyear; 761 this.wommon = wommon-1; 762 this.wom = wom; 763 this.dow = dow; 764 this.data = data; // year, month, week of month, day 765 this.normalized = data; 766 if (normalized != null) this.normalized = normalized; 767 } 768 } 769 770 // July 2001 August 2001 January 2002 771 // Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 772 // 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 5 773 // 8 9 10 11 12 13 14 5 6 7 8 9 10 11 6 7 8 9 10 11 12 774 // 15 16 17 18 19 20 21 12 13 14 15 16 17 18 13 14 15 16 17 18 19 775 // 22 23 24 25 26 27 28 19 20 21 22 23 24 25 20 21 22 23 24 25 26 776 // 29 30 31 26 27 28 29 30 31 27 28 29 30 31 777 TestData[] tests = { 778 new TestData(2001, 8, 6, 2001,8,2,Calendar.MONDAY, "2001 08 02 Mon", null), 779 new TestData(2001, 8, 7, 2001,8,2,Calendar.TUESDAY, "2001 08 02 Tue", null), 780 new TestData(2001, 8, 5,/*12,*/ 2001,8,2,Calendar.SUNDAY, "2001 08 02 Sun", null), 781 new TestData(2001, 8,6, /*7, 30,*/ 2001,7,6,Calendar.MONDAY, "2001 07 06 Mon", "2001 08 02 Mon"), 782 new TestData(2001, 8,7, /*7, 31,*/ 2001,7,6,Calendar.TUESDAY, "2001 07 06 Tue", "2001 08 02 Tue"), 783 new TestData(2001, 8, 5, 2001,7,6,Calendar.SUNDAY, "2001 07 06 Sun", "2001 08 02 Sun"), 784 new TestData(2001, 7, 30, 2001,8,1,Calendar.MONDAY, "2001 08 01 Mon", "2001 07 05 Mon"), 785 new TestData(2001, 7, 31, 2001,8,1,Calendar.TUESDAY, "2001 08 01 Tue", "2001 07 05 Tue"), 786 new TestData(2001, 7,29, /*8, 5,*/ 2001,8,1,Calendar.SUNDAY, "2001 08 01 Sun", "2001 07 05 Sun"), 787 new TestData(2001, 12, 31, 2001,12,6,Calendar.MONDAY, "2001 12 06 Mon", null), 788 new TestData(2002, 1, 1, 2002,1,1,Calendar.TUESDAY, "2002 01 01 Tue", null), 789 new TestData(2002, 1, 2, 2002,1,1,Calendar.WEDNESDAY, "2002 01 01 Wed", null), 790 new TestData(2002, 1, 3, 2002,1,1,Calendar.THURSDAY, "2002 01 01 Thu", null), 791 new TestData(2002, 1, 4, 2002,1,1,Calendar.FRIDAY, "2002 01 01 Fri", null), 792 new TestData(2002, 1, 5, 2002,1,1,Calendar.SATURDAY, "2002 01 01 Sat", null), 793 new TestData(2001,12,30, /*2002, 1, 6,*/ 2002,1,1,Calendar.SUNDAY, "2002 01 01 Sun", "2001 12 06 Sun"), 794 }; 795 796 int pass = 0, error = 0, warning = 0; 797 798 final String pattern = "yyyy MM WW EEE"; 799 GregorianCalendar cal = new GregorianCalendar(); 800 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 801 sdf.setCalendar(cal); 802 803 cal.setFirstDayOfWeek(Calendar.SUNDAY); 804 cal.setMinimalDaysInFirstWeek(1); 805 806 for (int i = 0; i < tests.length; ++i) { 807 TestData test = tests[i]; 808 log("\n-----\nTesting round trip of " + test.year + 809 " " + (test.month + 1) + 810 " " + test.date + 811 " (written as) " + test.data); 812 813 cal.clear(); 814 cal.set(test.year, test.month, test.date); 815 Date ms = cal.getTime(); 816 817 cal.clear(); 818 cal.set(Calendar.YEAR, test.womyear); 819 cal.set(Calendar.MONTH, test.wommon); 820 cal.set(Calendar.WEEK_OF_MONTH, test.wom); 821 cal.set(Calendar.DAY_OF_WEEK, test.dow); 822 Date ms2 = cal.getTime(); 823 824 if (!ms2.equals(ms)) { 825 log("\nError: GregorianCalendar.DOM gave " + ms + 826 "\n GregorianCalendar.WOM gave " + ms2); 827 error++; 828 } else { 829 pass++; 830 } 831 832 ms2 = null; 833 try { 834 ms2 = sdf.parse(test.data); 835 } 836 catch (ParseException e) { 837 errln("parse exception: " + e); 838 } 839 840 if (!ms2.equals(ms)) { 841 log("\nError: GregorianCalendar gave " + ms + 842 "\n SimpleDateFormat.parse gave " + ms2); 843 error++; 844 } else { 845 pass++; 846 } 847 848 String result = sdf.format(ms); 849 if (!result.equals(test.normalized)) { 850 log("\nWarning: format of '" + test.data + "' gave" + 851 "\n '" + result + "'" + 852 "\n expected '" + test.normalized + "'"); 853 warning++; 854 } else { 855 pass++; 856 } 857 858 Date ms3 = null; 859 try { 860 ms3 = sdf.parse(result); 861 } 862 catch (ParseException e) { 863 errln("parse exception 2: " + e); 864 } 865 866 if (!ms3.equals(ms)) { 867 error++; 868 log("\nError: Re-parse of '" + result + "' gave time of " + 869 "\n " + ms3 + 870 "\n not " + ms); 871 } else { 872 pass++; 873 } 874 } 875 String info = "\nPassed: " + pass + ", Warnings: " + warning + ", Errors: " + error; 876 if (error > 0) { 877 errln(info); 878 } else { 879 logln(info); 880 } 881 } 882 883 /** 884 * Test the ZoneMeta API. 885 */ 886 @Test TestZoneMeta()887 public void TestZoneMeta() { 888 // Test index by country API 889 890 // Format: {country, zone1, zone2, ..., zoneN} 891 String COUNTRY[][] = { {""}, 892 {"US", "America/Los_Angeles", "PST"} }; 893 StringBuffer buf = new StringBuffer(); 894 for (int i=0; i<COUNTRY.length; ++i) { 895 Set<String> a = ZoneMeta.getAvailableIDs(SystemTimeZoneType.ANY, COUNTRY[i][0], null); 896 buf.setLength(0); 897 buf.append("Country \"" + COUNTRY[i][0] + "\": ["); 898 // Use bitmask to track which of the expected zones we see 899 int mask = 0; 900 boolean first = true; 901 for (String z : a) { 902 if (first) { 903 first = false; 904 } else { 905 buf.append(", "); 906 } 907 buf.append(z); 908 for (int k = 1; k < COUNTRY[i].length; ++k) { 909 if ((mask & (1 << k)) == 0 && z.equals(COUNTRY[i][k])) { 910 mask |= (1 << k); 911 } 912 } 913 } 914 buf.append("]"); 915 mask >>= 1; 916 // Check bitmask to see if we saw all expected zones 917 if (mask == (1 << (COUNTRY[i].length-1))-1) { 918 logln(buf.toString()); 919 } else { 920 errln(buf.toString()); 921 } 922 } 923 924 // Test equivalent IDs API 925 926 int n = ZoneMeta.countEquivalentIDs("PST"); 927 boolean ok = false; 928 buf.setLength(0); 929 buf.append("Equivalent to PST: "); 930 for (int i=0; i<n; ++i) { 931 String id = ZoneMeta.getEquivalentID("PST", i); 932 if (id.equals("America/Los_Angeles")) { 933 ok = true; 934 } 935 if (i!=0) buf.append(", "); 936 buf.append(id); 937 } 938 if (ok) { 939 logln(buf.toString()); 940 } else { 941 errln(buf.toString()); 942 } 943 } 944 945 @Test TestComparable()946 public void TestComparable() { 947 GregorianCalendar c0 = new GregorianCalendar(); 948 GregorianCalendar c1 = new GregorianCalendar(); 949 c1.add(Calendar.DAY_OF_MONTH, 1); 950 if (c0.compareTo(c1) >= 0) { 951 errln("calendar " + c0 + " not < " + c1); 952 } 953 c0.add(Calendar.MONTH, 1); 954 if (c0.compareTo(c1) <= 0) { 955 errln("calendar " + c0 + " not > " + c1); 956 } 957 958 c0.setTimeInMillis(c1.getTimeInMillis()); 959 if (c0.compareTo(c1) != 0) { 960 errln("calendar " + c0 + " not == " + c1); 961 } 962 963 } 964 965 /** 966 * Miscellaneous tests to increase coverage. 967 */ 968 @Test TestCoverage()969 public void TestCoverage() { 970 // BuddhistCalendar 971 BuddhistCalendar bcal = new BuddhistCalendar(); 972 /*int i =*/ bcal.getMinimum(Calendar.ERA); 973 bcal.add(Calendar.YEAR, 1); 974 bcal.add(Calendar.MONTH, 1); 975 /*Date d = */bcal.getTime(); 976 977 // CalendarAstronomer 978 // (This class should probably be made package-private.) 979 CalendarAstronomer astro = new CalendarAstronomer(); 980 981 // ChineseCalendar 982 ChineseCalendar ccal = new ChineseCalendar(TimeZone.getDefault(), 983 Locale.getDefault()); 984 ccal.add(Calendar.MONTH, 1); 985 ccal.add(Calendar.YEAR, 1); 986 ccal.roll(Calendar.MONTH, 1); 987 ccal.roll(Calendar.YEAR, 1); 988 ccal.getTime(); 989 990 // ICU 2.6 991 Calendar cal = Calendar.getInstance(Locale.US); 992 logln(cal.toString()); 993 logln(cal.getDisplayName(Locale.US)); 994 int weekendOnset=-1; 995 int weekendCease=-1; 996 for (int i=Calendar.SUNDAY; i<=Calendar.SATURDAY; ++i) { 997 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_ONSET) { 998 weekendOnset = i; 999 } 1000 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_CEASE) { 1001 weekendCease = i; 1002 } 1003 } 1004 // can't call this unless we get a transition day (unusual), 1005 // but make the call anyway for coverage reasons 1006 try { 1007 /*int x=*/ cal.getWeekendTransition(weekendOnset); 1008 /*int x=*/ cal.getWeekendTransition(weekendCease); 1009 } catch (IllegalArgumentException e) {} 1010 /*int x=*/ cal.isWeekend(new Date()); 1011 1012 // new GregorianCalendar(ULocale) 1013 GregorianCalendar gcal = new GregorianCalendar(ULocale.getDefault()); 1014 if(gcal==null){ 1015 errln("could not create GregorianCalendar with ULocale"); 1016 } else { 1017 logln("Calendar display name: " + gcal.getDisplayName(ULocale.getDefault())); 1018 } 1019 1020 //cover getAvailableULocales 1021 final ULocale[] locales = Calendar.getAvailableULocales(); 1022 long count = locales.length; 1023 if (count == 0) 1024 errln("getAvailableULocales return empty list"); 1025 logln("" + count + " available ulocales in Calendar."); 1026 1027 // Jitterbug 4451, for coverage 1028 class StubCalendar extends Calendar{ 1029 /** 1030 * For serialization 1031 */ 1032 private static final long serialVersionUID = -4558903444622684759L; 1033 1034 @Override 1035 protected int handleGetLimit(int field, int limitType) { 1036 if (limitType == Calendar.LEAST_MAXIMUM) { 1037 return 1; 1038 } else if (limitType == Calendar.GREATEST_MINIMUM) { 1039 return 7; 1040 } 1041 return -1; 1042 } 1043 @Override 1044 protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) { 1045 if (useMonth) { 1046 return eyear * 365 + month * 31; 1047 } else { 1048 return eyear * 365; 1049 } 1050 } 1051 @Override 1052 protected int handleGetExtendedYear() {return 2017;} 1053 1054 public void run(){ 1055 if (Calendar.gregorianPreviousMonthLength(2000,2) != 29){ 1056 errln("Year 2000 Feb should have 29 days."); 1057 } 1058 long millis = Calendar.julianDayToMillis(Calendar.MAX_JULIAN); 1059 if(millis != Calendar.MAX_MILLIS){ 1060 errln("Did not get the expected value from julianDayToMillis. Got:" + millis); 1061 } 1062 DateFormat df = handleGetDateFormat("",Locale.getDefault()); 1063 if (!df.equals(handleGetDateFormat("",ULocale.getDefault()))){ 1064 errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)"); 1065 } 1066 if (!getType().equals("unknown")){ 1067 errln ("Calendar.getType() should be 'unknown'"); 1068 } 1069 1070 // Tests for complete coverage of Calendar functions. 1071 int julianDay = Calendar.millisToJulianDay(millis - 1); 1072 assertEquals("Julian max day -1", julianDay, Calendar.MAX_JULIAN - 1); 1073 1074 DateFormat df1 = handleGetDateFormat("GG yyyy-d:MM", "option=xyz", Locale.getDefault()); 1075 if (!df1.equals(handleGetDateFormat("GG yyyy-d:MM", "option=xyz", ULocale.getDefault()))){ 1076 errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)"); 1077 } 1078 1079 // Prove that the local overrides are used. 1080 int leastMsInDay = handleGetLimit(Calendar.MILLISECONDS_IN_DAY, Calendar.LEAST_MAXIMUM); 1081 assertEquals("getLimit test 1", leastMsInDay, 1); 1082 int maxMsInDay = handleGetLimit(Calendar.WEEK_OF_MONTH, Calendar.GREATEST_MINIMUM); 1083 assertEquals("getLimit test 2", 7, maxMsInDay); 1084 1085 int febLeapLength = handleGetMonthLength(2020, Calendar.FEBRUARY); 1086 assertEquals("handleMonthLength", 31, febLeapLength); 1087 int exYear = handleGetExtendedYear(); 1088 assertEquals("handleGetExtendeYear", exYear, 2017); 1089 int monthStart = handleComputeMonthStart(2016, 4, false); 1090 assertEquals("handleComputeMonthStart false", 735840, monthStart); 1091 monthStart = handleComputeMonthStart(2016, 4, true); 1092 assertEquals("handleComputeMonthStart true", 735964, monthStart); 1093 1094 Calendar cal = Calendar.getInstance(); 1095 cal.set(1980, 5, 2); 1096 this.setTime(cal.getTime()); 1097 assertEquals("handleComputeFields: year set", 1980, get(YEAR)); 1098 assertEquals("handleComputeFields: month set", 5, get(MONTH)); 1099 assertEquals("handleComputeFields: day set", 2, get(DAY_OF_MONTH)); 1100 } 1101 } 1102 StubCalendar stub = new StubCalendar(); 1103 stub.run(); 1104 } 1105 1106 // Tests for jb 4541 1107 @Test TestJB4541()1108 public void TestJB4541() { 1109 ULocale loc = new ULocale("en_US"); 1110 1111 // !!! Shouldn't we have an api like this? 1112 // !!! Question: should this reflect those actually available in this copy of ICU, or 1113 // the list of types we assume is available? 1114 // String[] calTypes = Calendar.getAvailableTypes(); 1115 final String[] calTypes = { 1116 "buddhist", "chinese", "coptic", "ethiopic", "gregorian", "hebrew", 1117 "islamic", "islamic-civil", "japanese", "roc" 1118 }; 1119 1120 // constructing a DateFormat with a locale indicating a calendar type should construct a 1121 // date format appropriate to that calendar 1122 final Date time = new Date(); 1123 for (int i = 0; i < calTypes.length; ++i) { 1124 ULocale aLoc = loc.setKeywordValue("calendar", calTypes[i]); 1125 logln("locale: " + aLoc); 1126 1127 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, 1128 DateFormat.FULL, 1129 aLoc); 1130 1131 logln("df type: " + df.getClass().getName() + " loc: " + df.getLocale(ULocale.VALID_LOCALE)); 1132 1133 Calendar cal = df.getCalendar(); 1134 assertEquals("calendar types", cal.getType(), calTypes[i]); 1135 DateFormat df2 = cal.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, ULocale.US); 1136 logln("df2 type: " + df2.getClass().getName() + " loc: " + df2.getLocale(ULocale.VALID_LOCALE)); 1137 assertEquals("format results", df.format(time), df2.format(time)); 1138 } 1139 1140 // dateFormat.setCalendar should throw exception if wrong format for calendar 1141 if (false) { 1142 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, 1143 DateFormat.FULL, 1144 new ULocale("en_US@calendar=chinese")); 1145 1146 logln("dateformat type: " + df.getClass().getName()); 1147 1148 Calendar cal = Calendar.getInstance(new ULocale("en_US@calendar=chinese")); 1149 1150 logln("calendar type: " + cal.getClass().getName()); 1151 } 1152 } 1153 1154 @Test TestTypes()1155 public void TestTypes() { 1156 String[] locs = { 1157 "en_US_VALLEYGIRL", 1158 "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese", 1159 "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian", 1160 "ja_JP@calendar=japanese", 1161 "th_TH@calendar=buddhist", 1162 "th-TH-u-ca-gregory", 1163 "th_TH_TRADITIONAL", 1164 "th_TH_TRADITIONAL@calendar=gregorian", 1165 "en_US", 1166 "th_TH", // Default calendar for th_TH is buddhist 1167 "th", // th's default region is TH and buddhist is used as default for TH 1168 "en_TH", // Default calendar for any locales with region TH is buddhist 1169 "th_TH@calendar=iso8601", // iso8601 calendar type 1170 "fr_CH", 1171 "fr_SA", 1172 "fr_CH@rg=sazzzz", 1173 "fr_CH@rg=sa14", 1174 "fr_CH@calendar=japanese;rg=sazzzz", 1175 "fr_CH@rg=twcyi", // test for ICU-22364 1176 "fr_CH@rg=ugw", // test for ICU-22364 1177 "fr_TH@rg=SA", // ignore malformed rg tag, use buddhist 1178 "th@rg=SA", // ignore malformed rg tag, use buddhist 1179 }; 1180 1181 // Android patch: Force default Gregorian calendar regardless of region. 1182 String[] types = { 1183 "gregorian", 1184 "japanese", 1185 "gregorian", 1186 "japanese", 1187 "buddhist", 1188 "gregorian", 1189 "gregorian", 1190 "gregorian", 1191 "gregorian", 1192 "gregorian", 1193 "gregorian", 1194 "gregorian", 1195 "gregorian", // iso8601 is a gregorian sub type 1196 "gregorian", 1197 "gregorian", 1198 "gregorian", 1199 "gregorian", 1200 "japanese", 1201 "gregorian", 1202 "gregorian", 1203 "gregorian", 1204 "gregorian", 1205 }; 1206 // Android patch end. 1207 1208 for (int i = 0; i < locs.length; i++) { 1209 Calendar cal = Calendar.getInstance(new ULocale(locs[i])); 1210 if (!cal.getType().equals(types[i])) { 1211 errln(locs[i] + " Calendar type " + cal.getType() + " instead of " + types[i]); 1212 } 1213 } 1214 } 1215 1216 @Test TestISO8601()1217 public void TestISO8601() { 1218 final ULocale[] TEST_LOCALES = { 1219 new ULocale("en_US@calendar=iso8601"), 1220 new ULocale("en_US@calendar=Iso8601"), 1221 new ULocale("th_TH@calendar=iso8601"), 1222 new ULocale("ar_EG@calendar=iso8601") 1223 }; 1224 1225 final int[][] TEST_DATA = { 1226 // {<year>, <week# of Jan 1>, <week# year of Jan 1>} 1227 {2008, 1, 2008}, 1228 {2009, 1, 2009}, 1229 {2010, 53, 2009}, 1230 {2011, 52, 2010}, 1231 {2012, 52, 2011}, 1232 {2013, 1, 2013}, 1233 {2014, 1, 2014}, 1234 }; 1235 1236 for (ULocale locale : TEST_LOCALES) { 1237 Calendar cal = Calendar.getInstance(locale); 1238 // No matter what locale is used, if calendar type is "iso8601", 1239 // calendar type must be Gregorian 1240 if (!cal.getType().equals("gregorian")) { 1241 errln("Error: Gregorian calendar is not used for locale: " + locale); 1242 } 1243 1244 for (int[] data : TEST_DATA) { 1245 cal.set(data[0], Calendar.JANUARY, 1); 1246 int weekNum = cal.get(Calendar.WEEK_OF_YEAR); 1247 int weekYear = cal.get(Calendar.YEAR_WOY); 1248 1249 if (weekNum != data[1] || weekYear != data[2]) { 1250 errln("Error: Incorrect week of year on January 1st, " + data[0] 1251 + " for locale " + locale 1252 + ": Returned [weekNum=" + weekNum + ", weekYear=" + weekYear 1253 + "], Expected [weekNum=" + data[1] + ", weekYear=" + data[2] + "]"); 1254 } 1255 } 1256 } 1257 } 1258 1259 private static class CalFields { 1260 private int year; 1261 private int month; 1262 private int day; 1263 private int hour; 1264 private int min; 1265 private int sec; 1266 private int ms; 1267 CalFields(int year, int month, int day, int hour, int min, int sec)1268 CalFields(int year, int month, int day, int hour, int min, int sec) { 1269 this(year, month, day, hour, min, sec, 0); 1270 } 1271 CalFields(int year, int month, int day, int hour, int min, int sec, int ms)1272 CalFields(int year, int month, int day, int hour, int min, int sec, int ms) { 1273 this.year = year; 1274 this.month = month; 1275 this.day = day; 1276 this.hour = hour; 1277 this.min = min; 1278 this.sec = sec; 1279 this.ms = ms; 1280 } 1281 setTo(Calendar cal)1282 void setTo(Calendar cal) { 1283 cal.clear(); 1284 cal.set(year, month - 1, day, hour, min, sec); 1285 cal.set(Calendar.MILLISECOND, ms); 1286 } 1287 1288 @Override toString()1289 public String toString() { 1290 return String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms); 1291 } 1292 1293 @Override equals(Object other)1294 public boolean equals(Object other) { 1295 if (other instanceof CalFields) { 1296 CalFields otr = (CalFields)other; 1297 return (year == otr.year 1298 && month == otr.month 1299 && day == otr.day 1300 && hour == otr.hour 1301 && min == otr.min 1302 && sec == otr.sec 1303 && ms == otr.ms); 1304 } 1305 return false; 1306 } 1307 isEquivalentTo(Calendar cal)1308 boolean isEquivalentTo(Calendar cal) { 1309 return year == cal.get(Calendar.YEAR) 1310 && month == cal.get(Calendar.MONTH) + 1 1311 && day == cal.get(Calendar.DAY_OF_MONTH) 1312 && hour == cal.get(Calendar.HOUR_OF_DAY) 1313 && min == cal.get(Calendar.MINUTE) 1314 && sec == cal.get(Calendar.SECOND) 1315 && ms == cal.get(Calendar.MILLISECOND); 1316 } 1317 createFrom(Calendar cal)1318 static CalFields createFrom(Calendar cal) { 1319 int year = cal.get(Calendar.YEAR); 1320 int month = cal.get(Calendar.MONTH) + 1; 1321 int day = cal.get(Calendar.DAY_OF_MONTH); 1322 int hour = cal.get(Calendar.HOUR_OF_DAY); 1323 int min = cal.get(Calendar.MINUTE); 1324 int sec = cal.get(Calendar.SECOND); 1325 1326 return new CalFields(year, month, day, hour, min, sec); 1327 } 1328 } 1329 1330 @Test TestAmbiguousWallTimeAPIs()1331 public void TestAmbiguousWallTimeAPIs() { 1332 Calendar cal = Calendar.getInstance(); 1333 1334 assertEquals("Default repeated wall time option", cal.getRepeatedWallTimeOption(), Calendar.WALLTIME_LAST); 1335 assertEquals("Default skipped wall time option", cal.getSkippedWallTimeOption(), Calendar.WALLTIME_LAST); 1336 1337 Calendar cal2 = (Calendar)cal.clone(); 1338 1339 assertTrue("Equality", cal2.equals(cal)); 1340 assertTrue("Hash code", cal.hashCode() == cal2.hashCode()); 1341 1342 cal2.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST); 1343 cal2.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST); 1344 1345 assertFalse("Equality after mod", cal2.equals(cal)); 1346 assertFalse("Hash code after mod", cal.hashCode() == cal2.hashCode()); 1347 1348 assertEquals("getRepeatedWallTimeOption after mod", cal2.getRepeatedWallTimeOption(), Calendar.WALLTIME_FIRST); 1349 assertEquals("getSkippedWallTimeOption after mod", cal2.getSkippedWallTimeOption(), Calendar.WALLTIME_FIRST); 1350 1351 try { 1352 cal.setRepeatedWallTimeOption(Calendar.WALLTIME_NEXT_VALID); 1353 errln("IAE expected on setRepeatedWallTimeOption(WALLTIME_NEXT_VALID"); 1354 } catch (IllegalArgumentException e) { 1355 // expected 1356 } 1357 } 1358 1359 @Test TestRepeatedWallTime()1360 public void TestRepeatedWallTime() { 1361 final Object[][] TESTDATA = { 1362 // Time zone Input wall time WALLTIME_LAST in GMT WALLTIME_FIRST in GMT 1363 {"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)}, 1364 {"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)}, 1365 {"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)}, 1366 {"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)}, 1367 {"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)}, 1368 {"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)}, 1369 {"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)}, 1370 1371 {"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)}, 1372 {"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)}, 1373 {"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)}, 1374 {"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)}, 1375 {"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)}, 1376 {"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)}, 1377 }; 1378 1379 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE); 1380 1381 Calendar calDefault = Calendar.getInstance(); 1382 Calendar calLast = Calendar.getInstance(); 1383 Calendar calFirst = Calendar.getInstance(); 1384 1385 calFirst.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST); 1386 calLast.setRepeatedWallTimeOption(Calendar.WALLTIME_LAST); 1387 1388 for (Object[] test : TESTDATA) { 1389 String tzid = (String)test[0]; 1390 TimeZone tz = TimeZone.getTimeZone(tzid); 1391 CalFields in = (CalFields)test[1]; 1392 CalFields expLastGMT = (CalFields)test[2]; 1393 CalFields expFirstGMT = (CalFields)test[3]; 1394 1395 // WALLTIME_LAST 1396 calLast.setTimeZone(tz); 1397 in.setTo(calLast); 1398 calGMT.setTimeInMillis(calLast.getTimeInMillis()); 1399 CalFields outLastGMT = CalFields.createFrom(calGMT); 1400 if (!outLastGMT.equals(expLastGMT)) { 1401 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1402 } 1403 1404 // default 1405 calDefault.setTimeZone(tz); 1406 in.setTo(calDefault); 1407 calGMT.setTimeInMillis(calDefault.getTimeInMillis()); 1408 CalFields outDefGMT = CalFields.createFrom(calGMT); 1409 if (!outDefGMT.equals(expLastGMT)) { 1410 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1411 } 1412 1413 // WALLTIME_FIRST 1414 calFirst.setTimeZone(tz); 1415 in.setTo(calFirst); 1416 calGMT.setTimeInMillis(calFirst.getTimeInMillis()); 1417 CalFields outFirstGMT = CalFields.createFrom(calGMT); 1418 if (!outFirstGMT.equals(expFirstGMT)) { 1419 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]"); 1420 } 1421 } 1422 } 1423 1424 @Test TestSkippedWallTime()1425 public void TestSkippedWallTime() { 1426 final Object[][] TESTDATA = { 1427 // Time zone Input wall time Valid wall time? 1428 {"America/New_York", new CalFields(2011,3,13,1,59,59), true, 1429 // WALLTIME_LAST in GMT WALLTIME_FIRST in GMT WALLTIME_NEXT_VALID in GMT 1430 new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59)}, 1431 1432 {"America/New_York", new CalFields(2011,3,13,2,0,0), false, 1433 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,6,0,0), new CalFields(2011,3,13,7,0,0)}, 1434 1435 {"America/New_York", new CalFields(2011,3,13,2,1,0), false, 1436 new CalFields(2011,3,13,7,1,0), new CalFields(2011,3,13,6,1,0), new CalFields(2011,3,13,7,0,0)}, 1437 1438 {"America/New_York", new CalFields(2011,3,13,2,30,0), false, 1439 new CalFields(2011,3,13,7,30,0), new CalFields(2011,3,13,6,30,0), new CalFields(2011,3,13,7,0,0)}, 1440 1441 {"America/New_York", new CalFields(2011,3,13,2,59,59), false, 1442 new CalFields(2011,3,13,7,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,7,0,0)}, 1443 1444 {"America/New_York", new CalFields(2011,3,13,3,0,0), true, 1445 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0)}, 1446 1447 {"Pacific/Apia", new CalFields(2011,12,29,23,59,59), true, 1448 new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59)}, 1449 1450 {"Pacific/Apia", new CalFields(2011,12,30,0,0,0), false, 1451 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,29,10,0,0), new CalFields(2011,12,30,10,0,0)}, 1452 1453 {"Pacific/Apia", new CalFields(2011,12,30,12,0,0), false, 1454 new CalFields(2011,12,30,22,0,0), new CalFields(2011,12,29,22,0,0), new CalFields(2011,12,30,10,0,0)}, 1455 1456 {"Pacific/Apia", new CalFields(2011,12,30,23,59,59), false, 1457 new CalFields(2011,12,31,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,10,0,0)}, 1458 1459 {"Pacific/Apia", new CalFields(2011,12,31,0,0,0), true, 1460 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0)}, 1461 }; 1462 1463 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE); 1464 1465 Calendar calDefault = Calendar.getInstance(); 1466 Calendar calLast = Calendar.getInstance(); 1467 Calendar calFirst = Calendar.getInstance(); 1468 Calendar calNextAvail = Calendar.getInstance(); 1469 1470 calLast.setSkippedWallTimeOption(Calendar.WALLTIME_LAST); 1471 calFirst.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST); 1472 calNextAvail.setSkippedWallTimeOption(Calendar.WALLTIME_NEXT_VALID); 1473 1474 for (Object[] test : TESTDATA) { 1475 String tzid = (String)test[0]; 1476 TimeZone tz = TimeZone.getTimeZone(tzid); 1477 CalFields in = (CalFields)test[1]; 1478 boolean isValid = (Boolean)test[2]; 1479 CalFields expLastGMT = (CalFields)test[3]; 1480 CalFields expFirstGMT = (CalFields)test[4]; 1481 CalFields expNextAvailGMT = (CalFields)test[5]; 1482 1483 for (int i = 0; i < 2; i++) { 1484 boolean bLenient = (i == 0); 1485 1486 // WALLTIME_LAST 1487 calLast.setLenient(bLenient); 1488 calLast.setTimeZone(tz); 1489 try { 1490 in.setTo(calLast); 1491 calGMT.setTimeInMillis(calLast.getTimeInMillis()); 1492 CalFields outLastGMT = CalFields.createFrom(calGMT); 1493 if (!bLenient && !isValid) { 1494 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_LAST)"); 1495 } else if (!outLastGMT.equals(expLastGMT)) { 1496 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1497 } 1498 } catch (IllegalArgumentException e) { 1499 if (bLenient || isValid) { 1500 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_LAST)"); 1501 } 1502 } 1503 1504 // default 1505 calDefault.setLenient(bLenient); 1506 calDefault.setTimeZone(tz); 1507 try { 1508 in.setTo(calDefault); 1509 calGMT.setTimeInMillis(calDefault.getTimeInMillis()); 1510 CalFields outDefGMT = CalFields.createFrom(calGMT); 1511 if (!bLenient && !isValid) { 1512 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (default)"); 1513 } else if (!outDefGMT.equals(expLastGMT)) { 1514 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]"); 1515 } 1516 } catch (IllegalArgumentException e) { 1517 if (bLenient || isValid) { 1518 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (default)"); 1519 } 1520 } 1521 1522 // WALLTIME_FIRST 1523 calFirst.setLenient(bLenient); 1524 calFirst.setTimeZone(tz); 1525 try { 1526 in.setTo(calFirst); 1527 calGMT.setTimeInMillis(calFirst.getTimeInMillis()); 1528 CalFields outFirstGMT = CalFields.createFrom(calGMT); 1529 if (!bLenient && !isValid) { 1530 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_FIRST)"); 1531 } else if (!outFirstGMT.equals(expFirstGMT)) { 1532 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]"); 1533 } 1534 } catch (IllegalArgumentException e) { 1535 if (bLenient || isValid) { 1536 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_FIRST)"); 1537 } 1538 } 1539 1540 // WALLTIME_NEXT_VALID 1541 calNextAvail.setLenient(bLenient); 1542 calNextAvail.setTimeZone(tz); 1543 try { 1544 in.setTo(calNextAvail); 1545 calGMT.setTimeInMillis(calNextAvail.getTimeInMillis()); 1546 CalFields outNextAvailGMT = CalFields.createFrom(calGMT); 1547 if (!bLenient && !isValid) { 1548 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)"); 1549 } else if (!outNextAvailGMT.equals(expNextAvailGMT)) { 1550 errln("Fail: WALLTIME_NEXT_VALID " + in + "[" + tzid + "] is parsed as " + outNextAvailGMT + "[GMT]. Expected: " + expNextAvailGMT + "[GMT]"); 1551 } 1552 } catch (IllegalArgumentException e) { 1553 if (bLenient || isValid) { 1554 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)"); 1555 } 1556 } 1557 } 1558 } 1559 } 1560 1561 @Test TestFieldDifference()1562 public void TestFieldDifference() { 1563 class TFDItem { 1564 public String tzname; 1565 public String locale; 1566 public long start; 1567 public long target; 1568 public boolean progressive; // true to compute progressive difference for each field, false to reset calendar after each call 1569 int yDiff; 1570 int MDiff; 1571 int dDiff; 1572 int HDiff; 1573 int mDiff; 1574 int sDiff; // 0x7FFFFFFF indicates overflow error expected 1575 // Simple constructor 1576 public TFDItem(String tz, String loc, long st, long tg, boolean prg, int yD, int MD, int dD, int HD, int mD, int sD ) { 1577 tzname = tz; 1578 locale = loc; 1579 start = st; 1580 target = tg; 1581 progressive = prg; 1582 yDiff = yD; 1583 MDiff = MD; 1584 dDiff = dD; 1585 HDiff = HD; 1586 mDiff = mD; 1587 sDiff = sD; 1588 } 1589 }; 1590 final TFDItem[] tfdItems = { 1591 // timezobe locale start target prog yDf MDf dDf HDf mDf sDf 1592 // For these we compute the progressive difference for each field - not resetting the calendar after each call 1593 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 1594 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 1595 // For these we compute the total difference for each field - resetting the calendar after each call 1596 new TFDItem( "GMT", "en_US", 0, 1073692800000L, false, 34, 408, 12427, 298248, 17894880, 1073692800 ), // 1970-Jan-01 00:00 -> 2004-Jan-10 00:00 1597 new TFDItem( "GMT", "en_US", 0, 1073779200000L, false, 34, 408, 12428, 298272, 17896320, 1073779200 ), // 1970-Jan-01 00:00 -> 2004-Jan-11 00:00 1598 new TFDItem( "GMT", "en_US", 0, 2147472000000L, false, 68, 816, 24855, 596520, 35791200, 2147472000 ), // 1970-Jan-01 00:00 -> 2038-Jan-19 00:00 1599 // 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 1600 new TFDItem( "GMT", "en_US", 0, -1073692800000L, false, -34,-408,-12427,-298248,-17894880,-1073692800 ), // 1970-Jan-01 00:00 -> 1935-Dec-24 00:00 1601 new TFDItem( "GMT", "en_US", 0, -1073779200000L, false, -34,-408,-12428,-298272,-17896320,-1073779200 ), // 1970-Jan-01 00:00 -> 1935-Dec-23 00:00 1602 // check fwd/backward on either side of era boundary and across era boundary 1603 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 1604 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 1605 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 1606 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 1607 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 1608 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 1609 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 1610 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 1611 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 1612 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 1613 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 1614 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 1615 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 1616 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 1617 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 1618 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 1619 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 1620 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 1621 }; 1622 for (TFDItem tfdItem: tfdItems) { 1623 TimeZone timezone = TimeZone.getFrozenTimeZone(tfdItem.tzname); 1624 Calendar ucal = Calendar.getInstance(timezone, new ULocale(tfdItem.locale)); 1625 ucal.setTimeInMillis(tfdItem.target); 1626 Date targetDate = ucal.getTime(); 1627 int yDf, MDf, dDf, HDf, mDf, sDf; 1628 if (tfdItem.progressive) { 1629 ucal.setTimeInMillis(tfdItem.start); 1630 yDf = ucal.fieldDifference(targetDate, YEAR); 1631 MDf = ucal.fieldDifference(targetDate, MONTH); 1632 dDf = ucal.fieldDifference(targetDate, DATE); 1633 HDf = ucal.fieldDifference(targetDate, HOUR); 1634 mDf = ucal.fieldDifference(targetDate, MINUTE); 1635 sDf = ucal.fieldDifference(targetDate, SECOND); 1636 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff || sDf != tfdItem.sDiff ) { 1637 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m-s progressive diffs " + 1638 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff +","+ tfdItem.sDiff + ", got " + 1639 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf +","+ sDf); 1640 } 1641 } else { 1642 ucal.setTimeInMillis(tfdItem.start); 1643 yDf = ucal.fieldDifference(targetDate, YEAR); 1644 ucal.setTimeInMillis(tfdItem.start); 1645 MDf = ucal.fieldDifference(targetDate, MONTH); 1646 ucal.setTimeInMillis(tfdItem.start); 1647 dDf = ucal.fieldDifference(targetDate, DATE); 1648 ucal.setTimeInMillis(tfdItem.start); 1649 HDf = ucal.fieldDifference(targetDate, HOUR); 1650 ucal.setTimeInMillis(tfdItem.start); 1651 mDf = ucal.fieldDifference(targetDate, MINUTE); 1652 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff ) { 1653 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m total diffs " + 1654 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff + ", got " + 1655 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf); 1656 } 1657 ucal.setTimeInMillis(tfdItem.start); 1658 sDf = ucal.fieldDifference(targetDate, SECOND); 1659 if ( sDf != 0x7FFFFFFF && sDf != tfdItem.sDiff ) { 1660 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected seconds total diffs " + 1661 tfdItem.sDiff + ", got " + sDf); 1662 } 1663 } 1664 } 1665 } 1666 1667 @Test TestAddRollEra0AndEraBounds()1668 public void TestAddRollEra0AndEraBounds() { 1669 final String[] localeIDs = { 1670 // calendars with non-modern era 0 that goes backwards, max era == 1 1671 "en@calendar=gregorian", 1672 "en@calendar=roc", 1673 "en@calendar=coptic", 1674 // calendars with non-modern era 0 that goes forwards, max era > 1 1675 "en@calendar=japanese", 1676 "en@calendar=chinese", 1677 // calendars with non-modern era 0 that goes forwards, max era == 1 1678 "en@calendar=ethiopic", 1679 // calendars with only one era = 0, forwards 1680 "en@calendar=buddhist", 1681 "en@calendar=hebrew", 1682 "en@calendar=islamic", 1683 "en@calendar=indian", 1684 //"en@calendar=persian", // no persian calendar in ICU4J yet 1685 "en@calendar=ethiopic-amete-alem", 1686 }; 1687 TimeZone zoneGMT = TimeZone.getFrozenTimeZone("GMT"); 1688 for (String localeID : localeIDs) { 1689 Calendar ucalTest = Calendar.getInstance(zoneGMT, new ULocale(localeID)); 1690 String calType = ucalTest.getType(); 1691 boolean era0YearsGoBackwards = (calType.equals("gregorian") || calType.equals("roc") || calType.equals("coptic")); 1692 int yrBefore, yrAfter, yrMax, eraAfter, eraMax, eraNow; 1693 1694 ucalTest.clear(); 1695 ucalTest.set(Calendar.YEAR, 2); 1696 ucalTest.set(Calendar.ERA, 0); 1697 yrBefore = ucalTest.get(Calendar.YEAR); 1698 ucalTest.add(Calendar.YEAR, 1); 1699 yrAfter = ucalTest.get(Calendar.YEAR); 1700 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) { 1701 errln("Fail: era 0 add 1 year does not move forward in time for " + localeID); 1702 } 1703 1704 ucalTest.clear(); 1705 ucalTest.set(Calendar.YEAR, 2); 1706 ucalTest.set(Calendar.ERA, 0); 1707 yrBefore = ucalTest.get(Calendar.YEAR); 1708 ucalTest.roll(Calendar.YEAR, 1); 1709 yrAfter = ucalTest.get(Calendar.YEAR); 1710 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) { 1711 errln("Fail: era 0 roll 1 year does not move forward in time for " + localeID); 1712 } 1713 1714 ucalTest.clear(); 1715 ucalTest.set(Calendar.YEAR, 1); 1716 ucalTest.set(Calendar.ERA, 0); 1717 if (era0YearsGoBackwards) { 1718 ucalTest.roll(Calendar.YEAR, 1); 1719 yrAfter = ucalTest.get(Calendar.YEAR); 1720 eraAfter = ucalTest.get(Calendar.ERA); 1721 if (eraAfter != 0 || yrAfter != 1) { 1722 errln("Fail: era 0 roll 1 year from year 1 does not stay within era or pin to year 1 for " 1723 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1724 } 1725 } else { 1726 // roll backward in time to where era 0 years go negative, except for the Chinese 1727 // calendar, which uses negative eras instead of having years outside the range 1-60 1728 ucalTest.roll(Calendar.YEAR, -2); 1729 yrAfter = ucalTest.get(Calendar.YEAR); 1730 eraAfter = ucalTest.get(Calendar.ERA); 1731 if ( !calType.equals("chinese") && (eraAfter != 0 || yrAfter != -1) ) { 1732 errln("Fail: era 0 roll -2 years from year 1 does not stay within era or produce year -1 for " 1733 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1734 } 1735 } 1736 1737 ucalTest.clear(); 1738 { 1739 int eraMin = ucalTest.getMinimum(Calendar.ERA); 1740 if (eraMin != 0 && calType.compareTo("chinese") != 0) { 1741 errln("Fail: getMinimum returns minimum era " + eraMin + " (should be 0) for calType " + calType); 1742 } 1743 } 1744 1745 ucalTest.clear(); 1746 ucalTest.set(Calendar.YEAR, 1); 1747 ucalTest.set(Calendar.ERA, 0); 1748 eraMax = ucalTest.getMaximum(Calendar.ERA); 1749 if (eraMax > 0) { 1750 // try similar tests for era 1 (if calendar has it), in which years always go forward 1751 1752 ucalTest.clear(); 1753 ucalTest.set(Calendar.YEAR, 2); 1754 ucalTest.set(Calendar.ERA, 1); 1755 yrBefore = ucalTest.get(Calendar.YEAR); 1756 ucalTest.add(Calendar.YEAR, 1); 1757 yrAfter = ucalTest.get(Calendar.YEAR); 1758 if ( yrAfter<yrBefore ) { 1759 errln("Fail: era 1 add 1 year does not move forward in time for " + localeID); 1760 } 1761 1762 ucalTest.clear(); 1763 ucalTest.set(Calendar.YEAR, 2); 1764 ucalTest.set(Calendar.ERA, 1); 1765 yrBefore = ucalTest.get(Calendar.YEAR); 1766 ucalTest.roll(Calendar.YEAR, 1); 1767 yrAfter = ucalTest.get(Calendar.YEAR); 1768 if ( yrAfter<yrBefore ) { 1769 errln("Fail: era 1 roll 1 year does not move forward in time for " + localeID); 1770 } 1771 1772 ucalTest.clear(); 1773 ucalTest.set(Calendar.YEAR, 1); 1774 ucalTest.set(Calendar.ERA, 1); 1775 yrMax = ucalTest.getActualMaximum(Calendar.YEAR); 1776 ucalTest.roll(Calendar.YEAR, -1); // roll down which should pin or wrap to end 1777 yrAfter = ucalTest.get(Calendar.YEAR); 1778 eraAfter = ucalTest.get(Calendar.ERA); 1779 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1 1780 if (yrMax >= 32768) { 1781 if (eraAfter != 1 || yrAfter != 1) { 1782 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or pin to year 1 for " 1783 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1784 } 1785 } else if (eraAfter != 1 || yrAfter != yrMax) { 1786 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or wrap to year " 1787 + yrMax + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1788 } else { 1789 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning 1790 yrAfter = ucalTest.get(Calendar.YEAR); 1791 eraAfter = ucalTest.get(Calendar.ERA); 1792 if (eraAfter != 1 || yrAfter != 1) { 1793 errln("Fail: era 1 roll 1 year from year " + yrMax + 1794 " does not stay within era or wrap to year 1 for " 1795 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1796 } 1797 } 1798 1799 // if current era > 1, try the same roll tests for current era 1800 ucalTest.setTime(new Date()); 1801 eraNow = ucalTest.get(Calendar.ERA); 1802 if (eraNow > 1) { 1803 ucalTest.clear(); 1804 ucalTest.set(Calendar.YEAR, 1); 1805 ucalTest.set(Calendar.ERA, eraNow); 1806 yrMax = ucalTest.getActualMaximum(Calendar.YEAR); // max year value for this era 1807 ucalTest.roll(Calendar.YEAR, -1); 1808 yrAfter = ucalTest.get(Calendar.YEAR); 1809 eraAfter = ucalTest.get(Calendar.ERA); 1810 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1 1811 if (yrMax >= 32768) { 1812 if (eraAfter != eraNow || yrAfter != 1) { 1813 errln("Fail: era " + eraNow + 1814 " roll -1 year from year 1 does not stay within era or pin to year 1 for " 1815 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1816 } 1817 } else if (eraAfter != eraNow || yrAfter != yrMax) { 1818 errln("Fail: era " + eraNow + 1819 " roll -1 year from year 1 does not stay within era or wrap to year " + yrMax 1820 + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1821 } else { 1822 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning 1823 yrAfter = ucalTest.get(Calendar.YEAR); 1824 eraAfter = ucalTest.get(Calendar.ERA); 1825 if (eraAfter != eraNow || yrAfter != 1) { 1826 errln("Fail: era " + eraNow + " roll 1 year from year " + yrMax + 1827 " does not stay within era or wrap to year 1 for " 1828 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")"); 1829 } 1830 } 1831 } 1832 } 1833 } 1834 } 1835 1836 @Test TestWeekData()1837 public void TestWeekData() { 1838 // Each line contains two locales using the same set of week rule data. 1839 final String LOCALE_PAIRS[] = { 1840 "en", "en_US", 1841 "de", "de_DE", 1842 "de_DE", "en_DE", 1843 "en_GB", "und_GB", 1844 "ar_EG", "en_EG", 1845 "ar_SA", "fr_SA", 1846 }; 1847 1848 for (int i = 0; i < LOCALE_PAIRS.length; i += 2) { 1849 Calendar cal1 = Calendar.getInstance(new ULocale(LOCALE_PAIRS[i])); 1850 Calendar cal2 = Calendar.getInstance(new ULocale(LOCALE_PAIRS[i + 1])); 1851 1852 // First day of week 1853 int dow1 = cal1.getFirstDayOfWeek(); 1854 int dow2 = cal2.getFirstDayOfWeek(); 1855 if (dow1 != dow2) { 1856 errln("getFirstDayOfWeek: " + LOCALE_PAIRS[i] + "->" + dow1 + ", " + LOCALE_PAIRS[i + 1] + "->" + dow2); 1857 } 1858 1859 // Minimum days in first week 1860 int minDays1 = cal1.getMinimalDaysInFirstWeek(); 1861 int minDays2 = cal2.getMinimalDaysInFirstWeek(); 1862 if (minDays1 != minDays2) { 1863 errln("getMinimalDaysInFirstWeek: " + LOCALE_PAIRS[i] + "->" + minDays1 + ", " + LOCALE_PAIRS[i + 1] + "->" + minDays2); 1864 } 1865 1866 // Weekdays and Weekends 1867 for (int d = Calendar.SUNDAY; d <= Calendar.SATURDAY; d++) { 1868 int wdt1 = cal1.getDayOfWeekType(d); 1869 int wdt2 = cal2.getDayOfWeekType(d); 1870 if (wdt1 != wdt2) { 1871 errln("getDayOfWeekType(" + d + "): " + LOCALE_PAIRS[i] + "->" + wdt1 + ", " + LOCALE_PAIRS[i + 1] + "->" + wdt2); 1872 } 1873 } 1874 } 1875 } 1876 1877 @Test TestAddAcrossZoneTransition()1878 public void TestAddAcrossZoneTransition() { 1879 class TestData { 1880 String zone; 1881 CalFields base; 1882 int deltaDays; 1883 int skippedWTOpt; 1884 CalFields expected; 1885 1886 TestData(String zone, CalFields base, int deltaDays, int skippedWTOpt, CalFields expected) { 1887 this.zone = zone; 1888 this.base = base; 1889 this.deltaDays = deltaDays; 1890 this.skippedWTOpt = skippedWTOpt; 1891 this.expected = expected; 1892 } 1893 } 1894 1895 TestData[] data = new TestData[] { 1896 // Add 1 day, from the date before DST transition 1897 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_FIRST, 1898 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1899 1900 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_LAST, 1901 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1902 1903 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 1, 59, 59, 999), 1, Calendar.WALLTIME_NEXT_VALID, 1904 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1905 1906 1907 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 1908 new CalFields(2014, 3, 9, 1, 0, 0, 0)), 1909 1910 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 1911 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1912 1913 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1914 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1915 1916 1917 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_FIRST, 1918 new CalFields(2014, 3, 9, 1, 30, 0, 0)), 1919 1920 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_LAST, 1921 new CalFields(2014, 3, 9, 3, 30, 0, 0)), 1922 1923 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 2, 30, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1924 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1925 1926 1927 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 1928 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1929 1930 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 1931 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1932 1933 new TestData("America/Los_Angeles", new CalFields(2014, 3, 8, 3, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 1934 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1935 1936 1937 // Subtract 1 day, from one day after DST transition 1938 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_FIRST, 1939 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1940 1941 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_LAST, 1942 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1943 1944 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 1, 59, 59, 999), -1, Calendar.WALLTIME_NEXT_VALID, 1945 new CalFields(2014, 3, 9, 1, 59, 59, 999)), 1946 1947 1948 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 1949 new CalFields(2014, 3, 9, 1, 0, 0, 0)), 1950 1951 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 1952 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1953 1954 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1955 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1956 1957 1958 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_FIRST, 1959 new CalFields(2014, 3, 9, 1, 30, 0, 0)), 1960 1961 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_LAST, 1962 new CalFields(2014, 3, 9, 3, 30, 0, 0)), 1963 1964 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 2, 30, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1965 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1966 1967 1968 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 1969 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1970 1971 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 1972 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1973 1974 new TestData("America/Los_Angeles", new CalFields(2014, 3, 10, 3, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 1975 new CalFields(2014, 3, 9, 3, 0, 0, 0)), 1976 1977 1978 // Test case for ticket#10544 1979 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_FIRST, 1980 new CalFields(2013, 9, 7, 23, 0, 0, 0)), 1981 1982 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_LAST, 1983 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1984 1985 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 0, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID, 1986 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1987 1988 1989 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_FIRST, 1990 new CalFields(2013, 9, 7, 23, 30, 0, 0)), 1991 1992 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_LAST, 1993 new CalFields(2013, 9, 8, 1, 30, 0, 0)), 1994 1995 new TestData("America/Santiago", new CalFields(2013, 4, 27, 0, 30, 0, 0), 134, Calendar.WALLTIME_NEXT_VALID, 1996 new CalFields(2013, 9, 8, 1, 0, 0, 0)), 1997 1998 1999 // Extreme transition - Pacific/Apia completely skips 2011-12-30 2000 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_FIRST, 2001 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 2002 2003 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_LAST, 2004 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 2005 2006 new TestData("Pacific/Apia", new CalFields(2011, 12, 29, 0, 0, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 2007 new CalFields(2011, 12, 31, 0, 0, 0, 0)), 2008 2009 2010 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_FIRST, 2011 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 2012 2013 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_LAST, 2014 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 2015 2016 new TestData("Pacific/Apia", new CalFields(2011, 12, 31, 12, 0, 0, 0), -1, Calendar.WALLTIME_NEXT_VALID, 2017 new CalFields(2011, 12, 29, 12, 0, 0, 0)), 2018 2019 2020 // 30 minutes DST - Australia/Lord_Howe 2021 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_FIRST, 2022 new CalFields(2013, 10, 6, 1, 45, 0, 0)), 2023 2024 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_LAST, 2025 new CalFields(2013, 10, 6, 2, 45, 0, 0)), 2026 2027 new TestData("Australia/Lord_Howe", new CalFields(2013, 10, 5, 2, 15, 0, 0), 1, Calendar.WALLTIME_NEXT_VALID, 2028 new CalFields(2013, 10, 6, 2, 30, 0, 0)), 2029 }; 2030 2031 Calendar cal = Calendar.getInstance(); 2032 for (TestData d : data) { 2033 cal.setTimeZone(TimeZone.getTimeZone(d.zone)); 2034 cal.setSkippedWallTimeOption(d.skippedWTOpt); 2035 d.base.setTo(cal); 2036 cal.add(Calendar.DATE, d.deltaDays); 2037 2038 if (!d.expected.isEquivalentTo(cal)) { 2039 CalFields res = CalFields.createFrom(cal); 2040 String optDisp = d.skippedWTOpt == Calendar.WALLTIME_FIRST ? "FIRST" : 2041 d.skippedWTOpt == Calendar.WALLTIME_LAST ? "LAST" : "NEXT_VALID"; 2042 errln("Error: base:" + d.base.toString() + ", tz:" + d.zone 2043 + ", delta:" + d.deltaDays + " day(s), opt:" + optDisp 2044 + ", result:" + res.toString() + " - expected:" + d.expected.toString()); 2045 } 2046 } 2047 } 2048 2049 @Test TestSimpleDateFormatCoverage()2050 public void TestSimpleDateFormatCoverage() { 2051 2052 class StubSimpleDateFormat extends SimpleDateFormat { 2053 private static final long serialVersionUID = 1L; 2054 2055 public StubSimpleDateFormat(String pattern, Locale loc) { 2056 new SimpleDateFormat(pattern, loc); 2057 } 2058 2059 public void run(){ 2060 Calendar cal = Calendar.getInstance(Locale.US); 2061 cal.clear(); 2062 cal.set(2000, Calendar.MARCH, 18, 15, 0, 1); // Sat 15:00 2063 2064 DateFormatSymbols theseSymbols = this.getSymbols(); 2065 String shouldBeMonday = theseSymbols.getWeekdays()[Calendar.MONDAY]; 2066 assertEquals("Should be Monday", "Monday", shouldBeMonday); 2067 2068 String [] matchData = {"16", "2016", "2016AD", "Monday", "lunes"}; 2069 int matchIndex = matchString("Monday March 28, 2016", 0, Calendar.DAY_OF_WEEK, matchData, cal); 2070 assertEquals("matchData for Monday", 6, matchIndex); // Position of the pointer after the matched string. 2071 matchIndex = matchString("Monday March 28, 2016 AD", 17, Calendar.YEAR, matchData, cal); 2072 assertEquals("matchData for 2016", 21, matchIndex); // Position of the pointer after the matched string. 2073 2074 char ch = 'y'; 2075 int count = 4; 2076 int beginOffset = 0; 2077 cal.set(Calendar.YEAR, 2000); // Reset this 2078 assertEquals("calendar year reset", 2000, cal.get(Calendar.YEAR)); 2079 FieldPosition pos = new FieldPosition(java.text.DateFormat.YEAR_FIELD); 2080 String subFormatResult = subFormat(ch, count, beginOffset, 2081 pos, theseSymbols, cal); 2082 assertEquals("subFormat result", "2000", subFormatResult); 2083 2084 String testParseString = "some text with a date 2017-03-15"; 2085 int start = 22; 2086 boolean obeyCount = true; 2087 boolean allowNegative = false; 2088 boolean ambiguousYear[] = {true, false, true}; 2089 int subParseResult = subParse(testParseString, start, ch, count, 2090 obeyCount, allowNegative, ambiguousYear, cal); 2091 assertEquals("subParseResult result", 26, subParseResult); 2092 assertEquals("parsed year", 2017, cal.get(Calendar.YEAR)); 2093 } 2094 } 2095 StubSimpleDateFormat stub = new StubSimpleDateFormat("EEE MMM dd yyyy G HH:mm:ss.SSS", Locale.US); 2096 stub.run(); 2097 } 2098 2099 @Test TestConsistencyGregorian()2100 public void TestConsistencyGregorian() { 2101 checkConsistency("en@calendar=gregorian"); 2102 } 2103 2104 @Test TestConsistencyIndian()2105 public void TestConsistencyIndian() { 2106 checkConsistency("en@calendar=indian"); 2107 } 2108 2109 @Test TestConsistencyHebrew()2110 public void TestConsistencyHebrew() { 2111 checkConsistency("en@calendar=hebrew"); 2112 } 2113 2114 @Test TestConsistencyIslamic()2115 public void TestConsistencyIslamic() { 2116 checkConsistency("en@calendar=islamic"); 2117 } 2118 2119 @Test TestConsistencyIslamicRGSA()2120 public void TestConsistencyIslamicRGSA() { 2121 checkConsistency("en@calendar=islamic-rgsa"); 2122 } 2123 2124 @Test TestConsistencyIslamicTBLA()2125 public void TestConsistencyIslamicTBLA() { 2126 checkConsistency("en@calendar=islamic-tbla"); 2127 } 2128 2129 @Test TestConsistencyIslamicUmalqura()2130 public void TestConsistencyIslamicUmalqura() { 2131 checkConsistency("en@calendar=islamic-umalqura"); 2132 } 2133 2134 @Test TestConsistencyIslamicCivil()2135 public void TestConsistencyIslamicCivil() { 2136 checkConsistency("en@calendar=islamic-civil"); 2137 } 2138 2139 @Test TestConsistencyCoptic()2140 public void TestConsistencyCoptic() { 2141 checkConsistency("en@calendar=coptic"); 2142 } 2143 2144 @Test TestConsistencyEthiopic()2145 public void TestConsistencyEthiopic() { 2146 checkConsistency("en@calendar=ethiopic"); 2147 } 2148 2149 @Test TestConsistencyROC()2150 public void TestConsistencyROC() { 2151 checkConsistency("en@calendar=roc"); 2152 } 2153 2154 @Test TestConsistencyChinese()2155 public void TestConsistencyChinese() { 2156 checkConsistency("en@calendar=chinese"); 2157 } 2158 2159 @Test TestConsistencyDangi()2160 public void TestConsistencyDangi() { 2161 checkConsistency("en@calendar=dangi"); 2162 } 2163 2164 @Test TestConsistencyPersian()2165 public void TestConsistencyPersian() { 2166 checkConsistency("en@calendar=persian"); 2167 } 2168 2169 @Test TestConsistencyBuddhist()2170 public void TestConsistencyBuddhist() { 2171 checkConsistency("en@calendar=buddhist"); 2172 } 2173 2174 @Test TestConsistencyJapanese()2175 public void TestConsistencyJapanese() { 2176 checkConsistency("en@calendar=japanese"); 2177 } 2178 2179 @Test TestConsistencyEthiopicAmeteAlem()2180 public void TestConsistencyEthiopicAmeteAlem() { 2181 checkConsistency("en@calendar=ethiopic-amete-alem"); 2182 } 2183 checkConsistency(String locale)2184 public void checkConsistency(String locale) { 2185 boolean quick = getExhaustiveness() <= 5; 2186 // Check 3 years in quick mode and 6000 years in exhaustive mode. 2187 int numOfDaysToTest = (quick ? 3 * 365 : 6000 * 365); 2188 int msInADay = 1000*60*60*24; 2189 2190 // g is just for debugging messages. 2191 Calendar g = new GregorianCalendar(TimeZone.GMT_ZONE, ULocale.ENGLISH); 2192 Calendar base = Calendar.getInstance(TimeZone.GMT_ZONE, new ULocale(locale)); 2193 Date test = Calendar.getInstance().getTime(); 2194 2195 Calendar r = (Calendar)base.clone(); 2196 int lastDay = 1; 2197 String type = base.getType(); 2198 boolean ignoreOrdinaryMonth12Bug = (!quick) && (type.equals("chinese") || type.equals("dangi")); 2199 for (int j = 0; j < numOfDaysToTest; j++, test.setTime(test.getTime() - msInADay)) { 2200 g.setTime(test); 2201 base.clear(); 2202 base.setTime(test); 2203 // First, we verify the date from base is decrease one day from the 2204 // last day unless the last day is 1. 2205 int cday = base.get(Calendar.DAY_OF_MONTH); 2206 if (lastDay == 1) { 2207 lastDay = cday; 2208 } else { 2209 if (cday != lastDay-1) { 2210 // Ignore if it is the last day before Gregorian Calendar switch on 2211 // 1582 Oct 4 2212 if ( g.get(Calendar.YEAR) == 1582 && (g.get(Calendar.MONTH) + 1) == 10 && 2213 g.get(Calendar.DAY_OF_MONTH) == 4) { 2214 lastDay = 5; 2215 } else { 2216 errln("Day is not one less from previous date for Gregorian(e=" + 2217 g.get(Calendar.ERA) + " " + g.get(Calendar.YEAR) + "/" + 2218 (g.get(Calendar.MONTH) + 1) + "/" + g.get(Calendar.DAY_OF_MONTH) + 2219 ") " + locale + "(" + 2220 base.get(Calendar.ERA) + " " + base.get(Calendar.YEAR) + "/" + 2221 (base.get(Calendar.MONTH) + 1 ) + "/" + base.get(Calendar.DAY_OF_MONTH) + 2222 ")"); 2223 } 2224 } 2225 lastDay--; 2226 } 2227 // Second, we verify the month is in reasonale range. 2228 int cmonth = base.get(Calendar.MONTH); 2229 if (cmonth < 0 || cmonth > 13) { 2230 errln("Month is out of range Gregorian(e=" + g.get(Calendar.ERA) + " " + 2231 g.get(Calendar.YEAR) + "/" + (g.get(Calendar.MONTH) + 1) + "/" + 2232 g.get(Calendar.DAY_OF_MONTH) + ") " + locale + "(" + base.get(Calendar.ERA) + 2233 " " + base.get(Calendar.YEAR) + "/" + (base.get(Calendar.MONTH) + 1 ) + "/" + 2234 base.get(Calendar.DAY_OF_MONTH) + ")"); 2235 } 2236 // Third, we verify the set function can round trip the time back. 2237 r.clear(); 2238 for (int f = 0; f < base.getFieldCount(); f++) { 2239 r.set(f, base.get(f)); 2240 } 2241 Date result = r.getTime(); 2242 if (!test.equals(result)) { 2243 if (ignoreOrdinaryMonth12Bug && base.get(Calendar.ORDINAL_MONTH) == 12) { 2244 logKnownIssue("ICU-22230", "Problem December in Leap Year"); 2245 continue; 2246 } 2247 int year = base.get(Calendar.YEAR); 2248 int month = base.get(Calendar.MONTH) + 1; 2249 int date = base.get(Calendar.DATE); 2250 2251 errln("Round trip conversion produces different time from " + test + " to " + 2252 result + " delta: " + (result.getTime() - test.getTime()) + 2253 " Gregorian(e=" + g.get(Calendar.ERA) + " " + g.get(Calendar.YEAR) + "/" + 2254 (g.get(Calendar.MONTH) + 1) + "/" + g.get(Calendar.DAY_OF_MONTH) + ") "); 2255 } 2256 } 2257 } 2258 2259 @Test TestBug21043Indian()2260 public void TestBug21043Indian() { 2261 Calendar cal = new IndianCalendar(ULocale.ENGLISH); 2262 Calendar g = new GregorianCalendar(ULocale.ENGLISH); 2263 // set to 10 BC 2264 g.set(Calendar.ERA, GregorianCalendar.BC); 2265 g.set(10, 1, 1); 2266 cal.setTime(g.getTime()); 2267 int m = cal.get(Calendar.MONTH); 2268 if (m < 0 || m > 11) { 2269 errln("Month (" + m + ") should be between 0 and 11 in India calendar"); 2270 } 2271 } 2272 2273 @Test TestBug21044Hebrew()2274 public void TestBug21044Hebrew() { 2275 Calendar cal = new HebrewCalendar(ULocale.ENGLISH); 2276 Calendar g = new GregorianCalendar(ULocale.ENGLISH); 2277 // set to 3771/10/27 BC which is before 3760 BC. 2278 g.set(Calendar.ERA, GregorianCalendar.BC); 2279 g.set(3771, 9, 27); 2280 cal.setTime(g.getTime()); 2281 int y = cal.get(Calendar.YEAR); 2282 int m = cal.get(Calendar.MONTH); 2283 int d = cal.get(Calendar.DATE); 2284 if (y > 0 || m < 0 || m > 12 || d < 0 || d > 32) { 2285 errln("Out of rage!\nYear " + y + " should be " + 2286 "negative number before 1AD.\nMonth " + m + " should " + 2287 "be between 0 and 12 in Hebrew calendar.\nDate " + d + 2288 " should be between 0 and 32 in Islamic calendar."); 2289 } 2290 } 2291 2292 @Test TestBug21045Islamic()2293 public void TestBug21045Islamic() { 2294 Calendar cal = new IslamicCalendar(ULocale.ENGLISH); 2295 Calendar g = new GregorianCalendar(ULocale.ENGLISH); 2296 // set to 500 AD before 622 AD. 2297 g.set(Calendar.ERA, GregorianCalendar.AD); 2298 g.set(500, 1, 1); 2299 cal.setTime(g.getTime()); 2300 int m = cal.get(Calendar.MONTH); 2301 if (m < 0 || m > 11) { 2302 errln("Month (" + m + ") should be between 0 and 11 in Islamic calendar"); 2303 } 2304 } 2305 2306 @Test TestBug21046IslamicUmalqura()2307 public void TestBug21046IslamicUmalqura() { 2308 IslamicCalendar cal = new IslamicCalendar(ULocale.ENGLISH); 2309 cal.setCalculationType(IslamicCalendar.CalculationType.ISLAMIC_UMALQURA); 2310 Calendar g = new GregorianCalendar(ULocale.ENGLISH); 2311 // set to 195366 BC 2312 g.set(Calendar.ERA, GregorianCalendar.BC); 2313 g.set(195366, 1, 1); 2314 cal.setTime(g.getTime()); 2315 int y = cal.get(Calendar.YEAR); 2316 int m = cal.get(Calendar.MONTH); 2317 int d = cal.get(Calendar.DATE); 2318 if (y > 0 || m < 0 || m > 11 || d < 0 || d > 32) { 2319 errln("Out of rage!\nYear " + y + " should be " + 2320 "negative number before 1AD.\nMonth " + m + " should " + 2321 "be between 0 and 11 in Islamic calendar.\nDate " + d + 2322 " should be between 0 and 32 in Islamic calendar."); 2323 } 2324 } 2325 } 2326