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