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