1 /* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.text.*; 25 import java.util.*; 26 import java.io.*; 27 28 /** 29 * @test 30 * @bug 4029195 4052408 4056591 4059917 4060212 4061287 4065240 4071441 4073003 31 * 4089106 4100302 4101483 4103340 4103341 4104136 4104522 4106807 4108407 32 * 4134203 4138203 4148168 4151631 4151706 4153860 4162071 4182066 4209272 4210209 33 * 4213086 4250359 4253490 4266432 4406615 4413980 8008577 34 * @library /java/text/testlib 35 * @run main/othervm -Djava.locale.providers=COMPAT,SPI DateFormatRegression 36 */ 37 public class DateFormatRegression extends IntlTest { 38 39 public static void main(String[] args) throws Exception { 40 new DateFormatRegression().run(args); 41 } 42 43 public void Test4029195() { 44 45 Date today = new Date(); 46 47 logln("today: " + today); 48 49 SimpleDateFormat sdf = (SimpleDateFormat)SimpleDateFormat.getDateInstance(); 50 logln("pattern: " + sdf.toPattern()); 51 logln("today: " + sdf.format(today)); 52 53 sdf.applyPattern("G yyyy DDD"); 54 String todayS = sdf.format(today); 55 logln("today: " + todayS); 56 try { 57 today = sdf.parse(todayS); 58 logln("today date: " + today); 59 } catch(Exception e) { 60 logln("Error reparsing date: " + e.getMessage()); 61 } 62 63 try { 64 String rt = sdf.format(sdf.parse(todayS)); 65 logln("round trip: " + rt); 66 if (!rt.equals(todayS)) errln("Fail: Want " + todayS + " Got " + rt); 67 } 68 catch (ParseException e) { 69 errln("Fail: " + e); 70 e.printStackTrace(); 71 } 72 } 73 74 public void Test4052408() { 75 DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, 76 DateFormat.SHORT, Locale.US); 77 Date date = new Date(97, Calendar.MAY, 3, 8, 55); 78 String str; 79 logln(str = fmt.format(date)); 80 81 if (!str.equals("5/3/97 8:55 AM")) 82 errln("Fail: Test broken; Want 5/3/97 8:55 AM Got " + str); 83 Hashtable expected = new Hashtable(); 84 expected.put(new Integer(DateFormat.MONTH_FIELD), "5"); 85 expected.put(new Integer(DateFormat.DATE_FIELD), "3"); 86 expected.put(new Integer(DateFormat.YEAR_FIELD), "97"); 87 expected.put(new Integer(DateFormat.HOUR1_FIELD), "8"); 88 expected.put(new Integer(DateFormat.MINUTE_FIELD), "55"); 89 expected.put(new Integer(DateFormat.AM_PM_FIELD), "AM"); 90 91 StringBuffer buf = new StringBuffer(); 92 String fieldNames[] = { 93 "ERA_FIELD", 94 "YEAR_FIELD", 95 "MONTH_FIELD", 96 "DATE_FIELD", 97 "HOUR_OF_DAY1_FIELD", 98 "HOUR_OF_DAY0_FIELD", 99 "MINUTE_FIELD", 100 "SECOND_FIELD", 101 "MILLISECOND_FIELD", 102 "DAY_OF_WEEK_FIELD", 103 "DAY_OF_YEAR_FIELD", 104 "DAY_OF_WEEK_IN_MONTH_FIELD", 105 "WEEK_OF_YEAR_FIELD", 106 "WEEK_OF_MONTH_FIELD", 107 "AM_PM_FIELD", 108 "HOUR1_FIELD", 109 "HOUR0_FIELD", 110 "TIMEZONE_FIELD", 111 }; 112 boolean pass = true; 113 for (int i=0; i<=17; ++i) { 114 FieldPosition pos = new FieldPosition(i); 115 fmt.format(date, buf, pos); 116 char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()]; 117 buf.getChars(pos.getBeginIndex(), pos.getEndIndex(), dst, 0); 118 str = new String(dst); 119 log(i + ": " + fieldNames[i] + 120 ", \"" + str + "\", " + 121 pos.getBeginIndex() + ", " + 122 pos.getEndIndex()); 123 String exp = (String) expected.get(new Integer(i)); 124 if ((exp == null && str.length() == 0) || 125 str.equals(exp)) 126 logln(" ok"); 127 else { 128 logln(" expected " + exp); 129 pass = false; 130 } 131 } 132 if (!pass) errln("Fail: FieldPosition not set right by DateFormat"); 133 } 134 135 /** 136 * Verify the function of the [s|g]et2DigitYearStart() API. 137 */ 138 public void Test4056591() { 139 try { 140 SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd", Locale.US); 141 Date start = new Date(1809-1900, Calendar.DECEMBER, 25); 142 fmt.set2DigitYearStart(start); 143 if (!fmt.get2DigitYearStart().equals(start)) 144 errln("get2DigitYearStart broken"); 145 Object[] DATA = { 146 "091225", new Date(1809-1900, Calendar.DECEMBER, 25), 147 "091224", new Date(1909-1900, Calendar.DECEMBER, 24), 148 "091226", new Date(1809-1900, Calendar.DECEMBER, 26), 149 "611225", new Date(1861-1900, Calendar.DECEMBER, 25), 150 }; 151 for (int i=0; i<DATA.length; i+=2) { 152 String s = (String) DATA[i]; 153 Date exp = (Date) DATA[i+1]; 154 Date got = fmt.parse(s); 155 logln(s + " -> " + got + "; exp " + exp); 156 if (!got.equals(exp)) errln("set2DigitYearStart broken"); 157 } 158 } 159 catch (ParseException e) { 160 errln("Fail: " + e); 161 e.printStackTrace(); 162 } 163 } 164 165 public void Test4059917() { 166 Locale locale = Locale.getDefault(); 167 if (!TestUtils.usesAsciiDigits(locale)) { 168 logln("Skipping this test because locale is " + locale); 169 return; 170 } 171 172 SimpleDateFormat fmt; 173 String myDate; 174 175 fmt = new SimpleDateFormat( "yyyy/MM/dd" ); 176 myDate = "1997/01/01"; 177 aux917( fmt, myDate ); 178 179 fmt = new SimpleDateFormat( "yyyyMMdd" ); 180 myDate = "19970101"; 181 aux917( fmt, myDate ); 182 } 183 184 void aux917( SimpleDateFormat fmt, String str ) { 185 try { 186 logln( "==================" ); 187 logln( "testIt: pattern=" + fmt.toPattern() + 188 " string=" + str ); 189 190 Object o; 191 o = fmt.parseObject( str ); 192 logln( "Parsed object: " + o ); 193 194 String formatted = fmt.format( o ); 195 logln( "Formatted string: " + formatted ); 196 if (!formatted.equals(str)) errln("Fail: Want " + str + " Got " + formatted); 197 } 198 catch (ParseException e) { 199 errln("Fail: " + e); 200 e.printStackTrace(); 201 } 202 } 203 204 public void Test4060212() { 205 Locale savedLocale = Locale.getDefault(); 206 Locale.setDefault(Locale.US); 207 try { 208 String dateString = "1995-040.05:01:29"; 209 210 logln( "dateString= " + dateString ); 211 logln("Using yyyy-DDD.hh:mm:ss"); 212 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-DDD.hh:mm:ss"); 213 ParsePosition pos = new ParsePosition(0); 214 Date myDate = formatter.parse( dateString, pos ); 215 String myString = DateFormat.getDateTimeInstance( DateFormat.FULL, 216 DateFormat.LONG).format( myDate ); 217 logln( myString ); 218 Calendar cal = new GregorianCalendar(); 219 cal.setTime(myDate); 220 if (cal.get(Calendar.DAY_OF_YEAR) != 40) 221 errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + 222 " Want 40"); 223 224 logln("Using yyyy-ddd.hh:mm:ss"); 225 formatter = new SimpleDateFormat("yyyy-ddd.hh:mm:ss"); 226 pos = new ParsePosition(0); 227 myDate = formatter.parse( dateString, pos ); 228 myString = DateFormat.getDateTimeInstance( DateFormat.FULL, 229 DateFormat.LONG).format( myDate ); 230 logln( myString ); 231 cal.setTime(myDate); 232 if (cal.get(Calendar.DAY_OF_YEAR) != 40) 233 errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + 234 " Want 40"); 235 } 236 finally { 237 Locale.setDefault(savedLocale); 238 } 239 } 240 241 public void Test4061287() { 242 SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy"); 243 try { 244 logln(df.parse("35/01/1971").toString()); 245 } 246 catch (ParseException e) { 247 errln("Fail: " + e); 248 e.printStackTrace(); 249 } 250 df.setLenient(false); 251 boolean ok = false; 252 try { 253 logln(df.parse("35/01/1971").toString()); 254 } catch (ParseException e) {ok=true;} 255 if (!ok) errln("Fail: Lenient not working"); 256 } 257 258 public void Test4065240() { 259 Date curDate; 260 DateFormat shortdate, fulldate; 261 String strShortDate, strFullDate; 262 Locale saveLocale = Locale.getDefault(); 263 TimeZone saveZone = TimeZone.getDefault(); 264 try { 265 Locale curLocale = new Locale("de","DE"); 266 Locale.setDefault(curLocale); 267 TimeZone.setDefault(TimeZone.getTimeZone("EST")); 268 curDate = new Date(98, 0, 1); 269 shortdate = DateFormat.getDateInstance(DateFormat.SHORT); 270 fulldate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG 271 ); 272 strShortDate = new String("The current date (short form) is " + shortdate. 273 format(curDate)); 274 strFullDate = new String("The current date (long form) is " + fulldate.format(curDate)); 275 276 logln(strShortDate); 277 logln(strFullDate); 278 279 // UPDATE THIS AS ZONE NAME RESOURCE FOR <EST> in de_DE is updated 280 if (!strFullDate.endsWith("EST") 281 && !strFullDate.endsWith("GMT-05:00")) { 282 errln("Fail: Want GMT-05:00"); 283 } 284 } 285 finally { 286 Locale.setDefault(saveLocale); 287 TimeZone.setDefault(saveZone); 288 } 289 } 290 291 /* 292 DateFormat.equals is too narrowly defined. As a result, MessageFormat 293 does not work correctly. DateFormat.equals needs to be written so 294 that the Calendar sub-object is not compared using Calendar.equals, 295 but rather compared for equivalency. This may necessitate adding a 296 (package private) method to Calendar to test for equivalency. 297 298 Currently this bug breaks MessageFormat.toPattern 299 */ 300 public void Test4071441() { 301 DateFormat fmtA = DateFormat.getInstance(); 302 DateFormat fmtB = DateFormat.getInstance(); 303 Calendar calA = fmtA.getCalendar(); 304 Calendar calB = fmtB.getCalendar(); 305 Date epoch = new Date(0); 306 Date xmas = new Date(61, Calendar.DECEMBER, 25); 307 calA.setTime(epoch); 308 calB.setTime(epoch); 309 if (!calA.equals(calB)) 310 errln("Fail: Can't complete test; Calendar instances unequal"); 311 if (!fmtA.equals(fmtB)) 312 errln("Fail: DateFormat unequal when Calendars equal"); 313 calB.setTime(xmas); 314 if (calA.equals(calB)) 315 errln("Fail: Can't complete test; Calendar instances equal"); 316 if (!fmtA.equals(fmtB)) 317 errln("Fail: DateFormat unequal when Calendars equivalent"); 318 logln("DateFormat.equals ok"); 319 } 320 321 /* The java.text.DateFormat.parse(String) method expects for the 322 US locale a string formatted according to mm/dd/yy and parses it 323 correctly. 324 325 When given a string mm/dd/yyyy it only parses up to the first 326 two y's, typically resulting in a date in the year 1919. 327 328 Please extend the parsing method(s) to handle strings with 329 four-digit year values (probably also applicable to various 330 other locales. */ 331 public void Test4073003() { 332 try { 333 DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US); 334 String[] tests = { "12/25/61", "12/25/1961", "4/3/2010", "4/3/10" }; 335 for (int i=0; i<tests.length; i+=2) { 336 Date d = fmt.parse(tests[i]); 337 Date dd = fmt.parse(tests[i+1]); 338 String s = fmt.format(d); 339 String ss = fmt.format(dd); 340 if (!d.equals(dd)) 341 errln("Fail: " + d + " != " + dd); 342 if (!s.equals(ss)) 343 errln("Fail: " + s + " != " + ss); 344 logln("Ok: " + s + " " + d); 345 } 346 } 347 catch (ParseException e) { 348 errln("Fail: " + e); 349 e.printStackTrace(); 350 } 351 } 352 353 public void Test4089106() { 354 TimeZone def = TimeZone.getDefault(); 355 try { 356 TimeZone z = new SimpleTimeZone((int)(1.25 * 3600000), "FAKEZONE"); 357 TimeZone.setDefault(z); 358 SimpleDateFormat f = new SimpleDateFormat(); 359 if (!f.getTimeZone().equals(z)) 360 errln("Fail: SimpleTimeZone should use TimeZone.getDefault()"); 361 } 362 finally { 363 TimeZone.setDefault(def); 364 } 365 } 366 367 public void Test4100302() { 368 Locale[] locales = new Locale[] { 369 Locale.CANADA, 370 Locale.CANADA_FRENCH, 371 Locale.CHINA, 372 Locale.CHINESE, 373 Locale.ENGLISH, 374 Locale.FRANCE, 375 Locale.FRENCH, 376 Locale.GERMAN, 377 Locale.GERMANY, 378 Locale.ITALIAN, 379 Locale.ITALY, 380 Locale.JAPAN, 381 Locale.JAPANESE, 382 Locale.KOREA, 383 Locale.KOREAN, 384 Locale.PRC, 385 Locale.SIMPLIFIED_CHINESE, 386 Locale.TAIWAN, 387 Locale.TRADITIONAL_CHINESE, 388 Locale.UK, 389 Locale.US 390 }; 391 try { 392 boolean pass = true; 393 for(int i = 0; i < locales.length; i++) { 394 395 Format format = DateFormat.getDateTimeInstance(DateFormat.FULL, 396 DateFormat.FULL, locales[i]); 397 byte[] bytes; 398 399 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 400 ObjectOutputStream oos = new ObjectOutputStream(baos); 401 402 oos.writeObject(format); 403 oos.flush(); 404 405 baos.close(); 406 bytes = baos.toByteArray(); 407 408 ObjectInputStream ois = 409 new ObjectInputStream(new ByteArrayInputStream(bytes)); 410 411 if (!format.equals(ois.readObject())) { 412 pass = false; 413 logln("DateFormat instance for locale " + 414 locales[i] + " is incorrectly serialized/deserialized."); 415 } else { 416 logln("DateFormat instance for locale " + 417 locales[i] + " is OKAY."); 418 } 419 } 420 if (!pass) errln("Fail: DateFormat serialization/equality bug"); 421 } 422 catch (IOException e) { 423 errln("Fail: " + e); 424 e.printStackTrace(); 425 } 426 catch (ClassNotFoundException e) { 427 errln("Fail: " + e); 428 e.printStackTrace(); 429 } 430 } 431 432 /** 433 * Test whether DataFormat can be serialized/deserialized correctly 434 * even if invalid/customized TimeZone is used. 435 */ 436 public void Test4413980() { 437 TimeZone savedTimeZone = TimeZone.getDefault(); 438 try { 439 boolean pass = true; 440 String[] IDs = new String[] {"Undefined", "PST", "US/Pacific", 441 "GMT+3:00", "GMT-01:30"}; 442 for (int i = 0; i < IDs.length; i++) { 443 TimeZone tz = TimeZone.getTimeZone(IDs[i]); 444 TimeZone.setDefault(tz); 445 446 Format format = DateFormat.getDateTimeInstance(DateFormat.FULL, 447 DateFormat.FULL); 448 byte[] bytes; 449 450 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 451 ObjectOutputStream oos = new ObjectOutputStream(baos); 452 453 oos.writeObject(format); 454 oos.flush(); 455 456 baos.close(); 457 bytes = baos.toByteArray(); 458 459 ObjectInputStream ois = 460 new ObjectInputStream(new ByteArrayInputStream(bytes)); 461 462 if (!format.equals(ois.readObject())) { 463 pass = false; 464 logln("DateFormat instance which uses TimeZone <" + 465 IDs[i] + "> is incorrectly serialized/deserialized."); 466 } else { 467 logln("DateFormat instance which uses TimeZone <" + 468 IDs[i] + "> is correctly serialized/deserialized."); 469 } 470 } 471 if (!pass) { 472 errln("Fail: DateFormat serialization/equality bug"); 473 } 474 } 475 catch (IOException e) { 476 errln("Fail: " + e); 477 e.printStackTrace(); 478 } 479 catch (ClassNotFoundException e) { 480 errln("Fail: " + e); 481 e.printStackTrace(); 482 } 483 finally { 484 TimeZone.setDefault(savedTimeZone); 485 } 486 } 487 488 public void Test4101483() { 489 SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.US); 490 FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD); 491 Date d= new Date(9234567890L); 492 StringBuffer buf = new StringBuffer(""); 493 logln(sdf.format(d, buf, fp).toString()); 494 logln(d + " => " + buf); 495 logln("beginIndex = " + fp.getBeginIndex()); 496 logln("endIndex = " + fp.getEndIndex()); 497 if (fp.getBeginIndex() == fp.getEndIndex()) errln("Fail: Empty field"); 498 } 499 500 /** 501 * Bug 4103340 502 * Bug 4138203 503 * This bug really only works in Locale.US, since that's what the locale 504 * used for Date.toString() is. Bug 4138203 reports that it fails on Korean 505 * NT; it would actually have failed on any non-US locale. Now it should 506 * work on all locales. 507 */ 508 public void Test4103340() { 509 // choose a date that is the FIRST of some month 510 // and some arbitrary time 511 Date d=new Date(97, 3, 1, 1, 1, 1); 512 SimpleDateFormat df=new SimpleDateFormat("MMMM", Locale.US); 513 514 String s = d.toString(); 515 String s2 = df.format(d); 516 logln("Date="+s); 517 logln("DF="+s2); 518 if (s.indexOf(s2.substring(0,2)) == -1) 519 errln("Months should match"); 520 } 521 522 public void Test4103341() { 523 TimeZone saveZone =TimeZone.getDefault(); 524 try { 525 TimeZone.setDefault(TimeZone.getTimeZone("CST")); 526 SimpleDateFormat simple = new SimpleDateFormat("MM/dd/yyyy HH:mm"); 527 if (!simple.getTimeZone().equals(TimeZone.getDefault())) 528 errln("Fail: SimpleDateFormat not using default zone"); 529 } 530 finally { 531 TimeZone.setDefault(saveZone); 532 } 533 } 534 535 public void Test4104136() { 536 SimpleDateFormat sdf = new SimpleDateFormat(); 537 String pattern = "'time' hh:mm"; 538 sdf.applyPattern(pattern); 539 logln("pattern: \"" + pattern + "\""); 540 541 Object[] DATA = { 542 "time 10:30", new ParsePosition(10), new Date(70, Calendar.JANUARY, 1, 10, 30), 543 "time 10:x", new ParsePosition(0), null, 544 "time 10x", new ParsePosition(0), null, 545 }; 546 for (int i=0; i<DATA.length; i+=3) { 547 String text = (String) DATA[i]; 548 ParsePosition finish = (ParsePosition) DATA[i+1]; 549 Date exp = (Date) DATA[i+2]; 550 551 ParsePosition pos = new ParsePosition(0); 552 Date d = sdf.parse(text, pos); 553 logln(" text: \"" + text + "\""); 554 logln(" index: " + pos.getIndex()); 555 logln(" result: " + d); 556 if (pos.getIndex() != finish.getIndex()) 557 errln("Fail: Expected pos " + finish.getIndex()); 558 if (!((d == null && exp == null) || 559 d.equals(exp))) 560 errln("Fail: Expected result " + exp); 561 } 562 } 563 564 /** 565 * CANNOT REPRODUCE 566 * According to the bug report, this test should throw a 567 * StringIndexOutOfBoundsException during the second parse. However, 568 * this is not seen. 569 */ 570 public void Test4104522() { 571 SimpleDateFormat sdf = new SimpleDateFormat(); 572 String pattern = "'time' hh:mm"; 573 sdf.applyPattern(pattern); 574 logln("pattern: \"" + pattern + "\""); 575 576 // works correctly 577 ParsePosition pp = new ParsePosition(0); 578 String text = "time "; 579 Date date = sdf.parse(text, pp); 580 logln(" text: \"" + text + "\"" + 581 " date: " + date); 582 583 // works wrong 584 pp = new ParsePosition(0); 585 text = "time"; 586 date = sdf.parse(text, pp); 587 logln(" text: \"" + text + "\"" + 588 " date: " + date); 589 } 590 591 public void Test4106807() { 592 Date date; 593 DateFormat df = DateFormat.getDateTimeInstance(); 594 Object[] data = { 595 new SimpleDateFormat("yyyyMMddHHmmss"), "19980211140000", 596 new SimpleDateFormat("yyyyMMddHHmmss'Z'"), "19980211140000", 597 new SimpleDateFormat("yyyyMMddHHmmss''"), "19980211140000", 598 new SimpleDateFormat("yyyyMMddHHmmss'a''a'"), "19980211140000a", 599 new SimpleDateFormat("yyyyMMddHHmmss %"), "19980211140000 ", 600 }; 601 GregorianCalendar gc = new GregorianCalendar(); 602 TimeZone timeZone = TimeZone.getDefault(); 603 604 TimeZone gmt = (TimeZone)timeZone.clone(); 605 606 gmt.setRawOffset(0); 607 608 for (int i=0; i<data.length; i+=2) { 609 SimpleDateFormat format = (SimpleDateFormat) data[i]; 610 String dateString = (String) data[i+1]; 611 try { 612 format.setTimeZone(gmt); 613 date = format.parse(dateString); 614 logln(df.format(date)); 615 gc.setTime(date); 616 logln("" + gc.get(Calendar.ZONE_OFFSET)); 617 logln(format.format(date)); 618 } 619 catch (ParseException e) { 620 logln("No way Jose"); 621 } 622 } 623 } 624 625 /** 626 * SimpleDateFormat won't parse "GMT" 627 */ 628 public void Test4134203() { 629 String dateFormat = "MM/dd/yy HH:mm:ss zzz"; 630 SimpleDateFormat fmt = new SimpleDateFormat(dateFormat); 631 ParsePosition p0 = new ParsePosition(0); 632 Date d = fmt.parse("01/22/92 04:52:00 GMT", p0); 633 logln(d.toString()); 634 // In the failure case an exception is thrown by parse(); 635 // if no exception is thrown, the test passes. 636 } 637 638 /** 639 * Another format for GMT string parse 640 */ 641 public void Test4266432() { 642 String dateFormat = "MM/dd HH:mm:ss zzz yyyy"; 643 SimpleDateFormat fmt = new SimpleDateFormat(dateFormat); 644 ParsePosition p0 = new ParsePosition(0); 645 Date d = fmt.parse("01/22 04:52:00 GMT 1992", p0); 646 logln(d.toString()); 647 // In the failure case an exception is thrown by parse(); 648 // if no exception is thrown, the test passes. 649 } 650 651 /** 652 * Millisecond field is limited to 3 digits; also test general millisecond 653 * handling. 654 * 655 * NOTE: Updated for fixed semantics as of Kestrel. See 656 * 4253490 657 */ 658 public void Test4148168() throws ParseException { 659 SimpleDateFormat fmt = new SimpleDateFormat("", Locale.US); 660 int ms = 456; 661 String[] PAT = { "S", "SS", "SSS", "SSSS", "SSSSS", 662 "SSSSSSSSSSSSSSSSSSSS" }; 663 String[] OUT = { "456", "456", "456", "0456", "00456", 664 "00000000000000000456" }; 665 Calendar cal = Calendar.getInstance(); 666 cal.clear(); 667 cal.set(Calendar.MILLISECOND, ms); 668 Date d = cal.getTime(); 669 for (int i=0; i<OUT.length; ++i) { 670 fmt.applyPattern(PAT[i]); 671 String str = fmt.format(d); 672 if (!str.equals(OUT[i])) { 673 errln("FAIL: " + ms + " ms x \"" + PAT[i] + "\" -> \"" + 674 str + "\", exp \"" + OUT[i] + '"'); 675 } 676 } 677 678 // Test parsing 679 fmt.applyPattern("s.S"); 680 String[] IN = { "1.4", "1.04", "1.004", "1.45", "1.456", 681 "1.4567", "1.45678" }; 682 int[] MS = { 4, 4, 4, 45, 456, 567, 678 }; 683 for (int i=0; i<IN.length; ++i) { 684 d = fmt.parse(IN[i]); 685 cal.setTime(d); 686 ms = cal.get(Calendar.MILLISECOND); 687 if (ms != MS[i]) { 688 errln("FAIL: parse(\"" + IN[i] + "\" x \"s.S\") -> " + 689 ms + " ms, exp " + MS[i] + " ms"); 690 } 691 } 692 } 693 694 /** 695 * SimpleDateFormat incorrect handling of 2 single quotes in format() 696 */ 697 public void Test4151631() { 698 String pattern = "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'"; 699 logln("pattern=" + pattern); 700 SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US); 701 String result = format.format(new Date(1998-1900, Calendar.JUNE, 30, 13, 30, 0)); 702 if (!result.equals("TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')")) { 703 errln("Fail: result=" + result); 704 } 705 else { 706 logln("Pass: result=" + result); 707 } 708 } 709 710 /** 711 * 'z' at end of date format throws index exception in SimpleDateFormat 712 * CANNOT REPRODUCE THIS BUG ON 1.2FCS 713 */ 714 public void Test4151706() { 715 SimpleDateFormat fmt = 716 new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss z", Locale.US); 717 try { 718 Date d = fmt.parse("Thursday, 31-Dec-98 23:00:00 GMT"); 719 if (d.getTime() != Date.UTC(1998-1900, Calendar.DECEMBER, 31, 23, 0, 0)) 720 errln("Incorrect value: " + d); 721 } catch (Exception e) { 722 errln("Fail: " + e); 723 } 724 } 725 726 /** 727 * SimpleDateFormat fails to parse redundant data. 728 * This is actually a bug down in GregorianCalendar, but it was reported 729 * as follows... 730 */ 731 public void Test4153860() throws ParseException { 732 Locale savedLocale = Locale.getDefault(); 733 Locale.setDefault(Locale.US); 734 try { 735 SimpleDateFormat sf = (SimpleDateFormat)DateFormat.getDateTimeInstance(); 736 // Set the pattern 737 sf.applyPattern("yyyy.MM-dd"); 738 // Try to create a Date for February 4th 739 Date d1 = sf.parse("1998.02-04"); 740 // Set the pattern, this time to use the W value 741 sf.applyPattern("yyyy.MM-dd W"); 742 // Try to create a Date for February 4th 743 Date d2 = sf.parse("1998.02-04 1"); 744 if (!d1.equals(d2)) { 745 errln("Parse failed, got " + d2 + 746 ", expected " + d1); 747 } 748 } 749 finally { 750 Locale.setDefault(savedLocale); 751 } 752 } 753 754 /** 755 * Confirm that "EST"(GMT-5:00) and "CST"(GMT-6:00) are used in US 756 * as "EST" or "CST", not Australian "EST" and "CST". 757 */ 758 public void Test4406615() { 759 Locale savedLocale = Locale.getDefault(); 760 TimeZone savedTimeZone = TimeZone.getDefault(); 761 Locale.setDefault(Locale.US); 762 TimeZone.setDefault(TimeZone.getTimeZone("PST")); 763 764 Date d1, d2; 765 String dt = "Mon, 1 Jan 2001 00:00:00"; 766 SimpleDateFormat sdf = 767 new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); 768 769 try { 770 d1 = sdf.parse(dt+" EST"); 771 d2 = sdf.parse(dt+" CST"); 772 773 if (d1.getYear() != (2000-1900) || d1.getMonth() != 11 || 774 d1.getDate() != 31 || d1.getHours() != 21 || d1.getMinutes() != 0 || 775 d2.getYear() != (2000-1900) || d2.getMonth() != 11 || 776 d2.getDate() != 31 || d2.getHours() != 22 || d2.getMinutes() != 0) { 777 errln("Parse failed, d1 = " + d1 + ", d2 = " + d2); 778 } else { 779 logln("Parse passed"); 780 } 781 } 782 catch (Exception e) { 783 errln("Parse failed, got Exception " + e); 784 } 785 finally { 786 Locale.setDefault(savedLocale); 787 TimeZone.setDefault(savedTimeZone); 788 } 789 } 790 791 /** 792 * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate 793 * of some other bug that has been fixed. 794 */ 795 public void Test4162071() { 796 String dateString = "Thu, 30-Jul-1999 11:51:14 GMT"; 797 String format = "EEE', 'dd-MMM-yyyy HH:mm:ss z"; // RFC 822/1123 798 SimpleDateFormat df = new 799 SimpleDateFormat(format, Locale.US); 800 801 try { 802 Date x = df.parse(dateString); 803 logln("Parse format \"" + format + "\" ok"); 804 logln(dateString + " -> " + df.format(x)); 805 } catch (Exception e) { 806 errln("Parse format \"" + format + "\" failed."); 807 } 808 } 809 810 /** 811 * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" -> 1999). 812 */ 813 public void Test4182066() { 814 Locale savedLocale = Locale.getDefault(); 815 Locale.setDefault(Locale.US); 816 try { 817 SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy", 818 DateFormatSymbols.getInstance(Locale.US)); 819 SimpleDateFormat dispFmt = new SimpleDateFormat("MMM dd yyyy GG", 820 DateFormatSymbols.getInstance(Locale.US)); 821 /* We expect 2-digit year formats to put 2-digit years in the right 822 * window. Out of range years, that is, anything less than "00" or 823 * greater than "99", are treated as literal years. So "1/2/3456" 824 * becomes 3456 AD. Likewise, "1/2/-3" becomes -3 AD == 2 BC. 825 */ 826 Object[] DATA = { 827 "02/29/00", new Date(2000-1900, Calendar.FEBRUARY, 29), 828 "01/23/01", new Date(2001-1900, Calendar.JANUARY, 23), 829 "04/05/-1", new Date( -1-1900, Calendar.APRIL, 5), 830 "01/23/-9", new Date( -9-1900, Calendar.JANUARY, 23), 831 "11/12/1314", new Date(1314-1900, Calendar.NOVEMBER, 12), 832 "10/31/1", new Date( 1-1900, Calendar.OCTOBER, 31), 833 "09/12/+1", null, // "+1" isn't recognized by US NumberFormat 834 "09/12/001", new Date( 1-1900, Calendar.SEPTEMBER,12), 835 }; 836 StringBuffer out = new StringBuffer(); 837 boolean pass = true; 838 for (int i=0; i<DATA.length; i+=2) { 839 String str = (String) DATA[i]; 840 Date expected = (Date) DATA[i+1]; 841 Date actual; 842 try { 843 actual = fmt.parse(str); 844 } catch (ParseException e) { 845 actual = null; 846 } 847 String actStr = actual != null 848 ? dispFmt.format(actual) : String.valueOf(actual); 849 if (expected == actual 850 || (expected != null && expected.equals(actual))) { 851 out.append(str + " => " + actStr + "\n"); 852 } else { 853 String expStr = expected != null 854 ? dispFmt.format(expected) : String.valueOf(expected); 855 out.append("FAIL: " + str + " => " + actStr 856 + ", expected " + expStr + "\n"); 857 pass = false; 858 } 859 } 860 if (pass) { 861 log(out.toString()); 862 } else { 863 err(out.toString()); 864 } 865 } 866 finally { 867 Locale.setDefault(savedLocale); 868 } 869 } 870 871 /** 872 * Bug 4210209 873 * Bug 4209272 874 * DateFormat cannot parse Feb 29 2000 when setLenient(false) 875 */ 876 public void Test4210209() { 877 String pattern = "MMM d, yyyy"; 878 DateFormat fmt = new SimpleDateFormat(pattern, 879 DateFormatSymbols.getInstance(Locale.US)); 880 fmt.getCalendar().setLenient(false); 881 Date d = new Date(2000-1900, Calendar.FEBRUARY, 29); 882 String s = fmt.format(d); 883 logln(d + " x " + pattern + " => " + s); 884 ParsePosition pos = new ParsePosition(0); 885 d = fmt.parse(s, pos); 886 logln(d + " <= " + pattern + " x " + s); 887 logln("Parse pos = " + pos); 888 if (pos.getErrorIndex() != -1) { 889 errln("FAIL"); 890 } 891 892 // The underlying bug is in GregorianCalendar. If the following lines 893 // succeed, the bug is fixed. If the bug isn't fixed, they will throw 894 // an exception. 895 GregorianCalendar cal = new GregorianCalendar(); 896 cal.clear(); 897 cal.setLenient(false); 898 cal.set(2000, Calendar.FEBRUARY, 29); // This should work! 899 logln(cal.getTime().toString()); 900 } 901 902 /** 903 * DateFormat.getDateTimeInstance() allows illegal parameters. 904 */ 905 public void Test4213086() { 906 int[] DATA = { 907 // Style value, 0/1 for illegal/legal 908 -99, 0, 909 -1, 0, 910 0, 1, 911 1, 1, 912 2, 1, 913 3, 1, 914 4, 0, 915 99, 0, 916 }; 917 String[] DESC = { 918 "getDateTimeInstance(date)", 919 "getDateTimeInstance(time)", 920 "getDateInstance", 921 "getTimeInstance", 922 }; 923 String[] GOT = { 924 "disallowed", "allowed", "<invalid>" 925 }; 926 for (int i=0; i<DATA.length; i+=2) { 927 int got = 2; 928 for (int j=0; j<4; ++j) { 929 Exception e = null; 930 try { 931 DateFormat df; 932 switch (j) { 933 case 0: 934 df = DateFormat.getDateTimeInstance(DATA[i], 0); 935 break; 936 case 1: 937 df = DateFormat.getDateTimeInstance(0, DATA[i]); 938 break; 939 case 2: 940 df = DateFormat.getDateInstance(DATA[i]); 941 break; 942 case 3: 943 df = DateFormat.getTimeInstance(DATA[i]); 944 break; 945 } 946 got = 1; 947 } catch (IllegalArgumentException iae) { 948 got = 0; 949 } catch (Exception ex) { 950 e = ex; 951 } 952 if (got != DATA[i+1] || e != null) { 953 errln("FAIL: DateFormat." + DESC[j] + " style " + DATA[i] + " " + 954 (e != null ? e.toString() : GOT[got])); 955 } 956 } 957 } 958 } 959 960 public void Test4253490() throws ParseException { 961 SimpleDateFormat fmt = new SimpleDateFormat("S", Locale.US); 962 963 GregorianCalendar cal = new GregorianCalendar(); 964 965 int FORMAT_MS = 12; 966 String[] FORMAT_PAT = { "S", "SS", "SSS", "SSSS" }; 967 String[] FORMAT_TO = { "12", "12", "012", "0012" }; 968 969 String PARSE_PAT = "S"; 970 String[] PARSE_STR = { "1", "12", "125", "1250" }; 971 int[] PARSE_TO = { 1, 12, 125, 250 }; 972 String PARSE_LPAT = "SSSSS"; 973 974 // Test formatting. We want to make sure all digits are output 975 // and that they are zero-padded on the left if necessary. 976 cal.setTime(new Date(0L)); 977 cal.set(Calendar.MILLISECOND, FORMAT_MS); 978 Date d = cal.getTime(); 979 for (int i=0; i<FORMAT_PAT.length; ++i) { 980 fmt.applyPattern(FORMAT_PAT[i]); 981 String s = fmt.format(d); 982 if (s.equals(FORMAT_TO[i])) { 983 logln(String.valueOf(FORMAT_MS) + " ms f* \"" + 984 FORMAT_PAT[i] + "\" -> \"" + s + '"'); 985 } else { 986 errln("FAIL: " + FORMAT_MS + " ms f* \"" + 987 FORMAT_PAT[i] + "\" -> \"" + s + "\", expect \"" + 988 FORMAT_TO[i] + '"'); 989 } 990 } 991 992 // Test parsing. We want to make sure all digits are read. 993 fmt.applyPattern(PARSE_PAT); 994 for (int i=0; i<PARSE_STR.length; ++i) { 995 cal.setTime(fmt.parse(PARSE_STR[i])); 996 int ms = cal.get(Calendar.MILLISECOND); 997 if (ms == PARSE_TO[i]) { 998 logln("\"" + PARSE_STR[i] + "\" p* \"" + 999 PARSE_PAT + "\" -> " + ms + " ms"); 1000 } else { 1001 errln("FAIL: \"" + PARSE_STR[i] + "\" p* \"" + 1002 PARSE_PAT + "\" -> " + ms + " ms, expect " + 1003 PARSE_TO[i] + " ms"); 1004 } 1005 } 1006 1007 // Test LONG parsing. We want to make sure all digits are read. 1008 fmt.applyPattern(PARSE_LPAT); 1009 for (int i=0; i<PARSE_STR.length; ++i) { 1010 cal.setTime(fmt.parse(PARSE_STR[i])); 1011 int ms = cal.get(Calendar.MILLISECOND); 1012 if (ms == PARSE_TO[i]) { 1013 logln("\"" + PARSE_STR[i] + "\" p* \"" + 1014 PARSE_LPAT + "\" -> " + ms + " ms"); 1015 } else { 1016 errln("FAIL: \"" + PARSE_STR[i] + "\" p* \"" + 1017 PARSE_LPAT + "\" -> " + ms + " ms, expect " + 1018 PARSE_TO[i] + " ms"); 1019 } 1020 } 1021 } 1022 1023 /** 1024 * Bug in handling of time instance; introduces in fix for 4213086. 1025 */ 1026 public void Test4250359() { 1027 DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, 1028 Locale.US); 1029 Date d = new Date(1999-1900, Calendar.DECEMBER, 25, 1030 1, 2, 3); 1031 String s = df.format(d); 1032 // If the bug is present, we see "1:02 AM 1:02 AM". 1033 // Look for more than one instance of "AM". 1034 int i = s.indexOf("AM"); 1035 int j = s.indexOf("AM", i+1); 1036 if (i < 0 || j >= 0) { 1037 errln("FAIL: getTimeInstance().format(d) => \"" + 1038 s + "\""); 1039 } 1040 } 1041 1042 /** 1043 * Test whether SimpleDataFormat (DateFormatSymbols) can format/parse 1044 * non-localized time zones. 1045 */ 1046 public void Test4261506() { 1047 Locale savedLocale = Locale.getDefault(); 1048 TimeZone savedTimeZone = TimeZone.getDefault(); 1049 Locale.setDefault(Locale.JAPAN); 1050 1051 // XXX: Test assumes "PST" is not TimeZoneNames_ja. Need to 1052 // pick up another time zone when L10N is done to that file. 1053 TimeZone.setDefault(TimeZone.getTimeZone("PST")); 1054 SimpleDateFormat fmt = new SimpleDateFormat("yy/MM/dd hh:ss zzz", Locale.JAPAN); 1055 String result = fmt.format(new Date(1999, 0, 1)); 1056 logln("format()=>" + result); 1057 if (!result.endsWith("PST")) { 1058 errln("FAIL: SimpleDataFormat.format() did not retrun PST"); 1059 } 1060 1061 Date d = null; 1062 try { 1063 d = fmt.parse("99/1/1 10:10 PST"); 1064 } catch (ParseException e) { 1065 errln("FAIL: SimpleDataFormat.parse() could not parse PST"); 1066 } 1067 1068 result = fmt.format(d); 1069 logln("roundtrip:" + result); 1070 if (!result.equals("99/01/01 10:10 PST")) { 1071 errln("FAIL: SimpleDataFomat timezone roundtrip failed"); 1072 } 1073 1074 Locale.setDefault(savedLocale); 1075 TimeZone.setDefault(savedTimeZone); 1076 } 1077 1078 } 1079 1080 //eof