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