/* * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.text.*; import java.util.*; import java.io.*; /** * @test * @bug 4029195 4052408 4056591 4059917 4060212 4061287 4065240 4071441 4073003 * 4089106 4100302 4101483 4103340 4103341 4104136 4104522 4106807 4108407 * 4134203 4138203 4148168 4151631 4151706 4153860 4162071 4182066 4209272 4210209 * 4213086 4250359 4253490 4266432 4406615 4413980 8008577 * @library /java/text/testlib * @run main/othervm -Djava.locale.providers=JRE,SPI DateFormatRegression */ public class DateFormatRegression extends IntlTest { public static void main(String[] args) throws Exception { new DateFormatRegression().run(args); } public void Test4029195() { Date today = new Date(); logln("today: " + today); SimpleDateFormat sdf = (SimpleDateFormat)SimpleDateFormat.getDateInstance(); logln("pattern: " + sdf.toPattern()); logln("today: " + sdf.format(today)); sdf.applyPattern("G yyyy DDD"); String todayS = sdf.format(today); logln("today: " + todayS); try { today = sdf.parse(todayS); logln("today date: " + today); } catch(Exception e) { logln("Error reparsing date: " + e.getMessage()); } try { String rt = sdf.format(sdf.parse(todayS)); logln("round trip: " + rt); if (!rt.equals(todayS)) errln("Fail: Want " + todayS + " Got " + rt); } catch (ParseException e) { errln("Fail: " + e); e.printStackTrace(); } } public void Test4052408() { DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.US); Date date = new Date(97, Calendar.MAY, 3, 8, 55); String str; logln(str = fmt.format(date)); if (!str.equals("5/3/97 8:55 AM")) errln("Fail: Test broken; Want 5/3/97 8:55 AM Got " + str); Hashtable expected = new Hashtable(); expected.put(new Integer(DateFormat.MONTH_FIELD), "5"); expected.put(new Integer(DateFormat.DATE_FIELD), "3"); expected.put(new Integer(DateFormat.YEAR_FIELD), "97"); expected.put(new Integer(DateFormat.HOUR1_FIELD), "8"); expected.put(new Integer(DateFormat.MINUTE_FIELD), "55"); expected.put(new Integer(DateFormat.AM_PM_FIELD), "AM"); StringBuffer buf = new StringBuffer(); String fieldNames[] = { "ERA_FIELD", "YEAR_FIELD", "MONTH_FIELD", "DATE_FIELD", "HOUR_OF_DAY1_FIELD", "HOUR_OF_DAY0_FIELD", "MINUTE_FIELD", "SECOND_FIELD", "MILLISECOND_FIELD", "DAY_OF_WEEK_FIELD", "DAY_OF_YEAR_FIELD", "DAY_OF_WEEK_IN_MONTH_FIELD", "WEEK_OF_YEAR_FIELD", "WEEK_OF_MONTH_FIELD", "AM_PM_FIELD", "HOUR1_FIELD", "HOUR0_FIELD", "TIMEZONE_FIELD", }; boolean pass = true; for (int i=0; i<=17; ++i) { FieldPosition pos = new FieldPosition(i); fmt.format(date, buf, pos); char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()]; buf.getChars(pos.getBeginIndex(), pos.getEndIndex(), dst, 0); str = new String(dst); log(i + ": " + fieldNames[i] + ", \"" + str + "\", " + pos.getBeginIndex() + ", " + pos.getEndIndex()); String exp = (String) expected.get(new Integer(i)); if ((exp == null && str.length() == 0) || str.equals(exp)) logln(" ok"); else { logln(" expected " + exp); pass = false; } } if (!pass) errln("Fail: FieldPosition not set right by DateFormat"); } /** * Verify the function of the [s|g]et2DigitYearStart() API. */ public void Test4056591() { try { SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd", Locale.US); Date start = new Date(1809-1900, Calendar.DECEMBER, 25); fmt.set2DigitYearStart(start); if (!fmt.get2DigitYearStart().equals(start)) errln("get2DigitYearStart broken"); Object[] DATA = { "091225", new Date(1809-1900, Calendar.DECEMBER, 25), "091224", new Date(1909-1900, Calendar.DECEMBER, 24), "091226", new Date(1809-1900, Calendar.DECEMBER, 26), "611225", new Date(1861-1900, Calendar.DECEMBER, 25), }; for (int i=0; i " + got + "; exp " + exp); if (!got.equals(exp)) errln("set2DigitYearStart broken"); } } catch (ParseException e) { errln("Fail: " + e); e.printStackTrace(); } } public void Test4059917() { if (Locale.getDefault().equals(new Locale("hi", "IN"))) { return; } SimpleDateFormat fmt; String myDate; fmt = new SimpleDateFormat( "yyyy/MM/dd" ); myDate = "1997/01/01"; aux917( fmt, myDate ); fmt = new SimpleDateFormat( "yyyyMMdd" ); myDate = "19970101"; aux917( fmt, myDate ); } void aux917( SimpleDateFormat fmt, String str ) { try { logln( "==================" ); logln( "testIt: pattern=" + fmt.toPattern() + " string=" + str ); Object o; o = fmt.parseObject( str ); logln( "Parsed object: " + o ); String formatted = fmt.format( o ); logln( "Formatted string: " + formatted ); if (!formatted.equals(str)) errln("Fail: Want " + str + " Got " + formatted); } catch (ParseException e) { errln("Fail: " + e); e.printStackTrace(); } } public void Test4060212() { Locale savedLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { String dateString = "1995-040.05:01:29"; logln( "dateString= " + dateString ); logln("Using yyyy-DDD.hh:mm:ss"); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-DDD.hh:mm:ss"); ParsePosition pos = new ParsePosition(0); Date myDate = formatter.parse( dateString, pos ); String myString = DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.LONG).format( myDate ); logln( myString ); Calendar cal = new GregorianCalendar(); cal.setTime(myDate); if (cal.get(Calendar.DAY_OF_YEAR) != 40) errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40"); logln("Using yyyy-ddd.hh:mm:ss"); formatter = new SimpleDateFormat("yyyy-ddd.hh:mm:ss"); pos = new ParsePosition(0); myDate = formatter.parse( dateString, pos ); myString = DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.LONG).format( myDate ); logln( myString ); cal.setTime(myDate); if (cal.get(Calendar.DAY_OF_YEAR) != 40) errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40"); } finally { Locale.setDefault(savedLocale); } } public void Test4061287() { SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy"); try { logln(df.parse("35/01/1971").toString()); } catch (ParseException e) { errln("Fail: " + e); e.printStackTrace(); } df.setLenient(false); boolean ok = false; try { logln(df.parse("35/01/1971").toString()); } catch (ParseException e) {ok=true;} if (!ok) errln("Fail: Lenient not working"); } public void Test4065240() { Date curDate; DateFormat shortdate, fulldate; String strShortDate, strFullDate; Locale saveLocale = Locale.getDefault(); TimeZone saveZone = TimeZone.getDefault(); try { Locale curLocale = new Locale("de","DE"); Locale.setDefault(curLocale); TimeZone.setDefault(TimeZone.getTimeZone("EST")); curDate = new Date(98, 0, 1); shortdate = DateFormat.getDateInstance(DateFormat.SHORT); fulldate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG ); strShortDate = new String("The current date (short form) is " + shortdate. format(curDate)); strFullDate = new String("The current date (long form) is " + fulldate.format(curDate)); logln(strShortDate); logln(strFullDate); // UPDATE THIS AS ZONE NAME RESOURCE FOR in de_DE is updated if (!strFullDate.endsWith("EST") && !strFullDate.endsWith("GMT-05:00")) { errln("Fail: Want GMT-05:00"); } } finally { Locale.setDefault(saveLocale); TimeZone.setDefault(saveZone); } } /* DateFormat.equals is too narrowly defined. As a result, MessageFormat does not work correctly. DateFormat.equals needs to be written so that the Calendar sub-object is not compared using Calendar.equals, but rather compared for equivalency. This may necessitate adding a (package private) method to Calendar to test for equivalency. Currently this bug breaks MessageFormat.toPattern */ public void Test4071441() { DateFormat fmtA = DateFormat.getInstance(); DateFormat fmtB = DateFormat.getInstance(); Calendar calA = fmtA.getCalendar(); Calendar calB = fmtB.getCalendar(); Date epoch = new Date(0); Date xmas = new Date(61, Calendar.DECEMBER, 25); calA.setTime(epoch); calB.setTime(epoch); if (!calA.equals(calB)) errln("Fail: Can't complete test; Calendar instances unequal"); if (!fmtA.equals(fmtB)) errln("Fail: DateFormat unequal when Calendars equal"); calB.setTime(xmas); if (calA.equals(calB)) errln("Fail: Can't complete test; Calendar instances equal"); if (!fmtA.equals(fmtB)) errln("Fail: DateFormat unequal when Calendars equivalent"); logln("DateFormat.equals ok"); } /* The java.text.DateFormat.parse(String) method expects for the US locale a string formatted according to mm/dd/yy and parses it correctly. When given a string mm/dd/yyyy it only parses up to the first two y's, typically resulting in a date in the year 1919. Please extend the parsing method(s) to handle strings with four-digit year values (probably also applicable to various other locales. */ public void Test4073003() { try { DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US); String[] tests = { "12/25/61", "12/25/1961", "4/3/2010", "4/3/10" }; for (int i=0; i is incorrectly serialized/deserialized."); } else { logln("DateFormat instance which uses TimeZone <" + IDs[i] + "> is correctly serialized/deserialized."); } } if (!pass) { errln("Fail: DateFormat serialization/equality bug"); } } catch (IOException e) { errln("Fail: " + e); e.printStackTrace(); } catch (ClassNotFoundException e) { errln("Fail: " + e); e.printStackTrace(); } finally { TimeZone.setDefault(savedTimeZone); } } public void Test4101483() { SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.US); FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD); Date d= new Date(9234567890L); StringBuffer buf = new StringBuffer(""); logln(sdf.format(d, buf, fp).toString()); logln(d + " => " + buf); logln("beginIndex = " + fp.getBeginIndex()); logln("endIndex = " + fp.getEndIndex()); if (fp.getBeginIndex() == fp.getEndIndex()) errln("Fail: Empty field"); } /** * Bug 4103340 * Bug 4138203 * This bug really only works in Locale.US, since that's what the locale * used for Date.toString() is. Bug 4138203 reports that it fails on Korean * NT; it would actually have failed on any non-US locale. Now it should * work on all locales. */ public void Test4103340() { // choose a date that is the FIRST of some month // and some arbitrary time Date d=new Date(97, 3, 1, 1, 1, 1); SimpleDateFormat df=new SimpleDateFormat("MMMM", Locale.US); String s = d.toString(); String s2 = df.format(d); logln("Date="+s); logln("DF="+s2); if (s.indexOf(s2.substring(0,2)) == -1) errln("Months should match"); } public void Test4103341() { TimeZone saveZone =TimeZone.getDefault(); try { TimeZone.setDefault(TimeZone.getTimeZone("CST")); SimpleDateFormat simple = new SimpleDateFormat("MM/dd/yyyy HH:mm"); if (!simple.getTimeZone().equals(TimeZone.getDefault())) errln("Fail: SimpleDateFormat not using default zone"); } finally { TimeZone.setDefault(saveZone); } } public void Test4104136() { SimpleDateFormat sdf = new SimpleDateFormat(); String pattern = "'time' hh:mm"; sdf.applyPattern(pattern); logln("pattern: \"" + pattern + "\""); Object[] DATA = { "time 10:30", new ParsePosition(10), new Date(70, Calendar.JANUARY, 1, 10, 30), "time 10:x", new ParsePosition(0), null, "time 10x", new ParsePosition(0), null, }; for (int i=0; i \"" + str + "\", exp \"" + OUT[i] + '"'); } } // Test parsing fmt.applyPattern("s.S"); String[] IN = { "1.4", "1.04", "1.004", "1.45", "1.456", "1.4567", "1.45678" }; int[] MS = { 4, 4, 4, 45, 456, 567, 678 }; for (int i=0; i " + ms + " ms, exp " + MS[i] + " ms"); } } } /** * SimpleDateFormat incorrect handling of 2 single quotes in format() */ public void Test4151631() { String pattern = "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'"; logln("pattern=" + pattern); SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US); String result = format.format(new Date(1998-1900, Calendar.JUNE, 30, 13, 30, 0)); if (!result.equals("TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')")) { errln("Fail: result=" + result); } else { logln("Pass: result=" + result); } } /** * 'z' at end of date format throws index exception in SimpleDateFormat * CANNOT REPRODUCE THIS BUG ON 1.2FCS */ public void Test4151706() { SimpleDateFormat fmt = new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss z", Locale.US); try { Date d = fmt.parse("Thursday, 31-Dec-98 23:00:00 GMT"); if (d.getTime() != Date.UTC(1998-1900, Calendar.DECEMBER, 31, 23, 0, 0)) errln("Incorrect value: " + d); } catch (Exception e) { errln("Fail: " + e); } } /** * SimpleDateFormat fails to parse redundant data. * This is actually a bug down in GregorianCalendar, but it was reported * as follows... */ public void Test4153860() throws ParseException { Locale savedLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { SimpleDateFormat sf = (SimpleDateFormat)DateFormat.getDateTimeInstance(); // Set the pattern sf.applyPattern("yyyy.MM-dd"); // Try to create a Date for February 4th Date d1 = sf.parse("1998.02-04"); // Set the pattern, this time to use the W value sf.applyPattern("yyyy.MM-dd W"); // Try to create a Date for February 4th Date d2 = sf.parse("1998.02-04 1"); if (!d1.equals(d2)) { errln("Parse failed, got " + d2 + ", expected " + d1); } } finally { Locale.setDefault(savedLocale); } } /** * Confirm that "EST"(GMT-5:00) and "CST"(GMT-6:00) are used in US * as "EST" or "CST", not Australian "EST" and "CST". */ public void Test4406615() { Locale savedLocale = Locale.getDefault(); TimeZone savedTimeZone = TimeZone.getDefault(); Locale.setDefault(Locale.US); TimeZone.setDefault(TimeZone.getTimeZone("PST")); Date d1, d2; String dt = "Mon, 1 Jan 2001 00:00:00"; SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); try { d1 = sdf.parse(dt+" EST"); d2 = sdf.parse(dt+" CST"); if (d1.getYear() != (2000-1900) || d1.getMonth() != 11 || d1.getDate() != 31 || d1.getHours() != 21 || d1.getMinutes() != 0 || d2.getYear() != (2000-1900) || d2.getMonth() != 11 || d2.getDate() != 31 || d2.getHours() != 22 || d2.getMinutes() != 0) { errln("Parse failed, d1 = " + d1 + ", d2 = " + d2); } else { logln("Parse passed"); } } catch (Exception e) { errln("Parse failed, got Exception " + e); } finally { Locale.setDefault(savedLocale); TimeZone.setDefault(savedTimeZone); } } /** * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate * of some other bug that has been fixed. */ public void Test4162071() { String dateString = "Thu, 30-Jul-1999 11:51:14 GMT"; String format = "EEE', 'dd-MMM-yyyy HH:mm:ss z"; // RFC 822/1123 SimpleDateFormat df = new SimpleDateFormat(format, Locale.US); try { Date x = df.parse(dateString); logln("Parse format \"" + format + "\" ok"); logln(dateString + " -> " + df.format(x)); } catch (Exception e) { errln("Parse format \"" + format + "\" failed."); } } /** * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" -> 1999). */ public void Test4182066() { Locale savedLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy", DateFormatSymbols.getInstance(Locale.US)); SimpleDateFormat dispFmt = new SimpleDateFormat("MMM dd yyyy GG", DateFormatSymbols.getInstance(Locale.US)); /* We expect 2-digit year formats to put 2-digit years in the right * window. Out of range years, that is, anything less than "00" or * greater than "99", are treated as literal years. So "1/2/3456" * becomes 3456 AD. Likewise, "1/2/-3" becomes -3 AD == 2 BC. */ Object[] DATA = { "02/29/00", new Date(2000-1900, Calendar.FEBRUARY, 29), "01/23/01", new Date(2001-1900, Calendar.JANUARY, 23), "04/05/-1", new Date( -1-1900, Calendar.APRIL, 5), "01/23/-9", new Date( -9-1900, Calendar.JANUARY, 23), "11/12/1314", new Date(1314-1900, Calendar.NOVEMBER, 12), "10/31/1", new Date( 1-1900, Calendar.OCTOBER, 31), "09/12/+1", null, // "+1" isn't recognized by US NumberFormat "09/12/001", new Date( 1-1900, Calendar.SEPTEMBER,12), }; StringBuffer out = new StringBuffer(); boolean pass = true; for (int i=0; i " + actStr + "\n"); } else { String expStr = expected != null ? dispFmt.format(expected) : String.valueOf(expected); out.append("FAIL: " + str + " => " + actStr + ", expected " + expStr + "\n"); pass = false; } } if (pass) { log(out.toString()); } else { err(out.toString()); } } finally { Locale.setDefault(savedLocale); } } /** * Bug 4210209 * Bug 4209272 * DateFormat cannot parse Feb 29 2000 when setLenient(false) */ public void Test4210209() { String pattern = "MMM d, yyyy"; DateFormat fmt = new SimpleDateFormat(pattern, DateFormatSymbols.getInstance(Locale.US)); fmt.getCalendar().setLenient(false); Date d = new Date(2000-1900, Calendar.FEBRUARY, 29); String s = fmt.format(d); logln(d + " x " + pattern + " => " + s); ParsePosition pos = new ParsePosition(0); d = fmt.parse(s, pos); logln(d + " <= " + pattern + " x " + s); logln("Parse pos = " + pos); if (pos.getErrorIndex() != -1) { errln("FAIL"); } // The underlying bug is in GregorianCalendar. If the following lines // succeed, the bug is fixed. If the bug isn't fixed, they will throw // an exception. GregorianCalendar cal = new GregorianCalendar(); cal.clear(); cal.setLenient(false); cal.set(2000, Calendar.FEBRUARY, 29); // This should work! logln(cal.getTime().toString()); } /** * DateFormat.getDateTimeInstance() allows illegal parameters. */ public void Test4213086() { int[] DATA = { // Style value, 0/1 for illegal/legal -99, 0, -1, 0, 0, 1, 1, 1, 2, 1, 3, 1, 4, 0, 99, 0, }; String[] DESC = { "getDateTimeInstance(date)", "getDateTimeInstance(time)", "getDateInstance", "getTimeInstance", }; String[] GOT = { "disallowed", "allowed", "" }; for (int i=0; i \"" + s + '"'); } else { errln("FAIL: " + FORMAT_MS + " ms f* \"" + FORMAT_PAT[i] + "\" -> \"" + s + "\", expect \"" + FORMAT_TO[i] + '"'); } } // Test parsing. We want to make sure all digits are read. fmt.applyPattern(PARSE_PAT); for (int i=0; i " + ms + " ms"); } else { errln("FAIL: \"" + PARSE_STR[i] + "\" p* \"" + PARSE_PAT + "\" -> " + ms + " ms, expect " + PARSE_TO[i] + " ms"); } } // Test LONG parsing. We want to make sure all digits are read. fmt.applyPattern(PARSE_LPAT); for (int i=0; i " + ms + " ms"); } else { errln("FAIL: \"" + PARSE_STR[i] + "\" p* \"" + PARSE_LPAT + "\" -> " + ms + " ms, expect " + PARSE_TO[i] + " ms"); } } } /** * Bug in handling of time instance; introduces in fix for 4213086. */ public void Test4250359() { DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.US); Date d = new Date(1999-1900, Calendar.DECEMBER, 25, 1, 2, 3); String s = df.format(d); // If the bug is present, we see "1:02 AM 1:02 AM". // Look for more than one instance of "AM". int i = s.indexOf("AM"); int j = s.indexOf("AM", i+1); if (i < 0 || j >= 0) { errln("FAIL: getTimeInstance().format(d) => \"" + s + "\""); } } /** * Test whether SimpleDataFormat (DateFormatSymbols) can format/parse * non-localized time zones. */ public void Test4261506() { Locale savedLocale = Locale.getDefault(); TimeZone savedTimeZone = TimeZone.getDefault(); Locale.setDefault(Locale.JAPAN); // XXX: Test assumes "PST" is not TimeZoneNames_ja. Need to // pick up another time zone when L10N is done to that file. TimeZone.setDefault(TimeZone.getTimeZone("PST")); SimpleDateFormat fmt = new SimpleDateFormat("yy/MM/dd hh:ss zzz", Locale.JAPAN); String result = fmt.format(new Date(1999, 0, 1)); logln("format()=>" + result); if (!result.endsWith("PST")) { errln("FAIL: SimpleDataFormat.format() did not retrun PST"); } Date d = null; try { d = fmt.parse("99/1/1 10:10 PST"); } catch (ParseException e) { errln("FAIL: SimpleDataFormat.parse() could not parse PST"); } result = fmt.format(d); logln("roundtrip:" + result); if (!result.equals("99/01/01 10:10 PST")) { errln("FAIL: SimpleDataFomat timezone roundtrip failed"); } Locale.setDefault(savedLocale); TimeZone.setDefault(savedTimeZone); } } //eof