2 *******************************************************************************
3 * Copyright (C) 2001-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 * Port From: ICU4C v1.8.1 : format : DateFormatRegressionTest
10 * Source File: $ICU4CRoot/source/test/intltest/dtfmrgts.cpp
13 package com.ibm.icu.dev.test.format;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.io.ObjectInputStream;
19 import java.io.ObjectOutputStream;
20 import java.io.OptionalDataException;
21 import java.text.FieldPosition;
22 import java.text.Format;
23 import java.text.ParseException;
24 import java.text.ParsePosition;
25 import java.util.Date;
26 import java.util.Locale;
28 import com.ibm.icu.text.DateFormat;
29 import com.ibm.icu.text.SimpleDateFormat;
30 import com.ibm.icu.util.Calendar;
31 import com.ibm.icu.util.GregorianCalendar;
32 import com.ibm.icu.util.IslamicCalendar;
33 import com.ibm.icu.util.JapaneseCalendar;
34 import com.ibm.icu.util.SimpleTimeZone;
35 import com.ibm.icu.util.TimeZone;
36 import com.ibm.icu.util.ULocale;
39 * Performs regression test for DateFormat
41 public class DateFormatRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
43 public static void main(String[] args) throws Exception{
44 new DateFormatRegressionTest().run(args);
50 public void Test4029195() {
51 Calendar cal = Calendar.getInstance();
52 Date today = cal.getTime();
53 logln("today: " + today);
54 SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance();
55 String pat = sdf.toPattern();
56 logln("pattern: " + pat);
57 StringBuffer fmtd = new StringBuffer("");
58 FieldPosition pos = new FieldPosition(0);
59 fmtd = sdf.format(today, fmtd, pos);
60 logln("today: " + fmtd);
62 sdf.applyPattern("G yyyy DDD");
63 StringBuffer todayS = new StringBuffer("");
64 todayS = sdf.format(today, todayS, pos);
65 logln("today: " + todayS);
67 today = sdf.parse(todayS.toString());
68 logln("today date: " + today);
69 } catch (Exception e) {
70 errln("Error reparsing date: " + e.getMessage());
74 StringBuffer rt = new StringBuffer("");
75 rt = sdf.format(sdf.parse(todayS.toString()), rt, pos);
76 logln("round trip: " + rt);
77 if (!rt.toString().equals(todayS.toString()))
78 errln("Fail: Want " + todayS + " Got " + rt);
79 } catch (ParseException e) {
88 public void Test4052408() {
90 DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.US);
91 Calendar cal = Calendar.getInstance();
93 cal.set(97 + 1900, Calendar.MAY, 3, 8, 55);
94 Date dt = cal.getTime();
95 String str = fmt.format(dt);
98 if (!str.equals("5/3/97, 8:55 AM"))
99 errln("Fail: Test broken; Want 5/3/97, 8:55 AM Got " + str);
101 String expected[] = {
103 "97", //"YEAR_FIELD",
104 "5", //"MONTH_FIELD",
106 "", //"HOUR_OF_DAY1_FIELD",
107 "", //"HOUR_OF_DAY0_FIELD",
108 "55", //"MINUTE_FIELD",
109 "", //"SECOND_FIELD",
110 "", //"MILLISECOND_FIELD",
111 "", //"DAY_OF_WEEK_FIELD",
112 "", //"DAY_OF_YEAR_FIELD",
113 "", //"DAY_OF_WEEK_IN_MONTH_FIELD",
114 "", //"WEEK_OF_YEAR_FIELD",
115 "", //"WEEK_OF_MONTH_FIELD",
116 "AM", //"AM_PM_FIELD",
117 "8", //"HOUR1_FIELD",
119 "" //"TIMEZONE_FIELD"
121 String fieldNames[] = {
126 "HOUR_OF_DAY1_FIELD",
127 "HOUR_OF_DAY0_FIELD",
133 "DAY_OF_WEEK_IN_MONTH_FIELD",
134 "WEEK_OF_YEAR_FIELD",
135 "WEEK_OF_MONTH_FIELD",
142 for (int i = 0; i <= 17; ++i) {
143 FieldPosition pos = new FieldPosition(i);
144 StringBuffer buf = new StringBuffer("");
145 fmt.format(dt, buf, pos);
146 //char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()];
147 String dst = buf.substring(pos.getBeginIndex(), pos.getEndIndex());
149 log(i + ": " + fieldNames[i] + ", \"" + str + "\", "
150 + pos.getBeginIndex() + ", " + pos.getEndIndex());
151 String exp = expected[i];
152 if ((exp.length() == 0 && str.length() == 0) || str.equals(exp))
155 logln(" expected " + exp);
160 errln("Fail: FieldPosition not set right by DateFormat");
165 * Verify the function of the [s|g]et2DigitYearStart() API.
167 public void Test4056591() {
170 SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd", Locale.US);
171 Calendar cal = Calendar.getInstance();
173 cal.set(1809, Calendar.DECEMBER, 25);
174 Date start = cal.getTime();
175 fmt.set2DigitYearStart(start);
176 if ((fmt.get2DigitYearStart() != start))
177 errln("get2DigitYearStart broken");
179 cal.set(1809, Calendar.DECEMBER, 25);
180 Date d1 = cal.getTime();
182 cal.set(1909, Calendar.DECEMBER, 24);
183 Date d2 = cal.getTime();
185 cal.set(1809, Calendar.DECEMBER, 26);
186 Date d3 = cal.getTime();
188 cal.set(1861, Calendar.DECEMBER, 25);
189 Date d4 = cal.getTime();
191 Date dates[] = {d1, d2, d3, d4};
193 String strings[] = {"091225", "091224", "091226", "611225"};
195 for (int i = 0; i < 4; i++) {
196 String s = strings[i];
198 Date got = fmt.parse(s);
199 logln(s + " . " + got + "; exp " + exp);
200 if (got.getTime() != exp.getTime())
201 errln("set2DigitYearStart broken");
203 } catch (ParseException e) {
212 public void Test4059917() {
213 SimpleDateFormat fmt;
215 fmt = new SimpleDateFormat("yyyy/MM/dd");
216 myDate = "1997/01/01";
217 aux917( fmt, myDate );
218 fmt = new SimpleDateFormat("yyyyMMdd");
220 aux917( fmt, myDate );
223 public void aux917(SimpleDateFormat fmt, String str) {
225 String pat = fmt.toPattern();
226 logln("==================");
227 logln("testIt: pattern=" + pat + " string=" + str);
228 ParsePosition pos = new ParsePosition(0);
229 Object o = fmt.parseObject(str, pos);
230 //logln( UnicodeString("Parsed object: ") + o );
232 StringBuffer formatted = new StringBuffer("");
233 FieldPosition poss = new FieldPosition(0);
234 formatted = fmt.format(o, formatted, poss);
236 logln("Formatted string: " + formatted);
237 if (!formatted.toString().equals(str))
238 errln("Fail: Want " + str + " Got " + formatted);
244 public void Test4060212() {
245 String dateString = "1995-040.05:01:29";
246 logln("dateString= " + dateString);
247 logln("Using yyyy-DDD.hh:mm:ss");
248 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-DDD.hh:mm:ss");
249 ParsePosition pos = new ParsePosition(0);
250 Date myDate = formatter.parse(dateString, pos);
251 DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.LONG);
252 String myString = fmt.format(myDate);
254 Calendar cal = new GregorianCalendar();
256 if ((cal.get(Calendar.DAY_OF_YEAR) != 40))
257 errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40");
259 logln("Using yyyy-ddd.hh:mm:ss");
260 formatter = new SimpleDateFormat("yyyy-ddd.hh:mm:ss");
262 myDate = formatter.parse(dateString, pos);
263 myString = fmt.format(myDate);
266 if ((cal.get(Calendar.DAY_OF_YEAR) != 40))
267 errln("Fail: Got " + cal.get(Calendar.DAY_OF_YEAR) + " Want 40");
272 public void Test4061287() {
274 SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
276 logln(df.parse("35/01/1971").toString());
277 } catch (ParseException e) {
281 df.setLenient(false);
284 logln(df.parse("35/01/1971").toString());
285 } catch (ParseException e) {
289 errln("Fail: Lenient not working");
295 public void Test4065240() {
297 DateFormat shortdate, fulldate;
298 String strShortDate, strFullDate;
299 Locale saveLocale = Locale.getDefault();
300 TimeZone saveZone = TimeZone.getDefault();
303 Locale curLocale = new Locale("de", "DE");
304 Locale.setDefault(curLocale);
305 // {sfb} adoptDefault instead of setDefault
306 //TimeZone.setDefault(TimeZone.createTimeZone("EST"));
307 TimeZone.setDefault(TimeZone.getTimeZone("EST"));
308 Calendar cal = Calendar.getInstance();
310 cal.set(98 + 1900, 0, 1);
311 curDate = cal.getTime();
312 shortdate = DateFormat.getDateInstance(DateFormat.SHORT);
313 fulldate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
314 strShortDate = "The current date (short form) is ";
316 temp = shortdate.format(curDate);
317 strShortDate += temp;
318 strFullDate = "The current date (long form) is ";
319 String temp2 = fulldate.format(curDate);
320 strFullDate += temp2;
325 // {sfb} What to do with resource bundle stuff?????
327 // Check to see if the resource is present; if not, we can't test
328 //ResourceBundle bundle = //The variable is never used
329 // ICULocaleData.getBundle("DateFormatZoneData", curLocale);
331 // {sfb} API change to ResourceBundle -- add getLocale()
332 /*if (bundle.getLocale().getLanguage().equals("de")) {
333 // UPDATE THIS AS ZONE NAME RESOURCE FOR <EST> in de_DE is updated
334 if (!strFullDate.endsWith("GMT-05:00"))
335 errln("Fail: Want GMT-05:00");
337 logln("*** TEST COULD NOT BE COMPLETED BECAUSE DateFormatZoneData ***");
338 logln("*** FOR LOCALE de OR de_DE IS MISSING ***");
340 } catch (Exception e) {
341 logln(e.getMessage());
343 Locale.setDefault(saveLocale);
344 TimeZone.setDefault(saveZone);
350 DateFormat.equals is too narrowly defined. As a result, MessageFormat
351 does not work correctly. DateFormat.equals needs to be written so
352 that the Calendar sub-object is not compared using Calendar.equals,
353 but rather compared for equivalency. This may necessitate adding a
354 (package private) method to Calendar to test for equivalency.
356 Currently this bug breaks MessageFormat.toPattern
361 public void Test4071441() {
362 DateFormat fmtA = DateFormat.getInstance();
363 DateFormat fmtB = DateFormat.getInstance();
365 // {sfb} Is it OK to cast away const here?
366 Calendar calA = fmtA.getCalendar();
367 Calendar calB = fmtB.getCalendar();
369 calA.set(1900, 0 ,0);
371 calB.set(1900, 0, 0);
372 if (!calA.equals(calB))
373 errln("Fail: Can't complete test; Calendar instances unequal");
374 if (!fmtA.equals(fmtB))
375 errln("Fail: DateFormat unequal when Calendars equal");
377 calB.set(1961, Calendar.DECEMBER, 25);
378 if (calA.equals(calB))
379 errln("Fail: Can't complete test; Calendar instances equal");
380 if (!fmtA.equals(fmtB))
381 errln("Fail: DateFormat unequal when Calendars equivalent");
382 logln("DateFormat.equals ok");
385 /* The java.text.DateFormat.parse(String) method expects for the
386 US locale a string formatted according to mm/dd/yy and parses it
389 When given a string mm/dd/yyyy it only parses up to the first
390 two y's, typically resulting in a date in the year 1919.
392 Please extend the parsing method(s) to handle strings with
393 four-digit year values (probably also applicable to various
398 public void Test4073003() {
400 DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
401 String tests[] = {"12/25/61", "12/25/1961", "4/3/2010", "4/3/10"};
402 for (int i = 0; i < 4; i += 2) {
403 Date d = fmt.parse(tests[i]);
404 Date dd = fmt.parse(tests[i + 1]);
409 if (d.getTime() != dd.getTime())
410 errln("Fail: " + d + " != " + dd);
412 errln("Fail: " + s + " != " + ss);
413 logln("Ok: " + s + " " + d);
415 } catch (ParseException e) {
424 public void Test4089106() {
425 TimeZone def = TimeZone.getDefault();
427 TimeZone z = new SimpleTimeZone((int) (1.25 * 3600000), "FAKEZONE");
428 TimeZone.setDefault(z);
429 SimpleDateFormat f = new SimpleDateFormat();
430 if (!f.getTimeZone().equals(z))
431 errln("Fail: SimpleTimeZone should use TimeZone.getDefault()");
433 TimeZone.setDefault(def);
440 public void Test4100302() {
443 Locale.CANADA, Locale.CANADA_FRENCH, Locale.CHINA,
444 Locale.CHINESE, Locale.ENGLISH, Locale.FRANCE, Locale.FRENCH,
445 Locale.GERMAN, Locale.GERMANY, Locale.ITALIAN, Locale.ITALY,
446 Locale.JAPAN, Locale.JAPANESE, Locale.KOREA, Locale.KOREAN,
447 Locale.PRC, Locale.SIMPLIFIED_CHINESE, Locale.TAIWAN,
448 Locale.TRADITIONAL_CHINESE, Locale.UK, Locale.US};
451 for (int i = 0; i < 21; i++) {
452 Format format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locales[i]);
454 ByteArrayOutputStream baos = new ByteArrayOutputStream();
455 ObjectOutputStream oos = new ObjectOutputStream(baos);
456 oos.writeObject(format);
459 bytes = baos.toByteArray();
460 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
461 Object o = ois.readObject();
462 if (!format.equals(o)) {
464 logln("DateFormat instance for locale " + locales[i] + " is incorrectly serialized/deserialized.");
466 logln("DateFormat instance for locale " + locales[i] + " is OKAY.");
470 errln("Fail: DateFormat serialization/equality bug");
471 } catch (OptionalDataException e) {
473 } catch (IOException e) {
475 } catch (ClassNotFoundException e) {
484 public void Test4101483() {
485 SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.US);
486 FieldPosition fp = new FieldPosition(DateFormat.TIMEZONE_FIELD);
487 Date d = new Date(9234567890L);
488 StringBuffer buf = new StringBuffer("");
489 sdf.format(d, buf, fp);
490 logln(sdf.format(d, buf, fp).toString());
491 logln("beginIndex = " + fp.getBeginIndex());
492 logln("endIndex = " + fp.getEndIndex());
493 if (fp.getBeginIndex() == fp.getEndIndex())
494 errln("Fail: Empty field");
500 * This bug really only works in Locale.US, since that's what the locale
501 * used for Date.toString() is. Bug 4138203 reports that it fails on Korean
502 * NT; it would actually have failed on any non-US locale. Now it should
503 * work on all locales.
505 public void Test4103340() {
507 // choose a date that is the FIRST of some month
508 // and some arbitrary time
509 Calendar cal = Calendar.getInstance();
511 cal.set(1997, 3, 1, 1, 1, 1);
512 Date d = cal.getTime();
513 SimpleDateFormat df = new SimpleDateFormat("MMMM", Locale.US);
514 String s = d.toString();
515 StringBuffer s2 = new StringBuffer("");
516 FieldPosition pos = new FieldPosition(0);
517 s2 = df.format(d, s2, pos);
520 String substr = s2.substring(0,2);
521 if (s.indexOf(substr) == -1)
522 errln("Months should match");
528 public void Test4103341() {
529 TimeZone saveZone = TimeZone.getDefault();
531 // {sfb} changed from adoptDefault to setDefault
532 TimeZone.setDefault(TimeZone.getTimeZone("CST"));
533 SimpleDateFormat simple = new SimpleDateFormat("MM/dd/yyyy HH:mm");
534 TimeZone temp = TimeZone.getDefault();
535 if (!simple.getTimeZone().equals(temp))
536 errln("Fail: SimpleDateFormat not using default zone");
538 TimeZone.setDefault(saveZone);
545 public void Test4104136() {
546 SimpleDateFormat sdf = new SimpleDateFormat();
547 String pattern = "'time' hh:mm";
548 sdf.applyPattern(pattern);
549 logln("pattern: \"" + pattern + "\"");
550 String strings[] = {"time 10:30", "time 10:x", "time 10x"};
551 ParsePosition ppos[] = {new ParsePosition(10), new ParsePosition(0), new ParsePosition(0)};
552 Calendar cal = Calendar.getInstance();
554 cal.set(1970, Calendar.JANUARY, 1, 10, 30);
555 Date dates[] = {cal.getTime(), new Date(-1), new Date(-1)};
556 for (int i = 0; i < 3; i++) {
557 String text = strings[i];
558 ParsePosition finish = ppos[i];
560 ParsePosition pos = new ParsePosition(0);
561 Date d = sdf.parse(text, pos);
562 logln(" text: \"" + text + "\"");
563 logln(" index: %d" + pos.getIndex());
564 logln(" result: " + d);
565 if (pos.getIndex() != finish.getIndex())
566 errln("Fail: Expected pos " + finish.getIndex());
567 if (!((d == null && exp.equals(new Date(-1))) || (d.equals(exp))))
568 errln( "Fail: Expected result " + exp);
575 * According to the bug report, this test should throw a
576 * StringIndexOutOfBoundsException during the second parse. However,
579 public void Test4104522() {
580 SimpleDateFormat sdf = new SimpleDateFormat();
581 String pattern = "'time' hh:mm";
582 sdf.applyPattern(pattern);
583 logln("pattern: \"" + pattern + "\"");
585 ParsePosition pp = new ParsePosition(0);
586 String text = "time ";
587 Date dt = sdf.parse(text, pp);
588 logln(" text: \"" + text + "\"" + " date: " + dt);
592 dt = sdf.parse(text, pp);
593 logln(" text: \"" + text + "\"" + " date: " + dt);
599 public void Test4106807() {
601 DateFormat df = DateFormat.getDateTimeInstance();
603 SimpleDateFormat sdfs[] = {
604 new SimpleDateFormat("yyyyMMddHHmmss"),
605 new SimpleDateFormat("yyyyMMddHHmmss'Z'"),
606 new SimpleDateFormat("yyyyMMddHHmmss''"),
607 new SimpleDateFormat("yyyyMMddHHmmss'a''a'"),
608 new SimpleDateFormat("yyyyMMddHHmmss %")};
615 GregorianCalendar gc = new GregorianCalendar();
616 TimeZone timeZone = TimeZone.getDefault();
617 TimeZone gmt = (TimeZone) timeZone.clone();
619 for (int i = 0; i < 5; i++) {
620 SimpleDateFormat format = sdfs[i];
621 String dateString = strings[i];
623 format.setTimeZone(gmt);
624 dt = format.parse(dateString);
625 // {sfb} some of these parses will fail purposely
627 StringBuffer fmtd = new StringBuffer("");
628 FieldPosition pos = new FieldPosition(0);
629 fmtd = df.format(dt, fmtd, pos);
630 logln(fmtd.toString());
631 //logln(df.format(dt));
633 logln("" + gc.get(Calendar.ZONE_OFFSET));
634 StringBuffer s = new StringBuffer("");
635 s = format.format(dt, s, pos);
637 } catch (ParseException e) {
638 logln("No way Jose");
644 Synopsis: Chinese time zone CTT is not recogonized correctly.
645 Description: Platform Chinese Windows 95 - ** Time zone set to CST **
651 // {sfb} what to do with this one ??
652 public void Test4108407() {
654 // TODO user.timezone is a protected system property, catch securityexception and warn
655 // if this is reenabled
656 long l = System.currentTimeMillis();
657 logln("user.timezone = " + System.getProperty("user.timezone", "?"));
658 logln("Time Zone :" +
659 DateFormat.getDateInstance().getTimeZone().getID());
660 logln("Default format :" +
661 DateFormat.getDateInstance().format(new Date(l)));
662 logln("Full format :" +
663 DateFormat.getDateInstance(DateFormat.FULL).format(new
665 logln("*** Set host TZ to CST ***");
666 logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
672 * SimpleDateFormat won't parse "GMT"
674 public void Test4134203() {
675 String dateFormat = "MM/dd/yy HH:mm:ss zzz";
676 SimpleDateFormat fmt = new SimpleDateFormat(dateFormat);
678 ParsePosition p0 = new ParsePosition(0);
679 Date d = fmt.parse("01/22/92 04:52:00 GMT", p0);
681 if(p0.equals(new ParsePosition(0)))
682 errln("Fail: failed to parse 'GMT'");
683 // In the failure case an exception is thrown by parse();
684 // if no exception is thrown, the test passes.
689 * SimpleDateFormat incorrect handling of 2 single quotes in format()
691 public void Test4151631() {
693 "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'";
694 logln("pattern=" + pattern);
695 SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
696 StringBuffer result = new StringBuffer("");
697 FieldPosition pos = new FieldPosition(0);
698 Calendar cal = Calendar.getInstance();
700 cal.set(1998, Calendar.JUNE, 30, 13, 30, 0);
701 Date d = cal.getTime();
702 result = format.format(d, result, pos);
703 if (!result.toString().equals("TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')")) {
704 errln("Fail: result=" + result);
706 logln("Pass: result=" + result);
712 * 'z' at end of date format throws index exception in SimpleDateFormat
713 * CANNOT REPRODUCE THIS BUG ON 1.2FCS
715 public void Test4151706() {
716 String dateString = "Thursday, 31-Dec-98 23:00:00 GMT";
717 SimpleDateFormat fmt = new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss z", Locale.US);
718 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
720 cal.set(1998, Calendar.DECEMBER, 31, 23, 0, 0);
723 d = fmt.parse(dateString);
724 // {sfb} what about next two lines?
725 if (d.getTime() != cal.getTime().getTime())
726 errln("Incorrect value: " + d);
727 } catch (Exception e) {
730 StringBuffer temp = new StringBuffer("");
731 FieldPosition pos = new FieldPosition(0);
732 logln(dateString + " . " + fmt.format(d, temp, pos));
737 * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate
738 * of some other bug that has been fixed.
740 public void Test4162071() {
741 String dateString = "Thu, 30-Jul-1999 11:51:14 GMT";
742 String format = "EEE', 'dd-MMM-yyyy HH:mm:ss z"; // RFC 822/1123
743 SimpleDateFormat df = new SimpleDateFormat(format, Locale.US);
745 Date x = df.parse(dateString);
746 StringBuffer temp = new StringBuffer("");
747 FieldPosition pos = new FieldPosition(0);
748 logln(dateString + " -> " + df.format(x, temp, pos));
749 } catch (Exception e) {
750 errln("Parse format \"" + format + "\" failed.");
755 * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" . 1999).
757 public void Test4182066() {
758 SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy", Locale.US);
759 SimpleDateFormat dispFmt = new SimpleDateFormat("MMM dd yyyy HH:mm:ss GG", Locale.US);
760 /* We expect 2-digit year formats to put 2-digit years in the right
761 * window. Out of range years, that is, anything less than "00" or
762 * greater than "99", are treated as literal years. So "1/2/3456"
763 * becomes 3456 AD. Likewise, "1/2/-3" becomes -3 AD == 2 BC.
765 final String STRINGS[] =
766 {"02/29/00", "01/23/01", "04/05/-1", "01/23/-9", "11/12/1314", "10/31/1", "09/12/+1", "09/12/001",};
767 int STRINGS_COUNT = STRINGS.length;
769 Calendar cal = Calendar.getInstance();
770 Date FAIL_DATE = cal.getTime();
772 cal.set(2000, Calendar.FEBRUARY, 29);
773 Date d0 = cal.getTime();
775 cal.set(2001, Calendar.JANUARY, 23);
776 Date d1 = cal.getTime();
778 cal.set(-1, Calendar.APRIL, 5);
779 Date d2 = cal.getTime();
781 cal.set(-9, Calendar.JANUARY, 23);
782 Date d3 = cal.getTime();
784 cal.set(1314, Calendar.NOVEMBER, 12);
785 Date d4 = cal.getTime();
787 cal.set(1, Calendar.OCTOBER, 31);
788 Date d5 = cal.getTime();
790 cal.set(1, Calendar.SEPTEMBER, 12);
791 Date d7 = cal.getTime();
792 Date DATES[] = {d0, d1, d2, d3, d4, d5, FAIL_DATE, d7};
796 for (int i = 0; i < STRINGS_COUNT; ++i) {
797 String str = STRINGS[i];
798 Date expected = DATES[i];
801 actual = fmt.parse(str);
802 } catch (ParseException e) {
806 if ((actual.getTime()) == FAIL_DATE.getTime()) {
810 actStr = ((DateFormat) dispFmt).format(actual);
813 if (expected.getTime() == (actual.getTime())) {
814 out += str + " => " + actStr + "\n";
817 if (expected.getTime() == FAIL_DATE.getTime()) {
821 expStr = ((DateFormat) dispFmt).format(expected);
823 out += "FAIL: " + str + " => " + actStr + ", expected " + expStr + "\n";
835 * j32 {JDK Bug 4210209 4209272}
836 * DateFormat cannot parse Feb 29 2000 when setLenient(false)
838 public void Test4210209() {
840 String pattern = "MMM d, yyyy";
841 DateFormat fmt = new SimpleDateFormat(pattern, Locale.US);
842 DateFormat disp = new SimpleDateFormat("MMM dd yyyy GG", Locale.US);
844 Calendar calx = fmt.getCalendar();
845 calx.setLenient(false);
846 Calendar calendar = Calendar.getInstance();
848 calendar.set(2000, Calendar.FEBRUARY, 29);
849 Date d = calendar.getTime();
850 String s = fmt.format(d);
851 logln(disp.format(d) + " f> " + pattern + " => \"" + s + "\"");
852 ParsePosition pos = new ParsePosition(0);
853 d = fmt.parse(s, pos);
854 logln("\"" + s + "\" p> " + pattern + " => " +
855 (d!=null?disp.format(d):"null"));
856 logln("Parse pos = " + pos.getIndex() + ", error pos = " + pos.getErrorIndex());
857 if (pos.getErrorIndex() != -1) {
858 errln("FAIL: Error index should be -1");
861 // The underlying bug is in GregorianCalendar. If the following lines
862 // succeed, the bug is fixed. If the bug isn't fixed, they will throw
864 GregorianCalendar cal = new GregorianCalendar();
866 cal.setLenient(false);
867 cal.set(2000, Calendar.FEBRUARY, 29); // This should work!
869 logln("Attempt to set Calendar to Feb 29 2000: " + disp.format(d));
872 public void Test714() {
874 TimeZone defaultTZ = TimeZone.getDefault();
875 TimeZone PST = TimeZone.getTimeZone("PST");
876 int defaultOffset = defaultTZ.getRawOffset();
877 int PSTOffset = PST.getRawOffset();
878 Date d = new Date(978103543000l - (defaultOffset - PSTOffset));
879 d = new Date(d.getTime() - (defaultTZ.inDaylightTime(d) ? 3600000 : 0));
880 DateFormat fmt = DateFormat.getDateTimeInstance(-1, DateFormat.MEDIUM, Locale.US);
881 String tests = "7:25:43 AM";
882 String s = fmt.format(d);
883 if (!s.equals(tests)) {
884 errln("Fail: " + s + " != " + tests);
886 logln("OK: " + s + " == " + tests);
890 public void Test_GEec() {
891 class PatternAndResult {
892 private String pattern;
893 private String result;
894 PatternAndResult(String pat, String res) {
898 public String getPattern() { return pattern; }
899 public String getResult() { return result; }
901 final PatternAndResult[] tests = {
902 new PatternAndResult( "dd MMM yyyy GGG", "02 Jul 2008 AD" ),
903 new PatternAndResult( "dd MMM yyyy GGGGG", "02 Jul 2008 A" ),
904 new PatternAndResult( "e dd MMM yyyy", "4 02 Jul 2008" ),
905 new PatternAndResult( "ee dd MMM yyyy", "04 02 Jul 2008" ),
906 new PatternAndResult( "c dd MMM yyyy", "4 02 Jul 2008" ),
907 new PatternAndResult( "cc dd MMM yyyy", "4 02 Jul 2008" ),
908 new PatternAndResult( "eee dd MMM yyyy", "Wed 02 Jul 2008" ),
909 new PatternAndResult( "EEE dd MMM yyyy", "Wed 02 Jul 2008" ),
910 new PatternAndResult( "EE dd MMM yyyy", "Wed 02 Jul 2008" ),
911 new PatternAndResult( "eeee dd MMM yyyy", "Wednesday 02 Jul 2008" ),
912 new PatternAndResult( "eeeee dd MMM yyyy", "W 02 Jul 2008" ),
913 new PatternAndResult( "e ww YYYY", "4 27 2008" ),
914 new PatternAndResult( "c ww YYYY", "4 27 2008" ),
916 ULocale loc = ULocale.ENGLISH;
917 TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
918 Calendar cal = new GregorianCalendar(tz, loc);
919 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MMM-dd", loc);
920 for ( int i = 0; i < tests.length; i++ ) {
921 PatternAndResult item = tests[i];
922 dateFormat.applyPattern( item.getPattern() );
923 cal.set(2008, 6, 2, 5, 0); // 2008 July 02 5 AM PDT
924 StringBuffer buf = new StringBuffer(32);
925 FieldPosition fp = new FieldPosition(DateFormat.YEAR_FIELD);
926 dateFormat.format(cal, buf, fp);
927 if ( buf.toString().compareTo(item.getResult()) != 0 ) {
928 errln("for pattern " + item.getPattern() + ", expected " + item.getResult() + ", got " + buf );
930 ParsePosition pos = new ParsePosition(0);
931 dateFormat.parse( item.getResult(), cal, pos);
932 int year = cal.get(Calendar.YEAR);
933 int month = cal.get(Calendar.MONTH);
934 int day = cal.get(Calendar.DATE);
935 if ( year != 2008 || month != 6 || day != 2 ) {
936 errln("use pattern " + item.getPattern() + " to parse " + item.getResult() +
937 ", expected y2008 m6 d2, got " + year + " " + month + " " + day );
942 static final char kArabicZero = 0x0660;
943 static final char kHindiZero = 0x0966;
944 static final char kLatinZero = 0x0030;
946 public void TestHindiArabicDigits()
953 DateFormat df = DateFormat.getInstance(new GregorianCalendar(), new ULocale("hi_IN@numbers=deva"));
954 what = "Gregorian Calendar, hindi";
955 s = df.format(new Date(0)); /* 31/12/1969 */
956 logln(what + "=" + s);
958 if(first<kHindiZero || first>(kHindiZero+9)) {
959 errln(what + "- wrong digit, got " + s + " (integer digit value " + new Integer((int)first).toString());
964 DateFormat df = DateFormat.getInstance(new IslamicCalendar(), new Locale("ar","IQ"));
965 s = df.format(new Date(0)); /* 21/10/1989 */
966 what = "Islamic Calendar, Arabic";
967 logln(what + ": " + s);
969 if(first<kArabicZero || first>(kArabicZero+9)) {
970 errln(what + " wrong digit, got " + s + " (integer digit value " + new Integer((int)first).toString());
975 DateFormat df = DateFormat.getInstance(new GregorianCalendar(), new Locale("ar","IQ"));
976 s = df.format(new Date(0)); /* 31/12/1969 */
977 what = "Gregorian, ar_IQ, df.getInstance";
978 logln(what + ": " + s);
980 if(first<kArabicZero || first>(kArabicZero+9)) {
981 errln(what + " wrong digit but got " + s + " (integer digit value " + new Integer((int)first).toString());
985 DateFormat df = DateFormat.getInstance(new GregorianCalendar(), new Locale("mt","MT"));
986 s = df.format(new Date(0)); /* 31/12/1969 */
987 what = "Gregorian, mt_MT, df.getInstance";
988 logln(what + ": " + s);
990 if(first<kLatinZero || first>(kLatinZero+9)) {
991 errln(what + " wrong digit but got " + s + " (integer digit value " + new Integer((int)first).toString());
996 DateFormat df = DateFormat.getInstance(new IslamicCalendar(), new Locale("ar","IQ"));
997 s = df.format(new Date(0)); /* 31/12/1969 */
998 what = "Islamic calendar, ar_IQ, df.getInstance";
999 logln(what+ ": " + s);
1000 first = s.charAt(0);
1001 if(first<kArabicZero || first>(kArabicZero+9)) {
1002 errln(what + " wrong digit but got " + s + " (integer digit value " + new Integer((int)first).toString());
1007 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, new Locale("ar","IQ"));
1008 s = df.format(new Date(0)); /* 31/12/1969 */
1009 what = "ar_IQ, getDateTimeInstance";
1010 logln(what+ ": " + s);
1011 first = s.charAt(0);
1012 if(first<kArabicZero || first>(kArabicZero+9)) {
1013 errln(what + " wrong digit but got " + s + " (integer digit value " + new Integer((int)first).toString());
1018 DateFormat df = DateFormat.getInstance(new JapaneseCalendar(), new Locale("ar","IQ"));
1019 s = df.format(new Date(0)); /* 31/12/1969 */
1020 what = "ar_IQ, Japanese Calendar, getInstance";
1021 logln(what+ ": " + s);
1022 first = s.charAt(0);
1023 if(first<kArabicZero || first>(kArabicZero+9)) {
1024 errln(what + " wrong digit but got " + s + " (integer digit value " + new Integer((int)first).toString());
1030 // Some ICU4J 3.6 data files contain garbage data which prevent the code to resolve another
1031 // bundle as an alias. zh_TW should be equivalent to zh_Hant_TW
1032 public void TestT5683() {
1033 Locale[] aliasLocales = {
1034 new Locale("zh", "CN"),
1035 new Locale("zh", "TW"),
1036 new Locale("zh", "HK"),
1037 new Locale("zh", "SG"),
1038 new Locale("zh", "MO")
1041 ULocale[] canonicalLocales = {
1042 new ULocale("zh_Hans_CN"),
1043 new ULocale("zh_Hant_TW"),
1044 new ULocale("zh_Hant_HK"),
1045 new ULocale("zh_Hans_SG"),
1046 new ULocale("zh_Hant_MO")
1049 Date d = new Date(0);
1051 for (int i = 0; i < aliasLocales.length; i++) {
1052 DateFormat dfAlias = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, aliasLocales[i]);
1053 DateFormat dfCanonical = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, canonicalLocales[i]);
1055 String sAlias = dfAlias.format(d);
1056 String sCanonical = dfCanonical.format(d);
1058 if (!sAlias.equals(sCanonical)) {
1059 errln("Fail: The format result for locale " + aliasLocales[i] + " is different from the result for locale " + canonicalLocales[i]
1060 + ": " + sAlias + "[" + aliasLocales[i] + "] / " + sCanonical + "[" + canonicalLocales[i] + "]");
1065 // Note: The purpose of this test case is a little bit questionable. This test
1066 // case expects Islamic month name is different from Gregorian month name.
1067 // However, some locales (in this code, zh_CN) may intentionally use the same
1068 // month name for both Gregorian and Islamic calendars. See #9645.
1069 public void Test5006GetShortMonths() throws Exception {
1070 // Currently supported NLV locales
1071 Locale ENGLISH = new Locale("en", "US"); // We don't support 'en' alone
1072 Locale ARABIC = new Locale("ar", "");
1073 Locale CZECH = new Locale("cs", "");
1074 Locale GERMAN = new Locale("de", "");
1075 Locale GREEK = new Locale("el", "");
1076 Locale SPANISH = new Locale("es", "");
1077 Locale FRENCH = new Locale("fr", "");
1078 Locale HUNGARIAN = new Locale("hu", "");
1079 Locale ITALIAN = new Locale("it", "");
1080 Locale HEBREW = new Locale("iw", "");
1081 Locale JAPANESE = new Locale("ja", "");
1082 Locale KOREAN = new Locale("ko", "");
1083 Locale POLISH = new Locale("pl", "");
1084 Locale PORTUGUESE = new Locale("pt", "BR");
1085 Locale RUSSIAN = new Locale("ru", "");
1086 Locale TURKISH = new Locale("tr", "");
1087 Locale CHINESE_SIMPLIFIED = new Locale("zh", "CN");
1088 Locale CHINESE_TRADITIONAL = new Locale("zh", "TW");
1090 Locale[] locales = new Locale[] { ENGLISH, ARABIC, CZECH, GERMAN, GREEK, SPANISH, FRENCH,
1091 HUNGARIAN, ITALIAN, HEBREW, JAPANESE, KOREAN, POLISH, PORTUGUESE, RUSSIAN, TURKISH,
1092 CHINESE_SIMPLIFIED, CHINESE_TRADITIONAL };
1094 String[] islamicCivilTwelfthMonthLocalized = new String[locales.length];
1095 String[] islamicTwelfthMonthLocalized = new String[locales.length];
1096 String[] gregorianTwelfthMonthLocalized = new String[locales.length];
1098 for (int i = 0; i < locales.length; i++) {
1100 Locale locale = locales[i];
1103 com.ibm.icu.util.Calendar islamicCivilCalendar = new com.ibm.icu.util.IslamicCalendar(locale);
1104 com.ibm.icu.text.SimpleDateFormat islamicCivilDateFormat = (com.ibm.icu.text.SimpleDateFormat) islamicCivilCalendar
1105 .getDateTimeFormat(com.ibm.icu.text.DateFormat.FULL, -1, locale);
1106 com.ibm.icu.text.DateFormatSymbols islamicCivilDateFormatSymbols = islamicCivilDateFormat
1107 .getDateFormatSymbols();
1109 String[] shortMonthsCivil = islamicCivilDateFormatSymbols.getShortMonths();
1110 String twelfthMonthLocalizedCivil = shortMonthsCivil[11];
1112 islamicCivilTwelfthMonthLocalized[i] = twelfthMonthLocalizedCivil;
1114 com.ibm.icu.util.IslamicCalendar islamicCalendar = new com.ibm.icu.util.IslamicCalendar(locale);
1115 islamicCalendar.setCivil(false);
1116 com.ibm.icu.text.SimpleDateFormat islamicDateFormat = (com.ibm.icu.text.SimpleDateFormat) islamicCalendar
1117 .getDateTimeFormat(com.ibm.icu.text.DateFormat.FULL, -1, locale);
1118 com.ibm.icu.text.DateFormatSymbols islamicDateFormatSymbols = islamicDateFormat
1119 .getDateFormatSymbols();
1121 String[] shortMonths = islamicDateFormatSymbols.getShortMonths();
1122 String twelfthMonthLocalized = shortMonths[11];
1124 islamicTwelfthMonthLocalized[i] = twelfthMonthLocalized;
1127 com.ibm.icu.util.Calendar gregorianCalendar = new com.ibm.icu.util.GregorianCalendar(
1129 com.ibm.icu.text.SimpleDateFormat gregorianDateFormat = (com.ibm.icu.text.SimpleDateFormat) gregorianCalendar
1130 .getDateTimeFormat(com.ibm.icu.text.DateFormat.FULL, -1, locale);
1132 com.ibm.icu.text.DateFormatSymbols gregorianDateFormatSymbols = gregorianDateFormat
1133 .getDateFormatSymbols();
1134 shortMonths = gregorianDateFormatSymbols.getShortMonths();
1135 twelfthMonthLocalized = shortMonths[11];
1137 gregorianTwelfthMonthLocalized[i] = twelfthMonthLocalized;
1142 for (int i = 0; i < locales.length; i++) {
1144 String gregorianTwelfthMonth = gregorianTwelfthMonthLocalized[i];
1145 String islamicCivilTwelfthMonth = islamicCivilTwelfthMonthLocalized[i];
1146 String islamicTwelfthMonth = islamicTwelfthMonthLocalized[i];
1148 logln(locales[i] + ": g:" + gregorianTwelfthMonth + ", ic:" + islamicCivilTwelfthMonth + ", i:"+islamicTwelfthMonth);
1149 if (gregorianTwelfthMonth.equalsIgnoreCase(islamicTwelfthMonth)) {
1150 // Simplified Chinese uses numeric month for both Gregorian/Islamic calendars
1151 if (locales[i] != CHINESE_SIMPLIFIED) {
1152 errln(locales[i] + ": gregorian and islamic are same: " + gregorianTwelfthMonth
1153 + ", " + islamicTwelfthMonth);
1157 if (gregorianTwelfthMonth.equalsIgnoreCase(islamicCivilTwelfthMonth)) {
1158 // Simplified Chinese uses numeric month for both Gregorian/Islamic calendars
1159 if (locales[i] != CHINESE_SIMPLIFIED) {
1160 errln(locales[i] + ": gregorian and islamic-civil are same: " + gregorianTwelfthMonth
1161 + ", " + islamicCivilTwelfthMonth);
1164 if (!islamicTwelfthMonth.equalsIgnoreCase(islamicCivilTwelfthMonth)) {
1165 errln(locales[i] + ": islamic-civil and islamic are NOT same: " + islamicCivilTwelfthMonth
1166 + ", " + islamicTwelfthMonth);
1171 public void TestParsing() {
1172 String pattern = "EEE-WW-MMMM-yyyy";
1173 String text = "mon-02-march-2011";
1174 int expectedDay = 7;
1176 SimpleDateFormat format = new SimpleDateFormat(pattern);
1177 Calendar cal = GregorianCalendar.getInstance(Locale.US);
1178 ParsePosition pos = new ParsePosition(0);
1181 format.parse(text, cal, pos);
1182 } catch (Exception e) {
1183 errln("Fail parsing: " + e);
1186 if (cal.get(Calendar.DAY_OF_MONTH) != expectedDay) {
1187 errln("Parsing failed: day of month should be '7' with pattern: \"" + pattern + "\" for text: \"" + text + "\"");
1191 // Date formatting with Dangi calendar in en locale (#9987)
1192 public void TestDangiFormat() {
1193 DateFormat fmt = DateFormat.getDateInstance(DateFormat.MEDIUM, new ULocale("en@calendar=dangi"));
1194 String calType = fmt.getCalendar().getType();
1195 assertEquals("Incorrect calendar type used by the date format instance", "dangi", calType);
1197 GregorianCalendar gcal = new GregorianCalendar();
1198 gcal.set(2013, Calendar.MARCH, 1, 0, 0, 0);
1199 Date d = gcal.getTime();
1201 String dangiDateStr = fmt.format(d);
1202 assertEquals("Bad date format", "Mo1 20, gui-si", dangiDateStr);
1205 public void TestT10110() {
1207 SimpleDateFormat formatter = new SimpleDateFormat("Gy年M月d日E", new Locale("zh_Hans"));
1208 /* Object parsed = */ formatter.parseObject("610000");
1210 catch(ParseException pe) {
1213 catch(Throwable t) {
1214 errln("ParseException not thrown for bad pattern! exception was: " + t.getLocalizedMessage());
1217 errln("No exception thrown at all for bad pattern!");