1 /*
   2  * Copyright (c) 1998, 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 import java.text.*;
  25 import java.util.*;
  26 import java.io.*;
  27 
  28 import org.junit.jupiter.api.Test;
  29 
  30 import static org.junit.jupiter.api.Assertions.fail;
  31 
  32 /**
  33  * @test
  34  * @bug 4029195 4052408 4056591 4059917 4060212 4061287 4065240 4071441 4073003
  35  * 4089106 4100302 4101483 4103340 4103341 4104136 4104522 4106807 4108407
  36  * 4134203 4138203 4148168 4151631 4151706 4153860 4162071 4182066 4209272 4210209
  37  * 4213086 4250359 4253490 4266432 4406615 4413980 8008577 8305853
  38  * @library /java/text/testlib
  39  * @run junit/othervm -Djava.locale.providers=COMPAT,SPI DateFormatRegression
  40  */
  41 public class DateFormatRegression {
  42 
  43     @Test
  44     public void Test4029195() {
  45         @SuppressWarnings("deprecation")
  46         Date today = new Date();
  47 
  48         System.out.println("today: " + today);
  49 
  50         SimpleDateFormat sdf = (SimpleDateFormat)SimpleDateFormat.getDateInstance();
  51         System.out.println("pattern: " + sdf.toPattern());
  52         System.out.println("today: " + sdf.format(today));
  53 
  54         sdf.applyPattern("G yyyy DDD");
  55         String todayS = sdf.format(today);
  56         System.out.println("today: " + todayS);
  57         try {
  58             today = sdf.parse(todayS);
  59             System.out.println("today date: " + today);
  60         } catch(Exception e) {
  61             System.out.println("Error reparsing date: " + e.getMessage());
  62         }
  63 
  64         try {
  65             String rt = sdf.format(sdf.parse(todayS));
  66             System.out.println("round trip: " + rt);
  67             if (!rt.equals(todayS)) fail("Fail: Want " + todayS + " Got " + rt);
  68         }
  69         catch (ParseException e) {
  70             fail("Fail: " + e);
  71             e.printStackTrace();
  72         }
  73     }
  74 
  75     @Test
  76     public void Test4052408() {
  77         DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT,
  78                                                         DateFormat.SHORT, Locale.US);
  79         @SuppressWarnings("deprecation")
  80         Date date = new Date(97, Calendar.MAY, 3, 8, 55);
  81         String str;
  82         System.out.println(str = fmt.format(date));
  83 
  84         if (!str.equals("5/3/97 8:55 AM"))
  85             fail("Fail: Test broken; Want 5/3/97 8:55 AM Got " + str);
  86         Map<Integer,String> expected = new HashMap<>();
  87         expected.put(DateFormat.MONTH_FIELD, "5");
  88         expected.put(DateFormat.DATE_FIELD, "3");
  89         expected.put(DateFormat.YEAR_FIELD, "97");
  90         expected.put(DateFormat.HOUR1_FIELD, "8");
  91         expected.put(DateFormat.MINUTE_FIELD, "55");
  92         expected.put(DateFormat.AM_PM_FIELD, "AM");
  93 
  94         StringBuffer buf = new StringBuffer();
  95         String fieldNames[] = {
  96             "ERA_FIELD",
  97             "YEAR_FIELD",
  98             "MONTH_FIELD",
  99             "DATE_FIELD",
 100             "HOUR_OF_DAY1_FIELD",
 101             "HOUR_OF_DAY0_FIELD",
 102             "MINUTE_FIELD",
 103             "SECOND_FIELD",
 104             "MILLISECOND_FIELD",
 105             "DAY_OF_WEEK_FIELD",
 106             "DAY_OF_YEAR_FIELD",
 107             "DAY_OF_WEEK_IN_MONTH_FIELD",
 108             "WEEK_OF_YEAR_FIELD",
 109             "WEEK_OF_MONTH_FIELD",
 110             "AM_PM_FIELD",
 111             "HOUR1_FIELD",
 112             "HOUR0_FIELD",
 113             "TIMEZONE_FIELD",
 114         };
 115         boolean pass = true;
 116         for (int i=0; i<=17; ++i) {
 117             FieldPosition pos = new FieldPosition(i);
 118             fmt.format(date, buf, pos);
 119             char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()];
 120             buf.getChars(pos.getBeginIndex(), pos.getEndIndex(), dst, 0);
 121             str = new String(dst);
 122             System.out.println(i + ": " + fieldNames[i] +
 123                              ", \"" + str + "\", " +
 124                              pos.getBeginIndex() + ", " +
 125                              pos.getEndIndex());
 126             String exp = expected.get(i);
 127             if ((exp == null && str.length() == 0) ||
 128                 str.equals(exp))
 129                 System.out.println(" ok");
 130             else {
 131                 System.out.println(" expected " + exp);
 132                 pass = false;
 133             }
 134         }
 135         if (!pass) fail("Fail: FieldPosition not set right by DateFormat");
 136     }
 137 
 138     /**
 139      * Verify the function of the [s|g]et2DigitYearStart() API.
 140      */
 141     @SuppressWarnings("deprecation")
 142     @Test
 143     public void Test4056591() {
 144         try {
 145             SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd", Locale.US);
 146             Date start = new Date(1809-1900, Calendar.DECEMBER, 25);
 147             fmt.set2DigitYearStart(start);
 148             if (!fmt.get2DigitYearStart().equals(start))
 149                 fail("get2DigitYearStart broken");
 150             Object[] DATA = {
 151                 "091225", new Date(1809-1900, Calendar.DECEMBER, 25),
 152                 "091224", new Date(1909-1900, Calendar.DECEMBER, 24),
 153                 "091226", new Date(1809-1900, Calendar.DECEMBER, 26),
 154                 "611225", new Date(1861-1900, Calendar.DECEMBER, 25),
 155             };
 156             for (int i=0; i<DATA.length; i+=2) {
 157                 String s = (String) DATA[i];
 158                 Date exp = (Date) DATA[i+1];
 159                 Date got = fmt.parse(s);
 160                 System.out.println(s + " -> " + got + "; exp " + exp);
 161                 if (!got.equals(exp)) fail("set2DigitYearStart broken");
 162             }
 163         }
 164         catch (ParseException e) {
 165             fail("Fail: " + e);
 166             e.printStackTrace();
 167         }
 168     }
 169 
 170     @Test
 171     public void Test4059917() {
 172         Locale locale = Locale.getDefault();
 173         if (!TestUtils.usesAsciiDigits(locale)) {
 174             System.out.println("Skipping this test because locale is " + locale);
 175             return;
 176         }
 177 
 178         SimpleDateFormat fmt;
 179         String myDate;
 180 
 181         fmt = new SimpleDateFormat( "yyyy/MM/dd" );
 182         myDate = "1997/01/01";
 183         aux917( fmt, myDate );
 184 
 185         fmt = new SimpleDateFormat( "yyyyMMdd" );
 186         myDate = "19970101";
 187         aux917( fmt, myDate );
 188     }
 189 
 190     void aux917( SimpleDateFormat fmt, String str ) {
 191         try {
 192             System.out.println( "==================" );
 193             System.out.println( "testIt: pattern=" + fmt.toPattern() +
 194                    " string=" + str );
 195 
 196             Object o;
 197             o = fmt.parseObject( str );
 198             System.out.println( "Parsed object: " + o );
 199 
 200             String formatted = fmt.format( o );
 201             System.out.println( "Formatted string: " + formatted );
 202             if (!formatted.equals(str)) fail("Fail: Want " + str + " Got " + formatted);
 203         }
 204         catch (ParseException e) {
 205             fail("Fail: " + e);
 206             e.printStackTrace();
 207         }
 208     }
 209 
 210     @Test
 211     public void Test4060212() {
 212       Locale savedLocale = Locale.getDefault();
 213       Locale.setDefault(Locale.US);
 214       try {
 215         String dateString = "1995-040.05:01:29";
 216 
 217         System.out.println( "dateString= " + dateString );
 218         System.out.println("Using yyyy-DDD.hh:mm:ss");
 219         SimpleDateFormat formatter = new SimpleDateFormat("yyyy-DDD.hh:mm:ss");
 220         ParsePosition pos = new ParsePosition(0);
 221         Date myDate = formatter.parse( dateString, pos );
 222         String myString = DateFormat.getDateTimeInstance( DateFormat.FULL,
 223                                                           DateFormat.LONG).format( myDate );
 224         System.out.println( myString );
 225         Calendar cal = new GregorianCalendar();
 226         cal.setTime(myDate);
 227         if (cal.get(Calendar.DAY_OF_YEAR) != 40)
 228             fail("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) +
 229                                 " Want 40");
 230 
 231         System.out.println("Using yyyy-ddd.hh:mm:ss");
 232         formatter = new SimpleDateFormat("yyyy-ddd.hh:mm:ss");
 233         pos = new ParsePosition(0);
 234         myDate = formatter.parse( dateString, pos );
 235         myString = DateFormat.getDateTimeInstance( DateFormat.FULL,
 236                                                    DateFormat.LONG).format( myDate );
 237         System.out.println( myString );
 238         cal.setTime(myDate);
 239         if (cal.get(Calendar.DAY_OF_YEAR) != 40)
 240             fail("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) +
 241                                 " Want 40");
 242       }
 243       finally {
 244          Locale.setDefault(savedLocale);
 245       }
 246     }
 247 
 248     @Test
 249     public void Test4061287() {
 250         SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
 251         try {
 252             System.out.println(df.parse("35/01/1971").toString());
 253         }
 254         catch (ParseException e) {
 255             fail("Fail: " + e);
 256             e.printStackTrace();
 257         }
 258         df.setLenient(false);
 259         boolean ok = false;
 260         try {
 261             System.out.println(df.parse("35/01/1971").toString());
 262         } catch (ParseException e) {ok=true;}
 263         if (!ok) fail("Fail: Lenient not working");
 264     }
 265 
 266     @SuppressWarnings("deprecation")
 267     @Test
 268     public void Test4065240() {
 269         Date curDate;
 270         DateFormat shortdate, fulldate;
 271         String strShortDate, strFullDate;
 272         Locale saveLocale = Locale.getDefault();
 273         TimeZone saveZone = TimeZone.getDefault();
 274         try {
 275             Locale curLocale = Locale.GERMANY;
 276             Locale.setDefault(curLocale);
 277             TimeZone.setDefault(TimeZone.getTimeZone("EST"));
 278             curDate = new Date(98, 0, 1);
 279             shortdate = DateFormat.getDateInstance(DateFormat.SHORT);
 280             fulldate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG
 281                                                       );
 282             strShortDate = new String("The current date (short form) is " + shortdate.
 283                                       format(curDate));
 284             strFullDate = new String("The current date (long form) is " + fulldate.format(curDate));
 285 
 286             System.out.println(strShortDate);
 287             System.out.println(strFullDate);
 288 
 289             // UPDATE THIS AS ZONE NAME RESOURCE FOR <EST> in de_DE is updated
 290             if (!strFullDate.endsWith("EST")
 291                     && !strFullDate.endsWith("GMT-05:00")) {
 292                 fail("Fail: Want GMT-05:00");
 293             }
 294         }
 295         finally {
 296             Locale.setDefault(saveLocale);
 297             TimeZone.setDefault(saveZone);
 298         }
 299     }
 300 
 301     /*
 302       DateFormat.equals is too narrowly defined.  As a result, MessageFormat
 303       does not work correctly.  DateFormat.equals needs to be written so
 304       that the Calendar sub-object is not compared using Calendar.equals,
 305       but rather compared for equivalency.  This may necessitate adding a
 306       (package private) method to Calendar to test for equivalency.
 307 
 308       Currently this bug breaks MessageFormat.toPattern
 309       */
 310     @SuppressWarnings("deprecation")
 311     @Test
 312     public void Test4071441() {
 313         DateFormat fmtA = DateFormat.getInstance();
 314         DateFormat fmtB = DateFormat.getInstance();
 315         Calendar calA = fmtA.getCalendar();
 316         Calendar calB = fmtB.getCalendar();
 317         Date epoch = new Date(0);
 318         Date xmas = new Date(61, Calendar.DECEMBER, 25);
 319         calA.setTime(epoch);
 320         calB.setTime(epoch);
 321         if (!calA.equals(calB))
 322             fail("Fail: Can't complete test; Calendar instances unequal");
 323         if (!fmtA.equals(fmtB))
 324             fail("Fail: DateFormat unequal when Calendars equal");
 325         calB.setTime(xmas);
 326         if (calA.equals(calB))
 327             fail("Fail: Can't complete test; Calendar instances equal");
 328         if (!fmtA.equals(fmtB))
 329             fail("Fail: DateFormat unequal when Calendars equivalent");
 330         System.out.println("DateFormat.equals ok");
 331     }
 332 
 333     /* The java.text.DateFormat.parse(String) method expects for the
 334       US locale a string formatted according to mm/dd/yy and parses it
 335       correctly.
 336 
 337       When given a string mm/dd/yyyy it only parses up to the first
 338       two y's, typically resulting in a date in the year 1919.
 339 
 340       Please extend the parsing method(s) to handle strings with
 341       four-digit year values (probably also applicable to various
 342       other locales.  */
 343     @Test
 344     public void Test4073003() {
 345         try {
 346             DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
 347             String[] tests = { "12/25/61", "12/25/1961", "4/3/2010", "4/3/10" };
 348             for (int i=0; i<tests.length; i+=2) {
 349                 Date d = fmt.parse(tests[i]);
 350                 Date dd = fmt.parse(tests[i+1]);
 351                 String s = fmt.format(d);
 352                 String ss = fmt.format(dd);
 353                 if (!d.equals(dd))
 354                     fail("Fail: " + d + " != " + dd);
 355                 if (!s.equals(ss))
 356                     fail("Fail: " + s + " != " + ss);
 357                 System.out.println("Ok: " + s + " " + d);
 358             }
 359         }
 360         catch (ParseException e) {
 361             fail("Fail: " + e);
 362             e.printStackTrace();
 363         }
 364     }
 365 
 366     @Test
 367     public void Test4089106() {
 368         TimeZone def = TimeZone.getDefault();
 369         try {
 370             TimeZone customTz = TimeZone.getTimeZone("GMT-08:15");
 371             TimeZone.setDefault(customTz);
 372             SimpleDateFormat f = new SimpleDateFormat();
 373             if (!f.getTimeZone().equals(customTz))
 374                 fail("Fail: SimpleDateFormat should use TimeZone.getDefault()");
 375         }
 376         finally {
 377             TimeZone.setDefault(def);
 378         }
 379     }
 380 
 381     @Test
 382     public void Test4100302() {
 383         Locale[] locales = new Locale[] {
 384             Locale.CANADA,
 385             Locale.CANADA_FRENCH,
 386             Locale.CHINA,
 387             Locale.CHINESE,
 388             Locale.ENGLISH,
 389             Locale.FRANCE,
 390             Locale.FRENCH,
 391             Locale.GERMAN,
 392             Locale.GERMANY,
 393             Locale.ITALIAN,
 394             Locale.ITALY,
 395             Locale.JAPAN,
 396             Locale.JAPANESE,
 397             Locale.KOREA,
 398             Locale.KOREAN,
 399             Locale.PRC,
 400             Locale.SIMPLIFIED_CHINESE,
 401             Locale.TAIWAN,
 402             Locale.TRADITIONAL_CHINESE,
 403             Locale.UK,
 404             Locale.US
 405             };
 406         try {
 407             boolean pass = true;
 408             for(int i = 0; i < locales.length; i++) {
 409 
 410                 Format format = DateFormat.getDateTimeInstance(DateFormat.FULL,
 411                                                                DateFormat.FULL, locales[i]);
 412                 byte[] bytes;
 413 
 414                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 415                 ObjectOutputStream oos = new ObjectOutputStream(baos);
 416 
 417                 oos.writeObject(format);
 418                 oos.flush();
 419 
 420                 baos.close();
 421                 bytes = baos.toByteArray();
 422 
 423                 ObjectInputStream ois =
 424                     new ObjectInputStream(new ByteArrayInputStream(bytes));
 425 
 426                 if (!format.equals(ois.readObject())) {
 427                     pass = false;
 428                     System.out.println("DateFormat instance for locale " +
 429                           locales[i] + " is incorrectly serialized/deserialized.");
 430                 } else {
 431                     System.out.println("DateFormat instance for locale " +
 432                           locales[i] + " is OKAY.");
 433                 }
 434             }
 435             if (!pass) fail("Fail: DateFormat serialization/equality bug");
 436         }
 437         catch (IOException e) {
 438             fail("Fail: " + e);
 439             e.printStackTrace();
 440         }
 441         catch (ClassNotFoundException e) {
 442             fail("Fail: " + e);
 443             e.printStackTrace();
 444         }
 445     }
 446 
 447     /**
 448      * Test whether DataFormat can be serialized/deserialized correctly
 449      * even if invalid/customized TimeZone is used.
 450      */
 451     @Test
 452     public void Test4413980() {
 453         TimeZone savedTimeZone = TimeZone.getDefault();
 454         try {
 455             boolean pass = true;
 456             String[] IDs = new String[] {"Undefined", "PST", "US/Pacific",
 457                                          "GMT+3:00", "GMT-01:30"};
 458             for (int i = 0; i < IDs.length; i++) {
 459                 TimeZone tz = TimeZone.getTimeZone(IDs[i]);
 460                 TimeZone.setDefault(tz);
 461 
 462                 Format format = DateFormat.getDateTimeInstance(DateFormat.FULL,
 463                                                                DateFormat.FULL);
 464                 byte[] bytes;
 465 
 466                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 467                 ObjectOutputStream oos = new ObjectOutputStream(baos);
 468 
 469                 oos.writeObject(format);
 470                 oos.flush();
 471 
 472                 baos.close();
 473                 bytes = baos.toByteArray();
 474 
 475                 ObjectInputStream ois =
 476                     new ObjectInputStream(new ByteArrayInputStream(bytes));
 477 
 478                 if (!format.equals(ois.readObject())) {
 479                     pass = false;
 480                     System.out.println("DateFormat instance which uses TimeZone <" +
 481                           IDs[i] + "> is incorrectly serialized/deserialized.");
 482                 } else {
 483                     System.out.println("DateFormat instance which uses TimeZone <" +
 484                           IDs[i] + "> is correctly serialized/deserialized.");
 485                 }
 486             }
 487             if (!pass) {
 488                 fail("Fail: DateFormat serialization/equality bug");
 489             }
 490         }
 491         catch (IOException e) {
 492             fail("Fail: " + e);
 493             e.printStackTrace();
 494         }
 495         catch (ClassNotFoundException e) {
 496             fail("Fail: " + e);
 497             e.printStackTrace();
 498         }
 499         finally {
 500             TimeZone.setDefault(savedTimeZone);
 501         }
 502     }
 503 
 504     @Test
 505     public void Test4101483() {
 506         SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.US);
 507         FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD);
 508         @SuppressWarnings("deprecation")
 509         Date d= new Date(9234567890L);
 510         StringBuffer buf = new StringBuffer("");
 511         System.out.println(sdf.format(d, buf, fp).toString());
 512         System.out.println(d + " => " + buf);
 513         System.out.println("beginIndex = " + fp.getBeginIndex());
 514         System.out.println("endIndex = " + fp.getEndIndex());
 515         if (fp.getBeginIndex() == fp.getEndIndex()) fail("Fail: Empty field");
 516     }
 517 
 518     /**
 519      * Bug 4103340
 520      * Bug 4138203
 521      * This bug really only works in Locale.US, since that's what the locale
 522      * used for Date.toString() is.  Bug 4138203 reports that it fails on Korean
 523      * NT; it would actually have failed on any non-US locale.  Now it should
 524      * work on all locales.
 525      */
 526     @Test
 527     public void Test4103340() {
 528         // choose a date that is the FIRST of some month
 529         // and some arbitrary time
 530         @SuppressWarnings("deprecation")
 531         Date d=new Date(97, 3, 1, 1, 1, 1);
 532         SimpleDateFormat df=new SimpleDateFormat("MMMM", Locale.US);
 533 
 534         String s = d.toString();
 535         String s2 = df.format(d);
 536         System.out.println("Date="+s);
 537         System.out.println("DF="+s2);
 538         if (s.indexOf(s2.substring(0,2)) == -1)
 539             fail("Months should match");
 540     }
 541 
 542     @Test
 543     public void Test4103341() {
 544         TimeZone saveZone  =TimeZone.getDefault();
 545         try {
 546             TimeZone.setDefault(TimeZone.getTimeZone("CST"));
 547             SimpleDateFormat simple = new SimpleDateFormat("MM/dd/yyyy HH:mm");
 548             if (!simple.getTimeZone().equals(TimeZone.getDefault()))
 549                 fail("Fail: SimpleDateFormat not using default zone");
 550         }
 551         finally {
 552             TimeZone.setDefault(saveZone);
 553         }
 554     }
 555 
 556     @Test
 557     public void Test4104136() {
 558         SimpleDateFormat sdf = new SimpleDateFormat();
 559         String pattern = "'time' hh:mm";
 560         sdf.applyPattern(pattern);
 561         System.out.println("pattern: \"" + pattern + "\"");
 562 
 563         @SuppressWarnings("deprecation")
 564         Object[] DATA = {
 565             "time 10:30", new ParsePosition(10), new Date(70, Calendar.JANUARY, 1, 10, 30),
 566             "time 10:x", new ParsePosition(0), null,
 567             "time 10x", new ParsePosition(0), null,
 568         };
 569         for (int i=0; i<DATA.length; i+=3) {
 570             String text = (String) DATA[i];
 571             ParsePosition finish = (ParsePosition) DATA[i+1];
 572             Date exp = (Date) DATA[i+2];
 573 
 574             ParsePosition pos = new ParsePosition(0);
 575             Date d = sdf.parse(text, pos);
 576             System.out.println(" text: \"" + text + "\"");
 577             System.out.println(" index: " + pos.getIndex());
 578             System.out.println(" result: " + d);
 579             if (pos.getIndex() != finish.getIndex())
 580                 fail("Fail: Expected pos " + finish.getIndex());
 581             if (!((d == null && exp == null) ||
 582                   d.equals(exp)))
 583                 fail("Fail: Expected result " + exp);
 584         }
 585     }
 586 
 587     /**
 588      * CANNOT REPRODUCE
 589      * According to the bug report, this test should throw a
 590      * StringIndexOutOfBoundsException during the second parse.  However,
 591      * this is not seen.
 592      */
 593     @Test
 594     public void Test4104522() {
 595         SimpleDateFormat sdf = new SimpleDateFormat();
 596         String pattern = "'time' hh:mm";
 597         sdf.applyPattern(pattern);
 598         System.out.println("pattern: \"" + pattern + "\"");
 599 
 600         // works correctly
 601         ParsePosition pp = new ParsePosition(0);
 602         String text = "time ";
 603         Date date = sdf.parse(text, pp);
 604         System.out.println(" text: \"" + text + "\"" +
 605               " date: " + date);
 606 
 607         // works wrong
 608         pp = new ParsePosition(0);
 609         text = "time";
 610         date = sdf.parse(text, pp);
 611         System.out.println(" text: \"" + text + "\"" +
 612               " date: " + date);
 613     }
 614 
 615     @Test
 616     public void Test4106807() {
 617         Date date;
 618         DateFormat df = DateFormat.getDateTimeInstance();
 619         Object[] data = {
 620             new SimpleDateFormat("yyyyMMddHHmmss"),       "19980211140000",
 621             new SimpleDateFormat("yyyyMMddHHmmss'Z'"),    "19980211140000",
 622             new SimpleDateFormat("yyyyMMddHHmmss''"),     "19980211140000",
 623             new SimpleDateFormat("yyyyMMddHHmmss'a''a'"), "19980211140000a",
 624             new SimpleDateFormat("yyyyMMddHHmmss %"),     "19980211140000 ",
 625         };
 626         GregorianCalendar gc = new GregorianCalendar();
 627         TimeZone timeZone = TimeZone.getDefault();
 628 
 629         TimeZone gmt = (TimeZone)timeZone.clone();
 630 
 631         gmt.setRawOffset(0);
 632 
 633         for (int i=0; i<data.length; i+=2) {
 634             SimpleDateFormat format = (SimpleDateFormat) data[i];
 635             String dateString = (String) data[i+1];
 636             try {
 637                 format.setTimeZone(gmt);
 638                 date = format.parse(dateString);
 639                 System.out.println(df.format(date));
 640                 gc.setTime(date);
 641                 System.out.println("" + gc.get(Calendar.ZONE_OFFSET));
 642                 System.out.println(format.format(date));
 643             }
 644             catch (ParseException e) {
 645                 System.out.println("No way Jose");
 646             }
 647         }
 648     }
 649 
 650     /**
 651      * SimpleDateFormat won't parse "GMT"
 652      */
 653     @Test
 654     public void Test4134203() {
 655         String dateFormat = "MM/dd/yy HH:mm:ss zzz";
 656         SimpleDateFormat fmt = new SimpleDateFormat(dateFormat);
 657         ParsePosition p0 = new ParsePosition(0);
 658         Date d = fmt.parse("01/22/92 04:52:00 GMT", p0);
 659         System.out.println(d.toString());
 660         // In the failure case an exception is thrown by parse();
 661         // if no exception is thrown, the test passes.
 662     }
 663 
 664     /**
 665      * Another format for GMT string parse
 666      */
 667     @Test
 668     public void Test4266432() {
 669         String dateFormat = "MM/dd HH:mm:ss zzz yyyy";
 670         SimpleDateFormat fmt = new SimpleDateFormat(dateFormat);
 671         ParsePosition p0 = new ParsePosition(0);
 672         Date d = fmt.parse("01/22 04:52:00 GMT 1992", p0);
 673         System.out.println(d.toString());
 674         // In the failure case an exception is thrown by parse();
 675         // if no exception is thrown, the test passes.
 676     }
 677 
 678     /**
 679      * Millisecond field is limited to 3 digits; also test general millisecond
 680      * handling.
 681      *
 682      * NOTE: Updated for fixed semantics as of Kestrel.  See
 683      * 4253490
 684      */
 685     @Test
 686     public void Test4148168() throws ParseException {
 687         SimpleDateFormat fmt = new SimpleDateFormat("", Locale.US);
 688         int ms = 456;
 689         String[] PAT = { "S", "SS", "SSS", "SSSS", "SSSSS",
 690                          "SSSSSSSSSSSSSSSSSSSS" };
 691         String[] OUT = { "456", "456", "456", "0456", "00456",
 692                          "00000000000000000456" };
 693         Calendar cal = Calendar.getInstance();
 694         cal.clear();
 695         cal.set(Calendar.MILLISECOND, ms);
 696         Date d = cal.getTime();
 697         for (int i=0; i<OUT.length; ++i) {
 698             fmt.applyPattern(PAT[i]);
 699             String str = fmt.format(d);
 700             if (!str.equals(OUT[i])) {
 701                 fail("FAIL: " + ms + " ms x \"" + PAT[i] + "\" -> \"" +
 702                       str + "\", exp \"" + OUT[i] + '"');
 703             }
 704         }
 705 
 706         // Test parsing
 707         fmt.applyPattern("s.S");
 708         String[] IN = { "1.4", "1.04", "1.004", "1.45", "1.456",
 709                         "1.4567", "1.45678" };
 710         int[] MS = { 4, 4, 4, 45, 456, 567, 678 };
 711         for (int i=0; i<IN.length; ++i) {
 712             d = fmt.parse(IN[i]);
 713             cal.setTime(d);
 714             ms = cal.get(Calendar.MILLISECOND);
 715             if (ms != MS[i]) {
 716                 fail("FAIL: parse(\"" + IN[i] + "\" x \"s.S\") -> " +
 717                       ms + " ms, exp " + MS[i] + " ms");
 718             }
 719         }
 720     }
 721 
 722     /**
 723      * SimpleDateFormat incorrect handling of 2 single quotes in format()
 724      */
 725     @Test
 726     public void Test4151631() {
 727         String pattern = "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'";
 728         System.out.println("pattern=" + pattern);
 729         SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
 730         @SuppressWarnings("deprecation")
 731         String result = format.format(new Date(1998-1900, Calendar.JUNE, 30, 13, 30, 0));
 732         if (!result.equals("TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')")) {
 733             fail("Fail: result=" + result);
 734         }
 735         else {
 736             System.out.println("Pass: result=" + result);
 737         }
 738     }
 739 
 740     /**
 741      * 'z' at end of date format throws index exception in SimpleDateFormat
 742      * CANNOT REPRODUCE THIS BUG ON 1.2FCS
 743      */
 744     @SuppressWarnings("deprecation")
 745     @Test
 746     public void Test4151706() {
 747         SimpleDateFormat fmt =
 748             new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss z", Locale.US);
 749         try {
 750             Date d = fmt.parse("Thursday, 31-Dec-98 23:00:00 GMT");
 751             if (d.getTime() != Date.UTC(1998-1900, Calendar.DECEMBER, 31, 23, 0, 0))
 752                 fail("Incorrect value: " + d);
 753         } catch (Exception e) {
 754             fail("Fail: " + e);
 755         }
 756     }
 757 
 758     /**
 759      * SimpleDateFormat fails to parse redundant data.
 760      * This is actually a bug down in GregorianCalendar, but it was reported
 761      * as follows...
 762      */
 763     @Test
 764     public void Test4153860() throws ParseException {
 765       Locale savedLocale = Locale.getDefault();
 766       Locale.setDefault(Locale.US);
 767       try {
 768         SimpleDateFormat sf = (SimpleDateFormat)DateFormat.getDateTimeInstance();
 769         // Set the pattern
 770         sf.applyPattern("yyyy.MM-dd");
 771         // Try to create a Date for February 4th
 772         Date d1 = sf.parse("1998.02-04");
 773         // Set the pattern, this time to use the W value
 774         sf.applyPattern("yyyy.MM-dd W");
 775         // Try to create a Date for February 4th
 776         Date d2 = sf.parse("1998.02-04 1");
 777         if (!d1.equals(d2)) {
 778             fail("Parse failed, got " + d2 +
 779                   ", expected " + d1);
 780         }
 781       }
 782       finally {
 783         Locale.setDefault(savedLocale);
 784       }
 785     }
 786 
 787     /**
 788      * Confirm that "EST"(GMT-5:00) and "CST"(GMT-6:00) are used in US
 789      * as "EST" or "CST", not Australian "EST" and "CST".
 790      */
 791     @SuppressWarnings("deprecation")
 792     @Test
 793     public void Test4406615() {
 794       Locale savedLocale = Locale.getDefault();
 795       TimeZone savedTimeZone = TimeZone.getDefault();
 796       Locale.setDefault(Locale.US);
 797       TimeZone.setDefault(TimeZone.getTimeZone("PST"));
 798 
 799       Date d1, d2;
 800       String dt = "Mon, 1 Jan 2001 00:00:00";
 801       SimpleDateFormat sdf =
 802         new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
 803 
 804       try {
 805         d1 = sdf.parse(dt+" EST");
 806         d2 = sdf.parse(dt+" CST");
 807 
 808         if (d1.getYear() != (2000-1900) || d1.getMonth() != 11 ||
 809             d1.getDate() != 31 || d1.getHours() != 21 || d1.getMinutes() != 0 ||
 810             d2.getYear() != (2000-1900) || d2.getMonth() != 11 ||
 811             d2.getDate() != 31 || d2.getHours() != 22 || d2.getMinutes() != 0) {
 812             fail("Parse failed, d1 = " + d1 + ", d2 = " + d2);
 813         } else {
 814             System.out.println("Parse passed");
 815         }
 816       }
 817       catch (Exception e) {
 818             fail("Parse failed, got Exception " + e);
 819       }
 820       finally {
 821         Locale.setDefault(savedLocale);
 822         TimeZone.setDefault(savedTimeZone);
 823       }
 824     }
 825 
 826     /**
 827      * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate
 828      * of some other bug that has been fixed.
 829      */
 830     @Test
 831     public void Test4162071() {
 832         String dateString = "Thu, 30-Jul-1999 11:51:14 GMT";
 833         String format = "EEE', 'dd-MMM-yyyy HH:mm:ss z"; // RFC 822/1123
 834         SimpleDateFormat df = new
 835             SimpleDateFormat(format, Locale.US);
 836 
 837         try {
 838             Date x = df.parse(dateString);
 839             System.out.println("Parse format \"" + format + "\" ok");
 840             System.out.println(dateString + " -> " + df.format(x));
 841         } catch (Exception e) {
 842             fail("Parse format \"" + format + "\" failed.");
 843         }
 844     }
 845 
 846     /**
 847      * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" -> 1999).
 848      */
 849     @Test
 850     public void Test4182066() {
 851       Locale savedLocale = Locale.getDefault();
 852       Locale.setDefault(Locale.US);
 853       try {
 854         SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy",
 855                                                     DateFormatSymbols.getInstance(Locale.US));
 856         SimpleDateFormat dispFmt = new SimpleDateFormat("MMM dd yyyy GG",
 857                                                         DateFormatSymbols.getInstance(Locale.US));
 858         /* We expect 2-digit year formats to put 2-digit years in the right
 859          * window.  Out of range years, that is, anything less than "00" or
 860          * greater than "99", are treated as literal years.  So "1/2/3456"
 861          * becomes 3456 AD.  Likewise, "1/2/-3" becomes -3 AD == 2 BC.
 862          */
 863         @SuppressWarnings("deprecation")
 864         Object[] DATA = {
 865             "02/29/00",   new Date(2000-1900, Calendar.FEBRUARY, 29),
 866             "01/23/01",   new Date(2001-1900, Calendar.JANUARY,  23),
 867             "04/05/-1",   new Date(  -1-1900, Calendar.APRIL,     5),
 868             "01/23/-9",   new Date(  -9-1900, Calendar.JANUARY,  23),
 869             "11/12/1314", new Date(1314-1900, Calendar.NOVEMBER, 12),
 870             "10/31/1",    new Date(   1-1900, Calendar.OCTOBER,  31),
 871             "09/12/+1",   null, // "+1" isn't recognized by US NumberFormat
 872             "09/12/001",  new Date(   1-1900, Calendar.SEPTEMBER,12),
 873         };
 874         StringBuffer out = new StringBuffer();
 875         boolean pass = true;
 876         for (int i=0; i<DATA.length; i+=2) {
 877             String str = (String) DATA[i];
 878             Date expected = (Date) DATA[i+1];
 879             Date actual;
 880             try {
 881                 actual = fmt.parse(str);
 882             } catch (ParseException e) {
 883                 actual = null;
 884             }
 885             String actStr = actual != null
 886                 ? dispFmt.format(actual) : String.valueOf(actual);
 887             if (expected == actual
 888                 || (expected != null && expected.equals(actual))) {
 889                 out.append(str + " => " + actStr + "\n");
 890             } else {
 891                 String expStr = expected != null
 892                     ? dispFmt.format(expected) : String.valueOf(expected);
 893                 out.append("FAIL: " + str + " => " + actStr
 894                            + ", expected " + expStr + "\n");
 895                 pass = false;
 896             }
 897         }
 898         if (pass) {
 899             System.out.println(out.toString());
 900         } else {
 901             fail(out.toString());
 902         }
 903       }
 904       finally {
 905         Locale.setDefault(savedLocale);
 906       }
 907     }
 908 
 909     /**
 910      * Bug 4210209
 911      * Bug 4209272
 912      * DateFormat cannot parse Feb 29 2000 when setLenient(false)
 913      */
 914     @Test
 915     public void Test4210209() {
 916         String pattern = "MMM d, yyyy";
 917         DateFormat fmt = new SimpleDateFormat(pattern,
 918                                               DateFormatSymbols.getInstance(Locale.US));
 919         fmt.getCalendar().setLenient(false);
 920         @SuppressWarnings("deprecation")
 921         Date d = new Date(2000-1900, Calendar.FEBRUARY, 29);
 922         String s = fmt.format(d);
 923         System.out.println(d + " x " + pattern + " => " + s);
 924         ParsePosition pos = new ParsePosition(0);
 925         d = fmt.parse(s, pos);
 926         System.out.println(d + " <= " + pattern + " x " + s);
 927         System.out.println("Parse pos = " + pos);
 928         if (pos.getErrorIndex() != -1) {
 929             fail("FAIL");
 930         }
 931 
 932         // The underlying bug is in GregorianCalendar.  If the following lines
 933         // succeed, the bug is fixed.  If the bug isn't fixed, they will throw
 934         // an exception.
 935         GregorianCalendar cal = new GregorianCalendar();
 936         cal.clear();
 937         cal.setLenient(false);
 938         cal.set(2000, Calendar.FEBRUARY, 29); // This should work!
 939         System.out.println(cal.getTime().toString());
 940     }
 941 
 942     /**
 943      * DateFormat.getDateTimeInstance() allows illegal parameters.
 944      */
 945     @Test
 946     public void Test4213086() {
 947         int[] DATA = {
 948             // Style value, 0/1 for illegal/legal
 949             -99, 0,
 950              -1, 0,
 951               0, 1,
 952               1, 1,
 953               2, 1,
 954               3, 1,
 955               4, 0,
 956              99, 0,
 957         };
 958         String[] DESC = {
 959             "getDateTimeInstance(date)",
 960             "getDateTimeInstance(time)",
 961             "getDateInstance",
 962             "getTimeInstance",
 963         };
 964         String[] GOT = {
 965             "disallowed", "allowed", "<invalid>"
 966         };
 967         for (int i=0; i<DATA.length; i+=2) {
 968             int got = 2;
 969             for (int j=0; j<4; ++j) {
 970                 Exception e = null;
 971                 try {
 972                     DateFormat df;
 973                     switch (j) {
 974                     case 0:
 975                         df = DateFormat.getDateTimeInstance(DATA[i], 0);
 976                         break;
 977                     case 1:
 978                         df = DateFormat.getDateTimeInstance(0, DATA[i]);
 979                         break;
 980                     case 2:
 981                         df = DateFormat.getDateInstance(DATA[i]);
 982                         break;
 983                     case 3:
 984                         df = DateFormat.getTimeInstance(DATA[i]);
 985                         break;
 986                     }
 987                     got = 1;
 988                 } catch (IllegalArgumentException iae) {
 989                     got = 0;
 990                 } catch (Exception ex) {
 991                     e = ex;
 992                 }
 993                 if (got != DATA[i+1] || e != null) {
 994                     fail("FAIL: DateFormat." + DESC[j] + " style " + DATA[i] + " " +
 995                           (e != null ? e.toString() : GOT[got]));
 996                 }
 997             }
 998         }
 999     }
