1 /* 2 * Copyright (c) 1997, 2019, 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 /** 25 * @test 26 * @bug 4052223 4089987 4469904 4326988 4486735 8008577 8045998 8140571 27 * 8216969 28 * @summary test DateFormat and SimpleDateFormat. 29 * @library /java/text/testlib 30 * @modules jdk.localedata 31 * @run main/othervm -Djava.locale.providers=COMPAT,SPI DateFormatTest 32 */ 33 34 import java.util.*; 35 import java.text.*; 36 import static java.util.GregorianCalendar.*; 37 38 public class DateFormatTest extends IntlTest 39 { main(String[] args)40 public static void main(String[] args) throws Exception { 41 Locale reservedLocale = Locale.getDefault(); 42 try { 43 Locale.setDefault(Locale.US); 44 new DateFormatTest().run(args); 45 } finally { 46 // restore the reserved locale 47 Locale.setDefault(reservedLocale); 48 } 49 } 50 51 // Test 4 digit year parsing with pattern "yy" 52 @SuppressWarnings("deprecation") TestYearParsing()53 public void TestYearParsing() 54 { 55 String str = "7/Sep/2001"; 56 Date exp = new Date(2001-1900, SEPTEMBER, 7); 57 String pat = "d/MMM/yy"; 58 SimpleDateFormat sdf = new SimpleDateFormat(pat, Locale.US); 59 try { 60 Date d = sdf.parse(str); 61 logln(str + " parses with " + pat + " to " + d); 62 if (d.getTime() != exp.getTime()) { 63 errln("FAIL: Expected " + exp); 64 } 65 } 66 catch (ParseException e) { 67 errln(str + " parse fails with " + pat); 68 } 69 } 70 71 // Test written by Wally Wedel and emailed to me. TestWallyWedel()72 public void TestWallyWedel() 73 { 74 /* 75 * Instantiate a TimeZone so we can get the ids. 76 */ 77 TimeZone tz = new SimpleTimeZone(7,""); 78 /* 79 * Computational variables. 80 */ 81 int offset, hours, minutes; 82 /* 83 * Instantiate a SimpleDateFormat set up to produce a full time 84 zone name. 85 */ 86 SimpleDateFormat sdf = new SimpleDateFormat("zzzz"); 87 /* 88 * A String array for the time zone ids. 89 */ 90 String[] ids = TimeZone.getAvailableIDs(); 91 /* 92 * How many ids do we have? 93 */ 94 logln("Time Zone IDs size: " + ids.length); 95 /* 96 * Column headings (sort of) 97 */ 98 logln("Ordinal ID offset(h:m) name"); 99 /* 100 * Loop through the tzs. 101 */ 102 Date today = new Date(); 103 Calendar cal = Calendar.getInstance(); 104 for (int i = 0; i < ids.length; i++) { 105 // logln(i + " " + ids[i]); 106 TimeZone ttz = TimeZone.getTimeZone(ids[i]); 107 // offset = ttz.getRawOffset(); 108 cal.setTimeZone(ttz); 109 cal.setTime(today); 110 offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); 111 // logln(i + " " + ids[i] + " offset " + offset); 112 char sign = '+'; 113 if (offset < 0) { sign = '-'; offset = -offset; } 114 hours = offset/3600000; 115 minutes = (offset%3600000)/60000; 116 String dstOffset = "" + sign + (hours < 10 ? "0" : "") + 117 hours + ':' + (minutes < 10 ? "0" : "") + minutes; 118 /* 119 * Instantiate a date so we can display the time zone name. 120 */ 121 sdf.setTimeZone(ttz); 122 /* 123 * Format the output. 124 */ 125 StringBuffer tzS = new StringBuffer(); 126 sdf.format(today,tzS, new FieldPosition(0)); 127 String fmtOffset = tzS.toString(); 128 String fmtDstOffset = null; 129 if (fmtOffset.startsWith("GMT")) 130 { 131 fmtDstOffset = fmtOffset.substring(3); 132 } 133 /* 134 * Show our result. 135 */ 136 boolean ok = fmtDstOffset == null || fmtDstOffset.equals(dstOffset); 137 if (ok) 138 { 139 logln(i + " " + ids[i] + " " + dstOffset + 140 " " + fmtOffset + 141 (fmtDstOffset != null ? " ok" : " ?")); 142 } 143 else 144 { 145 errln(i + " " + ids[i] + " " + dstOffset + 146 " " + fmtOffset + " *** FAIL ***"); 147 } 148 } 149 } 150 151 // Test equals TestEquals()152 public void TestEquals() 153 { 154 DateFormat fmtA = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); 155 156 DateFormat fmtB = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); 157 158 if (!fmtA.equals(fmtB)) { 159 errln("FAIL"); 160 } 161 } 162 163 // Check out some specific parsing problem 164 @SuppressWarnings("deprecation") TestTwoDigitYearDSTParse()165 public void TestTwoDigitYearDSTParse() 166 { 167 SimpleDateFormat fullFmt = 168 new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G"); 169 170 //DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL, 171 // Locale.ENGLISH); 172 SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yy h:mm:ss 'o''clock' a z", 173 Locale.ENGLISH); 174 //Date date = new Date(2004-1900, Calendar.APRIL, 3, 2, 20, 47); 175 //logln(fmt.format(date)); // This shows what the current locale format is 176 //logln(((SimpleDateFormat)fmt).toPattern()); 177 TimeZone save = TimeZone.getDefault(); 178 TimeZone PST = TimeZone.getTimeZone("PST"); 179 String s = "03-Apr-04 2:20:47 o'clock AM PST"; 180 int hour = 2; 181 try { 182 TimeZone.setDefault(PST); 183 Date d = fmt.parse(s); 184 logln(s + " P> " + fullFmt.format(d)); 185 if (d.getHours() != hour) { 186 errln("FAIL: Should parse to hour " + hour); 187 } 188 } 189 catch (ParseException e) { errln("FAIL: " + e.getMessage()); } 190 finally { 191 TimeZone.setDefault(save); 192 } 193 } 194 escape(String s)195 static String escape(String s) 196 { 197 StringBuilder buf = new StringBuilder(); 198 for (int i=0; i<s.length(); ++i) 199 { 200 char c = s.charAt(i); 201 if (c <= (char)0x7F) { 202 buf.append(c); 203 } else { 204 buf.append("\\u"); 205 buf.append(Integer.toHexString((c & 0xF000) >> 12)); 206 buf.append(Integer.toHexString((c & 0x0F00) >> 8)); 207 buf.append(Integer.toHexString((c & 0x00F0) >> 4)); 208 buf.append(Integer.toHexString(c & 0x000F)); 209 } 210 } 211 return buf.toString(); 212 } 213 214 // Test field position return values 215 static String fieldNames[] = { 216 "ERA_FIELD", "YEAR_FIELD", "MONTH_FIELD", 217 "WEEK_OF_YEAR_FIELD", "WEEK_OF_MONTH_FIELD", "DATE_FIELD", 218 "DAY_OF_YEAR_FIELD", "DAY_OF_WEEK_FIELD", "DAY_OF_WEEK_IN_MONTH_FIELD", 219 "AM_PM_FIELD", "HOUR0_FIELD", "HOUR1_FIELD", 220 "HOUR_OF_DAY0_FIELD", "HOUR_OF_DAY1_FIELD", 221 "MINUTE_FIELD", "SECOND_FIELD", 222 "MILLISECOND_FIELD", "TIMEZONE_FIELD", 223 }; 224 static int fieldIDs[] = { 225 DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD, 226 DateFormat.WEEK_OF_YEAR_FIELD, DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.DATE_FIELD, 227 DateFormat.DAY_OF_YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, 228 DateFormat.AM_PM_FIELD, DateFormat.HOUR0_FIELD, DateFormat.HOUR1_FIELD, 229 DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.HOUR_OF_DAY1_FIELD, 230 DateFormat.MINUTE_FIELD, DateFormat.SECOND_FIELD, 231 DateFormat.MILLISECOND_FIELD, DateFormat.TIMEZONE_FIELD, 232 }; 233 234 /** 235 * Bug 4089987 236 */ TestFieldPosition()237 public void TestFieldPosition() 238 { 239 DateFormat[] dateFormats = { 240 DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL, 241 Locale.US), 242 243 DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL,Locale.FRANCE), 244 new SimpleDateFormat("G, y, M, d, k, H, m, s, S, E, D, F, w, W, a, h, K, z"), 245 new SimpleDateFormat("G, yy, M, d, k, H, m, s, S, E, D, F, w, W, a, h, K, z"), 246 new SimpleDateFormat( "GGGG, yyyy, MMMM, dddd, kkkk, HHHH, mmmm, ssss, " + 247 "SSSS, EEEE, DDDD, " + 248 "FFFF, wwww, WWWW, aaaa, hhhh, KKKK, zzzz") 249 }; 250 String[] expected = 251 { 252 "", "1997", "August", "", "", "13", "", "Wednesday", "", 253 "PM", "", "2", "", "", "34", "12", "", "PDT", 254 255 "", "1997", "ao\u00FBt", "", "", "13", "", "mercredi", "", "", 256 "", "", "14", "", "34", "", "", "PDT" /*"GMT-07:00"*/, 257 258 "AD", "1997", "8", "33", "3", "13", "225", "Wed", "2", "PM", 259 "2", "2", "14", "14", "34", "12", "513", "PDT", 260 261 "AD", "97", "8", "33", "3", "13", "225", "Wed", "2", "PM", 262 "2", "2", "14", "14", "34", "12", "513", "PDT", 263 264 "AD", "1997", "August", "0033", "0003", "0013", "0225", 265 "Wednesday", "0002", "PM", "0002", "0002", "0014", "0014", 266 "0034", "0012", "0513", "Pacific Daylight Time", 267 }; 268 Date someDate = new Date(871508052513L); 269 TimeZone PST = TimeZone.getTimeZone("PST"); 270 for (int j = 0, exp = 0; j < dateFormats.length; ++j) { 271 DateFormat df = dateFormats[j]; 272 if (!(df instanceof SimpleDateFormat)) { 273 continue; 274 } 275 df.setTimeZone(PST); 276 logln(" Pattern = " + ((SimpleDateFormat)df).toPattern()); 277 logln(" Result = " + df.format(someDate)); 278 for (int i = 0; i < fieldIDs.length; ++i) 279 { 280 String field = getFieldText(df, fieldIDs[i], someDate); 281 if (!field.equals(expected[exp])) { 282 errln("FAIL: field #" + i + " " + fieldNames[i] + " = \"" + 283 escape(field) + "\", expected \"" + escape(expected[exp]) + "\""); 284 } 285 ++exp; 286 } 287 } 288 } 289 // get the string value for the given field for the given date getFieldText(DateFormat df, int field, Date date)290 static String getFieldText(DateFormat df, int field, Date date) 291 { 292 StringBuffer buffer = new StringBuffer(); 293 FieldPosition pos = new FieldPosition(field); 294 df.format(date, buffer, pos); 295 return buffer.toString().substring(pos.getBeginIndex(), 296 pos.getEndIndex()); 297 } 298 299 // Test parsing of partial strings 300 @SuppressWarnings("deprecation") TestPartialParse994()301 public void TestPartialParse994() 302 { 303 SimpleDateFormat f = new SimpleDateFormat(); 304 Calendar cal = new GregorianCalendar(2014 - 80, JANUARY, 1); 305 f.set2DigitYearStart(cal.getTime()); 306 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", new Date(97, 1-1, 17, 10, 11, 42)); 307 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", null); 308 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", null); 309 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", null); 310 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", null); 311 } 312 tryPat994(SimpleDateFormat format, String pat, String str, Date expected)313 void tryPat994(SimpleDateFormat format, String pat, String str, Date expected) 314 { 315 logln("Pattern \"" + pat + "\" String \"" + str + "\""); 316 try { 317 format.applyPattern(pat); 318 Date date = format.parse(str); 319 String f = format.format(date); 320 logln(" parse(" + str + ") -> " + date.toString()); 321 logln(" format -> " + f); 322 if (expected == null || 323 !date.equals(expected)) { 324 errln("FAIL: Expected " + expected); 325 } 326 if (!f.equals(str)) { 327 errln("FAIL: Expected " + str); 328 } 329 } 330 catch(ParseException e) { 331 logln("ParseException: " + e.getMessage()); 332 if (expected != null) { 333 errln("FAIL: Expected " + expected); 334 } 335 } 336 catch(Exception e) { 337 errln("*** Exception:"); 338 e.printStackTrace(); 339 } 340 } 341 342 // Test pattern with runs things together TestRunTogetherPattern985()343 public void TestRunTogetherPattern985() 344 { 345 String format = "yyyyMMddHHmmssSSS"; 346 String now, then; 347 348 SimpleDateFormat formatter = new SimpleDateFormat(format); 349 350 Date date1 = new Date(); 351 now = formatter.format(date1); 352 353 logln(now); 354 355 ParsePosition pos = new ParsePosition(0); 356 357 Date date2 = formatter.parse(now, pos); 358 if (date2 == null) { 359 then = "Parse stopped at " + pos.getIndex(); 360 } else { 361 then = formatter.format(date2); 362 } 363 364 logln(then); 365 366 if (!date2.equals(date1)) { 367 errln("FAIL"); 368 } 369 } 370 371 // Test patterns which run numbers together 372 @SuppressWarnings("deprecation") TestRunTogetherPattern917()373 public void TestRunTogetherPattern917() 374 { 375 SimpleDateFormat fmt; 376 String myDate; 377 378 fmt = new SimpleDateFormat( "yyyy/MM/dd" ); 379 myDate = "1997/02/03"; 380 _testIt917( fmt, myDate, new Date(97, 2-1, 3) ); 381 382 fmt = new SimpleDateFormat( "yyyyMMdd" ); 383 myDate = "19970304"; 384 _testIt917( fmt, myDate, new Date(97, 3-1, 4) ); 385 386 } _testIt917( SimpleDateFormat fmt, String str, Date expected )387 void _testIt917( SimpleDateFormat fmt, String str, Date expected ) 388 { 389 logln( "pattern=" + fmt.toPattern() + " string=" + str ); 390 391 Object o; 392 try { 393 o = fmt.parseObject( str ); 394 } catch( ParseException e ) { 395 e.printStackTrace(); 396 return; 397 } 398 logln( "Parsed object: " + o ); 399 if (!o.equals(expected)) { 400 errln("FAIL: Expected " + expected); 401 } 402 403 String formatted = fmt.format( o ); 404 logln( "Formatted string: " + formatted ); 405 if (!formatted.equals(str)) { 406 errln("FAIL: Expected " + str); 407 } 408 } 409 410 // Test Czech month formatting -- this can cause a problem because the June and 411 // July month names share a common prefix. 412 @SuppressWarnings("deprecation") TestCzechMonths459()413 public void TestCzechMonths459() 414 { 415 // Use Czech, which has month names with shared prefixes for June and July 416 DateFormat fmt = DateFormat.getDateInstance(DateFormat.FULL, new Locale("cs", "", "")); 417 //((SimpleDateFormat)fmt).applyPattern("MMMM d yyyy"); 418 logln("Pattern " + ((SimpleDateFormat)fmt).toPattern()); 419 420 Date june = new Date(97, Calendar.JUNE, 15); 421 Date july = new Date(97, Calendar.JULY, 15); 422 423 String juneStr = fmt.format(june); 424 String julyStr = fmt.format(july); 425 426 try { 427 logln("format(June 15 1997) = " + juneStr); 428 Date d = fmt.parse(juneStr); 429 String s = fmt.format(d); 430 int month = d.getMonth(); 431 logln(" -> parse -> " + s + " (month = " + month + ")"); 432 if (month != JUNE) { 433 errln("FAIL: Month should be June"); 434 } 435 436 logln("format(July 15 1997) = " + julyStr); 437 d = fmt.parse(julyStr); 438 s = fmt.format(d); 439 month = d.getMonth(); 440 logln(" -> parse -> " + s + " (month = " + month + ")"); 441 if (month != JULY) { 442 errln("FAIL: Month should be July"); 443 } 444 } 445 catch (ParseException e) { 446 errln("Exception: " + e); 447 } 448 } 449 450 // Test big D (day of year) versus little d (day of month) 451 @SuppressWarnings("deprecation") TestLetterDPattern212()452 public void TestLetterDPattern212() 453 { 454 String dateString = "1995-040.05:01:29"; 455 String bigD = "yyyy-DDD.hh:mm:ss"; 456 String littleD = "yyyy-ddd.hh:mm:ss"; 457 Date expLittleD = new Date(95, 0, 1, 5, 1, 29); 458 Date expBigD = new Date(expLittleD.getTime() + 39*24*3600000L); // 39 days 459 expLittleD = expBigD; // Expect the same, with default lenient parsing 460 logln( "dateString= " + dateString ); 461 SimpleDateFormat formatter = new SimpleDateFormat(bigD); 462 ParsePosition pos = new ParsePosition(0); 463 Date myDate = formatter.parse( dateString, pos ); 464 logln("Using " + bigD + " -> " + myDate); 465 if (myDate.getTime() != expBigD.getTime()) { 466 errln("FAIL: Expected " + expBigD + " got " + myDate); 467 } 468 469 formatter = new SimpleDateFormat(littleD); 470 pos = new ParsePosition(0); 471 myDate = formatter.parse( dateString, pos ); 472 logln("Using " + littleD + " -> " + myDate); 473 if (myDate.getTime() != expLittleD.getTime()) { 474 errln("FAIL: Expected " + expLittleD + " got " + myDate); 475 } 476 } 477 478 // Test the 'G' day of year pattern 479 @SuppressWarnings("deprecation") TestDayOfYearPattern195()480 public void TestDayOfYearPattern195() 481 { 482 Date today = new Date(); 483 Date expected = new Date(today.getYear(), today.getMonth(), today.getDate()); 484 485 logln("Test Date: " + today); 486 487 SimpleDateFormat sdf = 488 (SimpleDateFormat)SimpleDateFormat.getDateInstance(); 489 490 tryPattern(sdf, today, null, expected); 491 tryPattern(sdf, today, "G yyyy DDD", expected); 492 } 493 tryPattern(SimpleDateFormat sdf, Date d, String pattern, Date expected)494 void tryPattern(SimpleDateFormat sdf, Date d, String pattern, Date expected) 495 { 496 if (pattern != null) { 497 sdf.applyPattern(pattern); 498 } 499 logln("pattern: " + sdf.toPattern()); 500 501 String formatResult = sdf.format(d); 502 logln(" format -> " + formatResult); 503 try { 504 Date d2 = sdf.parse(formatResult); 505 logln(" parse(" + formatResult + ") -> " + d2); 506 if (d2.getTime() != expected.getTime()) { 507 errln("FAIL: Expected " + expected); 508 } 509 String format2 = sdf.format(d2); 510 logln(" format -> " + format2); 511 if (!formatResult.equals(format2)) { 512 errln("FAIL: Round trip drift"); 513 } 514 } 515 catch(Exception e) { 516 errln("Error: " + e.getMessage()); 517 } 518 } 519 520 // Test a pattern with single quotes 521 @SuppressWarnings("deprecation") TestQuotePattern161()522 public void TestQuotePattern161() 523 { 524 // This pattern used to end in " zzz" but that makes this test zone-dependent 525 SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy 'at' hh:mm:ss a zzz"); 526 Date currentTime_1 = new Date(97, Calendar.AUGUST, 13, 10, 42, 28); 527 String dateString = formatter.format(currentTime_1); 528 String exp = "08/13/1997 at 10:42:28 AM "; 529 logln("format(" + currentTime_1 + ") = " + dateString); 530 if (!dateString.regionMatches(0, exp, 0, exp.length())) { 531 errln("FAIL: Expected " + exp); 532 } 533 } 534 535 // Test the parsing of bad input strings 536 /** Demonstrates a number of bugs in DateFormat.parse(String) where 537 * either StringIndexOutOfBoundsException is thrown or null is 538 * returned instead of ParseException. To reproduce, run this program 539 * and notice all the "SHOULD NOT HAPPEN" errors. Note also that the 540 * 1 line that should be correct is off by 100 years. (In this day 541 * and age, no one would assume that 1/1/00 is Jan 1 1900.) 542 **/ TestBadInput135()543 public void TestBadInput135() 544 { 545 int looks[] = { DateFormat.SHORT, DateFormat.MEDIUM, 546 DateFormat.LONG, DateFormat.FULL }; 547 String strings[] = { "Mar 15", "Mar 15 1997", "asdf", 548 "3/1/97 1:23:", "3/1/00 1:23:45 AM" }; 549 DateFormat full = DateFormat.getDateTimeInstance(DateFormat.LONG, 550 DateFormat.LONG); 551 String expected = "March 1, 2000 1:23:45 AM "; 552 for ( int i = 0; i < strings.length; ++i ){ 553 String text = strings[i]; 554 for ( int j = 0; j < looks.length; ++j ){ 555 int dateLook = looks[j]; 556 for ( int k = 0; k < looks.length; ++k ){ 557 int timeLook = looks[k]; 558 DateFormat df = DateFormat.getDateTimeInstance(dateLook, timeLook); 559 String prefix = text + ", " + dateLook + "/" + timeLook + ": "; 560 try { 561 Date when = df.parse(text); 562 if ( when == null ){ 563 errln(prefix + 564 "SHOULD NOT HAPPEN: parse returned null."); 565 continue; 566 } 567 String format = full.format(when); 568 logln(prefix + "OK: " + format); 569 // Only match the start -- not the zone, which could vary 570 if (!format.regionMatches(0, expected, 0, expected.length())) { 571 errln("FAIL: Expected " + expected); 572 } 573 } 574 catch ( ParseException e ){ 575 //errln(prefix + e); // This is expected. 576 } 577 catch ( StringIndexOutOfBoundsException e ){ 578 errln(prefix + "SHOULD NOT HAPPEN: " + e); 579 } 580 } 581 } 582 } 583 } 584 585 final private static String parseFormats[] = 586 { 587 "MMMM d, yyyy", // january 1, 1970 or jan 1, 1970 588 "MMMM d yyyy", // january 1 1970 or jan 1 1970 589 "M/d/yy", // 1/1/70 590 "d MMMM, yyyy", // 1 january, 1970 or 1 jan, 1970 591 "d MMMM yyyy", // 1 january 1970 or 1 jan 1970 592 "d MMMM", // 1 january or 1 jan 593 "MMMM d", // january 1 or jan 1 594 "yyyy", // 1970 595 "h:mm a MMMM d, yyyy" // Date and Time 596 }; 597 final private static String inputStrings[] = 598 { 599 "bogus string", null, null, null, null, null, null, null, null, null, 600 "April 1, 1997", "April 1, 1997", null, null, null, null, null, "April 1", null, null, 601 "Jan 1, 1970", "January 1, 1970", null, null, null, null, null, "January 1", null, null, 602 "Jan 1 2037", null, "January 1 2037", null, null, null, null, "January 1", null, null, 603 "1/1/70", null, null, "1/1/70", null, null, null, null, "0001", null, 604 "5 May 1997", null, null, null, null, "5 May 1997", "5 May", null, "0005", null, 605 "16 May", null, null, null, null, null, "16 May", null, "0016", null, 606 "April 30", null, null, null, null, null, null, "April 30", null, null, 607 "1998", null, null, null, null, null, null, null, "1998", null, 608 "1", null, null, null, null, null, null, null, "0001", null, // Bug620 609 "3:00 pm Jan 1, 1997", null, null, null, null, null, null, null, "0003", "3:00 PM January 1, 1997", 610 }; 611 // More testing of the parsing of bad input 612 @SuppressWarnings("UnusedAssignment") TestBadInput135a()613 public void TestBadInput135a() 614 { 615 SimpleDateFormat dateParse = new SimpleDateFormat(); 616 String s; 617 Date date; 618 int PFLENGTH = parseFormats.length; 619 620 dateParse.applyPattern("d MMMM, yyyy"); 621 dateParse.setTimeZone(TimeZone.getDefault()); 622 s = "not parseable"; 623 logln("Trying to parse \"" + s + "\" with " + dateParse.toPattern()); 624 try { 625 date = dateParse.parse(s); 626 errln("FAIL: Expected exception during parse"); 627 } catch (Exception ex) { 628 logln("Exception during parse: " + ex); // This is expected 629 } 630 631 for (int i=0; i<inputStrings.length; i += (PFLENGTH+1)) 632 { 633 ParsePosition parsePosition = new ParsePosition(0); 634 s = inputStrings[i]; 635 636 for (int index=0; index<PFLENGTH; ++index) 637 { 638 String expected = inputStrings[i + 1 + index]; 639 dateParse.applyPattern(parseFormats[index]); 640 dateParse.setTimeZone(TimeZone.getDefault()); 641 // logln("Trying to parse \"" + s + "\" with " + dateParse.toPattern()); 642 try { 643 parsePosition.setIndex(0); 644 date = dateParse.parse(s, parsePosition); 645 if (parsePosition.getIndex() != 0) { 646 if (date == null) { 647 errln("ERROR: null result with pos " + 648 parsePosition.getIndex() + " " + 649 s.substring(0, parsePosition.getIndex()) + "|" + 650 s.substring(parsePosition.getIndex())); 651 } else { 652 String result = dateParse.format(date); 653 logln("Parsed \"" + s + "\" using \"" + dateParse.toPattern() + 654 "\" to: " + result); 655 if (expected == null) { 656 errln("FAIL: Expected parse failure"); 657 } else if (!expected.equals(result)) { 658 errln("FAIL: Expected " + expected); 659 } 660 } 661 } else { 662 // logln("Not parsed."); 663 if (expected != null) { 664 errln("FAIL: Expected " + expected); 665 } 666 } 667 } catch (Exception ex) { 668 errln("An exception was thrown during parse: " + ex); 669 } 670 } 671 } 672 } 673 674 // Test the handling of 2-digit dates TestTwoDigitYear()675 public void TestTwoDigitYear() { 676 SimpleDateFormat fmt = new SimpleDateFormat("M/d/yy"); 677 678 // find out the expected 2-digit year values for "6/5/17" and "6/4/34" 679 long start = fmt.get2DigitYearStart().getTime(); 680 Calendar cal = new Calendar.Builder().setInstant(start).build(); 681 int startYear = cal.get(YEAR); 682 cal.add(YEAR, 100); 683 long end = cal.getTimeInMillis(); 684 int endYear = cal.get(YEAR); 685 int xx17 = 0, xx34 = 0; 686 for (int year = startYear; year <= endYear; year++) { 687 int yy = year % 100; 688 if (yy == 17 && xx17 == 0) { 689 xx17 = yearValue(start, end, year, JUNE, 5); 690 } else if (yy == 34 && xx34 == 0) { 691 xx34 = yearValue(start, end, year, JUNE, 4); 692 } 693 if (xx17 != 0 && xx34 != 0) { 694 break; 695 } 696 } 697 if (xx17 == 0 || xx34 == 0) { 698 errln("Failed: producing expected values: 2DigitYearStart: " + new Date(start) 699 + ", xx17 = " + xx17 + ", xx34 = " + xx34); 700 } 701 logln("2DigitYearStart: " + new Date(start) + ", xx17 = " + xx17 + ", xx34 = " + xx34); 702 703 parse2DigitYear(fmt, "6/5/17", new GregorianCalendar(xx17, JUNE, 5).getTime()); 704 parse2DigitYear(fmt, "6/4/34", new GregorianCalendar(xx34, JUNE, 4).getTime()); 705 } 706 yearValue(long start, long end, int year, int month, int dayOfMonth)707 private int yearValue(long start, long end, int year, int month, int dayOfMonth) { 708 Calendar cal = new GregorianCalendar(year, month, dayOfMonth); 709 long time = cal.getTimeInMillis(); 710 return (start <= time && time < end) ? year : 0; 711 } 712 parse2DigitYear(SimpleDateFormat fmt, String str, Date expected)713 private void parse2DigitYear(SimpleDateFormat fmt, String str, Date expected) { 714 try { 715 Date d = fmt.parse(str); 716 logln("Parsing \"" + str + "\" with " + 717 fmt.toPattern() + 718 " => " + d.toString()); 719 if (d.getTime() != expected.getTime()) { 720 errln("FAIL: Expected " + expected); 721 } 722 } catch (ParseException e) { 723 errln("FAIL: Got exception"); 724 } 725 } 726 727 // Test behavior of DateFormat with applied time zone TestDateFormatZone061()728 public void TestDateFormatZone061() 729 { 730 Date date; 731 DateFormat formatter; 732 733 // 25-Mar-97 00:00:00 GMT 734 date = new Date( 859248000000L ); 735 logln( "Date 1997/3/25 00:00 GMT: " + date ); 736 formatter = new SimpleDateFormat("dd-MMM-yyyyy HH:mm", Locale.UK); 737 formatter.setTimeZone( TimeZone.getTimeZone( "GMT" ) ); 738 739 String temp = formatter.format( date ); 740 logln( "Formatted in GMT to: " + temp ); 741 742 /* Parse date string */ 743 try { 744 Date tempDate = formatter.parse( temp ); 745 logln( "Parsed to: " + tempDate ); 746 if (tempDate.getTime() != date.getTime()) { 747 errln("FAIL: Expected " + date); 748 } 749 } 750 catch( Throwable t ) { 751 errln( "Date Formatter throws: " + 752 t.toString() ); 753 } 754 } 755 756 // Make sure DateFormat uses the correct zone. TestDateFormatZone146()757 public void TestDateFormatZone146() 758 { 759 TimeZone saveDefault = TimeZone.getDefault(); 760 761 try { 762 TimeZone thedefault = TimeZone.getTimeZone("GMT"); 763 TimeZone.setDefault(thedefault); 764 // java.util.Locale.setDefault(new java.util.Locale("ar", "", "")); 765 766 // check to be sure... its GMT all right 767 TimeZone testdefault = TimeZone.getDefault(); 768 String testtimezone = testdefault.getID(); 769 if (testtimezone.equals("GMT")) { 770 logln("Test timezone = " + testtimezone); 771 } else { 772 errln("Test timezone should be GMT, not " + testtimezone); 773 } 774 775 // now try to use the default GMT time zone 776 GregorianCalendar greenwichcalendar = 777 new GregorianCalendar(1997, 3, 4, 23, 0); 778 //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault()); 779 //greenwichcalendar.set(1997, 3, 4, 23, 0); 780 // try anything to set hour to 23:00 !!! 781 greenwichcalendar.set(Calendar.HOUR_OF_DAY, 23); 782 // get time 783 Date greenwichdate = greenwichcalendar.getTime(); 784 // format every way 785 String[] DATA = { 786 "simple format: ", "04/04/97 23:00 GMT", 787 "MM/dd/yy HH:mm z", 788 "full format: ", "Friday, April 4, 1997 11:00:00 o'clock PM GMT", 789 "EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z", 790 "long format: ", "April 4, 1997 11:00:00 PM GMT", 791 "MMMM d, yyyy h:mm:ss a z", 792 "default format: ", "04-Apr-97 11:00:00 PM", 793 "dd-MMM-yy h:mm:ss a", 794 "short format: ", "4/4/97 11:00 PM", 795 "M/d/yy h:mm a", 796 }; 797 798 for (int i=0; i<DATA.length; i+=3) { 799 DateFormat fmt = new SimpleDateFormat(DATA[i+2], Locale.ENGLISH); 800 fmt.setCalendar(greenwichcalendar); 801 String result = fmt.format(greenwichdate); 802 logln(DATA[i] + result); 803 if (!result.equals(DATA[i+1])) { 804 errln("FAIL: Expected " + DATA[i+1] 805 + ", got " + result); 806 } 807 } 808 } 809 finally { 810 TimeZone.setDefault(saveDefault); 811 } 812 } 813 814 /* HS : Commented out for now, need to be changed not to use hardcoded results. 815 public void TestLocaleDateFormat() // Bug 495 816 { 817 Date testDate = new Date (97, Calendar.SEPTEMBER, 15); 818 DateFormat dfFrench = DateFormat.getDateTimeInstance(DateFormat.FULL, 819 DateFormat.FULL, Locale.FRENCH); 820 DateFormat dfUS = DateFormat.getDateTimeInstance(DateFormat.FULL, 821 DateFormat.FULL, Locale.US); 822 String expectedFRENCH = "lundi 15 septembre 1997 00 h 00 GMT-07:00"; 823 String expectedUS = "Monday, September 15, 1997 12:00:00 o'clock AM PDT"; 824 logln("Date set to : " + testDate); 825 String out = dfFrench.format(testDate); 826 logln("Date Formated with French Locale " + out); 827 if (!out.equals(expectedFRENCH)) errln("FAIL: Expected " + expectedFRENCH); 828 out = dfUS.format(testDate); 829 logln("Date Formated with US Locale " + out); 830 if (!out.equals(expectedUS)) errln("FAIL: Expected " + expectedUS); 831 } 832 */ 833 /** 834 * Bug 4056591 835 */ 836 /* 837 test commented out pending API-change approval 838 public void Test2YearStartDate() throws ParseException 839 { 840 // create a SimpleDateFormat to test with; dump out if it's not a SimpleDateFormat 841 DateFormat test = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US); 842 843 if (!(test instanceof SimpleDateFormat)) { 844 errln("DateFormat.getInstance() didn't return an instance of SimpleDateFormat!"); 845 return; 846 } 847 848 SimpleDateFormat sdf = (SimpleDateFormat)test; 849 String testString1 = "3/10/67"; 850 String testString2 = "3/16/43"; 851 String testString3 = "7/21/43"; 852 853 // set 2-digit start date to 1/1/1900 854 Calendar cal = Calendar.getInstance(Locale.US); 855 cal.set(1900, 0, 1); 856 sdf.set2DigitStartDate(cal.getTime()); 857 858 // check to make sure get2DigitStartDate() returns the value we passed to 859 // set2DigitStartDate() 860 Date date = sdf.get2DigitStartDate(); 861 cal.setTime(date); 862 if (cal.get(Calendar.YEAR) != 1900 || cal.get(Calendar.MONTH) != 0 || 863 cal.get(Calendar.DATE) != 1) 864 errln("SimpleDateFormat.get2DigitStartDate() returned " + (cal.get(Calendar.MONTH) 865 + 1) + "/" + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR) + 866 " instead of 1/1/1900."); 867 868 // try parsing "3/10/67" and "3/16/43" with the 2-digit start date set to 1/1/1900 869 date = sdf.parse(testString1); 870 cal.setTime(date); 871 if (cal.get(Calendar.YEAR) != 1967) 872 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/1900 yielded a year of " 873 + cal.get(Calendar.YEAR) + " instead of 1967."); 874 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 10) 875 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/1900 failed: got " + 876 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 877 " instead of 3/10."); 878 date = sdf.parse(testString2); 879 cal.setTime(date); 880 if (cal.get(Calendar.YEAR) != 1943) 881 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/1900 yielded a year of " 882 + cal.get(Calendar.YEAR) + " instead of 1943."); 883 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 16) 884 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/1900 failed: got " + 885 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 886 " instead of 3/16."); 887 888 // try parsing "3/10/67" and "3/16/43" with the 2-digit start date set to 1/1/2000 889 cal.set(2000, 0, 1); 890 sdf.set2DigitStartDate(cal.getTime()); 891 date = sdf.parse(testString1); 892 cal.setTime(date); 893 if (cal.get(Calendar.YEAR) != 2067) 894 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/2000 yielded a year of " 895 + cal.get(Calendar.YEAR) + " instead of 2067."); 896 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 10) 897 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/2000 failed: got " + 898 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 899 " instead of 3/10."); 900 date = sdf.parse(testString2); 901 cal.setTime(date); 902 if (cal.get(Calendar.YEAR) != 2043) 903 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/2000 yielded a year of " 904 + cal.get(Calendar.YEAR) + " instead of 1943."); 905 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 16) 906 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/2000 failed: got " + 907 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 908 " instead of 3/16."); 909 910 // try parsing "3/10/67" and "3/16/43" with the 2-digit start date set to 1/1/1950 911 cal.set(1950, 0, 1); 912 sdf.set2DigitStartDate(cal.getTime()); 913 date = sdf.parse(testString1); 914 cal.setTime(date); 915 if (cal.get(Calendar.YEAR) != 1967) 916 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/1950 yielded a year of " 917 + cal.get(Calendar.YEAR) + " instead of 1967."); 918 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 10) 919 errln("Parsing \"3/10/67\" with 2-digit start date set to 1/1/1950 failed: got " + 920 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 921 " instead of 3/10."); 922 date = sdf.parse(testString2); 923 cal.setTime(date); 924 if (cal.get(Calendar.YEAR) != 2043) 925 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/1950 yielded a year of " 926 + cal.get(Calendar.YEAR) + " instead of 1943."); 927 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 16) 928 errln("Parsing \"3/16/43\" with 2-digit start date set to 1/1/1950 failed: got " + 929 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 930 " instead of 3/16."); 931 932 // try parsing "3/16/43" and "7/21/43" with the 2-digit start date set to 6/1/1943 933 cal.set(1943, 5, 1); 934 sdf.set2DigitStartDate(cal.getTime()); 935 date = sdf.parse(testString2); 936 cal.setTime(date); 937 if (cal.get(Calendar.YEAR) != 2043) 938 errln("Parsing \"3/16/43\" with 2-digit start date set to 6/1/1943 yielded a year of " 939 + cal.get(Calendar.YEAR) + " instead of 2043."); 940 if (cal.get(Calendar.MONTH) != 2 || cal.get(Calendar.DATE) != 16) 941 errln("Parsing \"3/16/43\" with 2-digit start date set to 6/1/1943 failed: got " + 942 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 943 " instead of 3/16."); 944 date = sdf.parse(testString3); 945 cal.setTime(date); 946 if (cal.get(Calendar.YEAR) != 1943) 947 errln("Parsing \"7/21/43\" with 2-digit start date set to 6/1/1943 yielded a year of " 948 + cal.get(Calendar.YEAR) + " instead of 1943."); 949 if (cal.get(Calendar.MONTH) != 6 || cal.get(Calendar.DATE) != 21) 950 errln("Parsing \"7/21/43\" with 2-digit start date set to 6/1/1943 failed: got " + 951 (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE) + 952 " instead of 7/21."); 953 954 // and finally, check one more time to make sure get2DigitStartDate() returns the last 955 // value we passed to set2DigitStartDate() 956 date = sdf.get2DigitStartDate(); 957 cal.setTime(date); 958 if (cal.get(Calendar.YEAR) != 1943 || cal.get(Calendar.MONTH) != 5 || 959 cal.get(Calendar.DATE) != 1) 960 errln("SimpleDateFormat.get2DigitStartDate() returned " + (cal.get(Calendar.MONTH) 961 + 1) + "/" + cal.get(Calendar.DATE) + "/" + cal.get(Calendar.YEAR) + 962 " instead of 6/1/1943."); 963 } 964 */ 965 966 /** 967 * ParsePosition.errorIndex tests. 968 */ 969 @SuppressWarnings("deprecation") Test4052223()970 public void Test4052223() 971 { 972 String str = "7/SOS/2001"; 973 Date exp = new Date(101, Calendar.SEPTEMBER, 7); 974 String pat = "d/MMM/yy"; 975 SimpleDateFormat sdf = new SimpleDateFormat(pat); 976 ParsePosition pos = new ParsePosition(0); 977 Date d = sdf.parse(str, pos); 978 logln(str + " parses with " + pat + " to " + d); 979 if (d == null && pos.getErrorIndex() == 2) { 980 logln("Expected null returned, failed at : " + pos.getErrorIndex()); 981 } else { 982 errln("Failed, parse " + str + " got : " + d + ", index=" + pos.getErrorIndex()); 983 } 984 } 985 986 /** 987 * Bug4469904 -- th_TH date format doesn't use Thai B.E. 988 */ TestBuddhistEraBugId4469904()989 public void TestBuddhistEraBugId4469904() { 990 String era = "\u0e1e.\u0e28."; 991 Locale loc = new Locale("th", "TH"); 992 Calendar cal = Calendar.getInstance(Locale.US); 993 cal.set(2001, 7, 23); 994 Date date = cal.getTime(); 995 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, loc); 996 String output = df.format(date); 997 int index = output.indexOf(era); 998 if (index == -1) { 999 errln("Test4469904: Failed. Buddhist Era abbrev not present."); 1000 } 1001 } 1002 1003 /** 1004 * 4326988: API: SimpleDateFormat throws NullPointerException when parsing with null pattern 1005 */ 1006 @SuppressWarnings("UnusedAssignment") Test4326988()1007 public void Test4326988() { 1008 String[] wrongPatterns = { 1009 "hh o''clock", 1010 "hh 'o''clock", // unterminated quote 1011 "''''''''''''oclock", 1012 "efgxyz", 1013 }; 1014 String[] goodPatterns = { 1015 "hh 'o''clock'", 1016 "'''''''''''''o'", 1017 "'efgxyz'", 1018 ":;,.-", 1019 }; 1020 1021 // Check NullPointerException 1022 try { 1023 SimpleDateFormat fmt = new SimpleDateFormat(null); 1024 errln("SimpleDateFormat() doesn't throw NPE with null pattern"); 1025 } catch (NullPointerException e) { 1026 // Okay 1027 } 1028 try { 1029 Locale loc = null; 1030 SimpleDateFormat fmt = new SimpleDateFormat("yyyy/MM/dd", loc); 1031 errln("SimpleDateFormat() doesn't throw NPE with null locale"); 1032 } catch (NullPointerException e) { 1033 // Okay 1034 } 1035 try { 1036 DateFormatSymbols symbols = null; 1037 SimpleDateFormat fmt = new SimpleDateFormat("yyyy/MM/dd", symbols); 1038 errln("SimpleDateFormat() doesn't throw NPE with null DateFormatSymbols"); 1039 } catch (NullPointerException e) { 1040 // Okay 1041 } 1042 try { 1043 SimpleDateFormat fmt = new SimpleDateFormat(); 1044 fmt.applyPattern(null); 1045 errln("applyPattern() doesn't throw NPE with null pattern"); 1046 } catch (NullPointerException e) { 1047 // Okay 1048 } 1049 1050 // Check IllegalParameterException 1051 for (int i = 0; i < wrongPatterns.length; i++) { 1052 try { 1053 SimpleDateFormat fmt = new SimpleDateFormat(wrongPatterns[i]); 1054 errln("SimpleDateFormat(\"" + wrongPatterns[i] + "\")" + 1055 " doesn't throw an IllegalArgumentException"); 1056 } catch (IllegalArgumentException e) { 1057 // Okay 1058 } 1059 try { 1060 SimpleDateFormat fmt = new SimpleDateFormat(wrongPatterns[i], 1061 DateFormatSymbols.getInstance()); 1062 errln("SimpleDateFormat(\"" + wrongPatterns[i] + "\", DateFormatSymbols) doesn't " + 1063 "throw an IllegalArgumentException"); 1064 } catch (IllegalArgumentException e) { 1065 // Okay 1066 } 1067 try { 1068 SimpleDateFormat fmt = new SimpleDateFormat(wrongPatterns[i], 1069 Locale.US); 1070 errln("SimpleDateFormat(\"" + wrongPatterns[i] + 1071 "\", Locale) doesn't throw an IllegalArgumentException"); 1072 } catch (IllegalArgumentException e) { 1073 // Okay 1074 } 1075 try { 1076 SimpleDateFormat fmt = new SimpleDateFormat(); 1077 fmt.applyPattern(wrongPatterns[i]); 1078 errln("SimpleDateFormat.applyPattern(\"" + wrongPatterns[i] + 1079 "\") doesn't throw an IllegalArgumentException"); 1080 } catch (IllegalArgumentException e) { 1081 // Okay 1082 } 1083 } 1084 1085 for (int i = 0; i < goodPatterns.length; i++) { 1086 SimpleDateFormat fmt; 1087 fmt = new SimpleDateFormat(goodPatterns[i]); 1088 fmt = new SimpleDateFormat(goodPatterns[i], 1089 DateFormatSymbols.getInstance()); 1090 fmt = new SimpleDateFormat(goodPatterns[i], 1091 Locale.US); 1092 fmt = new SimpleDateFormat(); 1093 fmt.applyPattern(goodPatterns[i]); 1094 } 1095 } 1096 1097 /** 1098 * 4486735: RFE: SimpleDateFormat performance improvement 1099 * 1100 * Another round trip test 1101 */ 1102 @SuppressWarnings("deprecation") Test4486735()1103 public void Test4486735() throws Exception { 1104 TimeZone initialTimeZone = TimeZone.getDefault(); 1105 TimeZone.setDefault(TimeZone.getTimeZone("GMT")); 1106 Locale[] locales = Locale.getAvailableLocales(); 1107 String[] zones = { "GMT", "America/Los_Angeles", "Europe/London", "Asia/Tokyo" }; 1108 1109 // Round to minutes. Some FULL formats don't have seconds. 1110 long time = System.currentTimeMillis()/60000 * 60000; 1111 Date date = new Date(time); 1112 logln("the test date: " + date); 1113 1114 try { 1115 for (int z = 0; z < zones.length; z++) { 1116 TimeZone.setDefault(TimeZone.getTimeZone(zones[z])); 1117 for (int i = 0; i < locales.length; i++) { 1118 Locale loc = locales[i]; 1119 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, 1120 DateFormat.FULL, 1121 loc); 1122 String s = df.format(date); 1123 logln(s); 1124 Date parsedDate = df.parse(s); 1125 long parsedTime = parsedDate.getTime(); 1126 if (time != parsedTime) { 1127 // See if the time is in daylight-standard time transition. (JDK-8140571) 1128 // Date-time formats in some locales don't have time zone information. 1129 TimeZone tz = TimeZone.getDefault(); 1130 if (tz.inDaylightTime(date) && !tz.inDaylightTime(parsedDate)) { 1131 if (time == parsedTime - tz.getDSTSavings()) { 1132 // OK (in "fall-back") 1133 continue; 1134 } 1135 } 1136 errln("round trip conversion failed: timezone="+zones[z]+ 1137 ", locale=" + loc + 1138 ", expected=" + time + ", got=" + parsedTime); 1139 } 1140 } 1141 } 1142 1143 // Long format test 1144 String pat = 1145 "'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // 100 1146 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1147 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // 200 1148 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1149 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // 300 1150 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1151 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // 400 1152 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1153 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // 500 1154 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'" + 1155 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1156 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1157 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1158 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593':'" + 1159 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1160 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + // 100 1161 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + 1162 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + // 200 1163 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + 1164 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" + // 300 1165 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\u5e74"; 1166 1167 // Note that >4 y's produces just "2001" until 1.3.1. This 1168 // was fixed in 1.4. 1169 String expected = 1170 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1171 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1172 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1173 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1174 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1175 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1176 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1177 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1178 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1179 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 1180 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1181 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1182 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1183 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1184 "\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:\u6642\u9593:" + 1185 "00000000000000000000000000000000000000000000000000" + 1186 "00000000000000000000000000000000000000000000000000" + 1187 "00000000000000000000000000000000000000000000000000" + 1188 "00000000000000000000000000000000000000000000000000" + 1189 "00000000000000000000000000000000000000000000000000" + 1190 "00000000000000000000000000000000000000000000002001\u5e74"; 1191 SimpleDateFormat sdf = new SimpleDateFormat(pat); 1192 String s = sdf.format(new Date(2001-1900, Calendar.JANUARY, 1)); 1193 if (!expected.equals(s)) { 1194 errln("wrong format result: expected="+expected+", got="+s); 1195 } 1196 Date longday = sdf.parse(s); 1197 GregorianCalendar cal = new GregorianCalendar(); 1198 cal.setTime(longday); 1199 if (cal.get(YEAR) != 2001) { 1200 errln("wrong parse result: expected=2001, got=" + cal.get(YEAR)); 1201 } 1202 } catch (Exception e) { 1203 throw e; 1204 } finally { 1205 // Restore the initial time zone 1206 TimeZone.setDefault(initialTimeZone); 1207 } 1208 } 1209 Test8216969()1210 public void Test8216969() throws Exception { 1211 Locale locale = new Locale("ru"); 1212 String format = "\u0434\u0435\u043a"; 1213 String standalone = "\u0434\u0435\u043a."; 1214 1215 // Check that format form is used so that the dot is parsed correctly. 1216 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd MMM.yyyy", locale); 1217 System.out.println(simpleDateFormat.parse("28 " + format + ".2018")); 1218 1219 // Check that standalone form is used. 1220 simpleDateFormat = new SimpleDateFormat("MMM", locale); 1221 System.out.println(simpleDateFormat.parse(standalone)); 1222 } 1223 } 1224