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