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