1000 
1001     @SuppressWarnings("deprecation")
1002     @Test
1003     public void Test4253490() throws ParseException {
1004         SimpleDateFormat fmt = new SimpleDateFormat("S", Locale.US);
1005 
1006         GregorianCalendar cal = new GregorianCalendar();
1007 
1008         int      FORMAT_MS  = 12;
1009         String[] FORMAT_PAT = {  "S", "SS", "SSS", "SSSS" };
1010         String[] FORMAT_TO  = { "12", "12", "012", "0012" };
1011 
1012         String   PARSE_PAT  = "S";
1013         String[] PARSE_STR  = { "1", "12", "125", "1250" };
1014         int[]    PARSE_TO   = {  1,   12,   125,   250   };
1015         String   PARSE_LPAT  = "SSSSS";
1016 
1017         // Test formatting.  We want to make sure all digits are output
1018         // and that they are zero-padded on the left if necessary.
1019         cal.setTime(new Date(0L));
1020         cal.set(Calendar.MILLISECOND, FORMAT_MS);
1021         Date d = cal.getTime();
1022         for (int i=0; i<FORMAT_PAT.length; ++i) {
1023             fmt.applyPattern(FORMAT_PAT[i]);
1024             String s = fmt.format(d);
1025             if (s.equals(FORMAT_TO[i])) {
1026                 System.out.println(String.valueOf(FORMAT_MS) + " ms f* \"" +
1027                       FORMAT_PAT[i] + "\" -> \"" + s + '"');
1028             } else {
1029                 fail("FAIL: " + FORMAT_MS + " ms f* \"" +
1030                       FORMAT_PAT[i] + "\" -> \"" + s + "\", expect \"" +
1031                       FORMAT_TO[i] + '"');
1032             }
1033         }
1034 
1035         // Test parsing.  We want to make sure all digits are read.
1036         fmt.applyPattern(PARSE_PAT);
1037         for (int i=0; i<PARSE_STR.length; ++i) {
1038             cal.setTime(fmt.parse(PARSE_STR[i]));
1039             int ms = cal.get(Calendar.MILLISECOND);
1040             if (ms == PARSE_TO[i]) {
1041                 System.out.println("\"" + PARSE_STR[i] + "\" p* \"" +
1042                       PARSE_PAT + "\" -> " + ms + " ms");
1043             } else {
1044                 fail("FAIL: \"" + PARSE_STR[i] + "\" p* \"" +
1045                       PARSE_PAT + "\" -> " + ms + " ms, expect " +
1046                       PARSE_TO[i] + " ms");
1047             }
1048         }
1049 
1050         // Test LONG parsing.  We want to make sure all digits are read.
1051         fmt.applyPattern(PARSE_LPAT);
1052         for (int i=0; i<PARSE_STR.length; ++i) {
1053             cal.setTime(fmt.parse(PARSE_STR[i]));
1054             int ms = cal.get(Calendar.MILLISECOND);
1055             if (ms == PARSE_TO[i]) {
1056                 System.out.println("\"" + PARSE_STR[i] + "\" p* \"" +
1057                       PARSE_LPAT + "\" -> " + ms + " ms");
1058             } else {
1059                 fail("FAIL: \"" + PARSE_STR[i] + "\" p* \"" +
1060                       PARSE_LPAT + "\" -> " + ms + " ms, expect " +
1061                       PARSE_TO[i] + " ms");
1062             }
1063         }
1064     }
1065 
1066     /**
1067      * Bug in handling of time instance; introduces in fix for 4213086.
1068      */
1069     @Test
1070     public void Test4250359() {
1071         DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT,
1072                                                    Locale.US);
1073         @SuppressWarnings("deprecation")
1074         Date d = new Date(1999-1900, Calendar.DECEMBER, 25,
1075                           1, 2, 3);
1076         String s = df.format(d);
1077         // If the bug is present, we see "1:02 AM 1:02 AM".
1078         // Look for more than one instance of "AM".
1079         int i = s.indexOf("AM");
1080         int j = s.indexOf("AM", i+1);
1081         if (i < 0 || j >= 0) {
1082             fail("FAIL: getTimeInstance().format(d) => \"" +
1083                   s + "\"");
1084         }
1085     }
1086 
1087     /**
1088      * Test whether SimpleDataFormat (DateFormatSymbols) can format/parse
1089      * non-localized time zones.
1090      */
1091     @Test
1092     public void Test4261506() {
1093         Locale savedLocale = Locale.getDefault();
1094         TimeZone savedTimeZone = TimeZone.getDefault();
1095         Locale.setDefault(Locale.JAPAN);
1096 
1097         // XXX: Test assumes "PST" is not TimeZoneNames_ja. Need to
1098         // pick up another time zone when L10N is done to that file.
1099         TimeZone.setDefault(TimeZone.getTimeZone("PST"));
1100         SimpleDateFormat fmt = new SimpleDateFormat("yy/MM/dd hh:ss zzz", Locale.JAPAN);
1101         @SuppressWarnings("deprecation")
1102         String result = fmt.format(new Date(1999 - 1900, 0, 1));
1103         System.out.println("format()=>" + result);
1104         if (!result.endsWith("PST")) {
1105             fail("FAIL: SimpleDataFormat.format() did not retrun PST");
1106         }
1107 
1108         Date d = null;
1109         try {
1110             d = fmt.parse("99/1/1 10:10 PST");
1111         } catch (ParseException e) {
1112             fail("FAIL: SimpleDataFormat.parse() could not parse PST");
1113         }
1114 
1115         result = fmt.format(d);
1116         System.out.println("roundtrip:" + result);
1117         if (!result.equals("99/01/01 10:10 PST")) {
1118             fail("FAIL: SimpleDataFomat timezone roundtrip failed");
1119         }
1120 
1121         Locale.setDefault(savedLocale);
1122         TimeZone.setDefault(savedTimeZone);
1123     }
1124 
1125 }
1126 
1127 //eof