+void DateFormatTest::TestPatternFromSkeleton() {
+ static const struct {
+ const Locale& locale;
+ const char* const skeleton;
+ const char* const pattern;
+ } TESTDATA[] = {
+ // Ticket #11985
+ {Locale::getEnglish(), "jjmm", "h:mm a"},
+ {Locale::getEnglish(), "JJmm", "hh:mm"},
+ {Locale::getGerman(), "jjmm", "HH:mm"},
+ {Locale::getGerman(), "JJmm", "HH:mm"}
+ };
+
+ for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<DateFormat> fmt(
+ DateFormat::createInstanceForSkeleton(
+ TESTDATA[i].skeleton, TESTDATA[i].locale, status));
+ if (!assertSuccess("createInstanceForSkeleton", status)) {
+ return;
+ }
+ UnicodeString pattern;
+ static_cast<const SimpleDateFormat*>(fmt.getAlias())->toPattern(pattern);
+ assertEquals("Format pattern", TESTDATA[i].pattern, pattern);
+ }
+}
+
+void DateFormatTest::TestAmPmMidnightNoon() {
+ // Some times on 2015-11-13 (UTC+0).
+ UDate k000000 = 1447372800000.0;
+ UDate k000030 = 1447372830000.0;
+ UDate k003000 = 1447374600000.0;
+ UDate k060000 = 1447394400000.0;
+ UDate k120000 = 1447416000000.0;
+ UDate k180000 = 1447437600000.0;
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ SimpleDateFormat sdf(UnicodeString(), errorCode);
+ if (U_FAILURE(errorCode)) {
+ dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+ return;
+ }
+ const TimeZone *tz = TimeZone::getGMT();
+ sdf.setTimeZone(*tz);
+ UnicodeString out;
+
+ // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+ // For ICU 57 output of "midnight" is temporarily suppressed.
+
+ // Short.
+ sdf.applyPattern(UnicodeString("hh:mm:ss bbb"));
+
+ // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm bbb"));
+
+ // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh bbb"));
+
+ // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
+ // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
+ // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+ assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
+
+ // Wide.
+ sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
+
+ // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm bbbb"));
+
+ // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh bbbb"));
+
+ // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
+ // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
+ // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+ assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
+
+ // Narrow.
+ sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb"));
+
+ // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm bbbbb"));
+
+ // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh bbbbb"));
+
+ // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove()));
+ // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
+ assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove()));
+ // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
+ assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove()));
+}
+
+void DateFormatTest::TestFlexibleDayPeriod() {
+ // Some times on 2015-11-13 (UTC+0).
+ UDate k000000 = 1447372800000.0;
+ UDate k000030 = 1447372830000.0;
+ UDate k003000 = 1447374600000.0;
+ UDate k060000 = 1447394400000.0;
+ UDate k120000 = 1447416000000.0;
+ UDate k180000 = 1447437600000.0;
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ SimpleDateFormat sdf(UnicodeString(), errorCode);
+ if (U_FAILURE(errorCode)) {
+ dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+ return;
+ }
+ const TimeZone *tz = TimeZone::getGMT();
+ sdf.setTimeZone(*tz);
+ UnicodeString out;
+
+ // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+ // For ICU 57 output of "midnight" is temporarily suppressed.
+
+ // Short.
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBB"));
+
+ // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm BBB"));
+
+ // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh BBB"));
+
+ // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+ // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+ // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+ assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
+
+ // Wide.
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+ // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm BBBB"));
+
+ // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh BBBB"));
+
+ // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+ assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+ assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove()));
+ assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+
+ // Narrow.
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB"));
+
+ // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
+ assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm BBBBB"));
+
+ // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh BBBBB"));
+
+ // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
+ assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+ // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
+ assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+ // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
+ assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
+}
+
+void DateFormatTest::TestDayPeriodWithLocales() {
+ // Some times on 2015-11-13 (UTC+0).
+ UDate k000000 = 1447372800000.0;
+ UDate k010000 = 1447376400000.0;
+ UDate k120000 = 1447416000000.0;
+ UDate k220000 = 1447452000000.0;
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ const TimeZone *tz = TimeZone::getGMT();
+ UnicodeString out;
+
+ // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+ // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed.
+
+ // Locale de has a word for midnight, but not noon.
+ SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode);
+ if (U_FAILURE(errorCode)) {
+ dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+ return;
+ }
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
+
+ // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht",
+ // sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM" /* change for Apple data */,
+ sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM" /* change for Apple data */,
+ sdf.format(k120000, out.remove()));
+
+ // Locale ee has a rule that wraps around midnight (21h - 4h).
+ sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+ assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(),
+ sdf.format(k220000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(),
+ sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(),
+ sdf.format(k010000, out.remove()));
+
+ // Locale root has rules for AM/PM only.
+ sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+ assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM",
+ sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM",
+ sdf.format(k120000, out.remove()));
+
+ // Empty string should behave exactly as root.
+ sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+ assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM",
+ sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM",
+ sdf.format(k120000, out.remove()));
+
+ // Locale en_US should fall back to en.
+ sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+ // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight",
+ // sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night",
+ sdf.format(k000000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night",
+ sdf.format(k010000, out.remove()));
+ assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon",
+ sdf.format(k120000, out.remove()));
+
+ // Locale es_CO should not fall back to es and should have a
+ // different string for 1 in the morning.
+ // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada")
+ sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+ assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", UnicodeString("01:00:00 de la ma\\u00F1ana").unescape(),
+ sdf.format(k010000, out.remove()));
+
+ sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode);
+ sdf.setTimeZone(*tz);
+
+ sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+ assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada",
+ sdf.format(k010000, out.remove()));
+}
+
+void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() {
+ // Some times on 2015-11-13 (UTC+0).
+ UDate k000000 = 1447372800000.0;
+ UDate k000030 = 1447372830000.0;
+ UDate k003000 = 1447374600000.0;
+ UDate k060030 = 1447394430000.0;
+ UDate k063000 = 1447396200000.0;
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ const TimeZone *tz = TimeZone::getGMT();
+ UnicodeString out;
+
+ // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+ // For ICU 57 output of "midnight" is temporarily suppressed.
+
+ // Seconds field is not present.
+
+ // Apply pattern through constructor to make sure parsePattern() is called during initialization.
+ SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode);
+ if (U_FAILURE(errorCode)) {
+ dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+ return;
+ }
+ sdf.setTimeZone(*tz);
+
+ // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight",
+ // sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM",
+ sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM",
+ sdf.format(k060030, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB"));
+
+ // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight",
+ // sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night",
+ sdf.format(k000030, out.remove()));
+ assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning",
+ sdf.format(k060030, out.remove()));
+
+ // Minutes field is not present.
+ sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb"));
+
+ // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight",
+ // sdf.format(k003000, out.remove()));
+ assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM",
+ sdf.format(k003000, out.remove()));
+ assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM",
+ sdf.format(k063000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB"));
+
+ // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight",
+ // sdf.format(k003000, out.remove()));
+ assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night",
+ sdf.format(k003000, out.remove()));
+ assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning",
+ sdf.format(k063000, out.remove()));
+
+ // Minutes and seconds fields appear after day periods.
+ sdf.applyPattern(UnicodeString("bbbb hh:mm:ss"));
+
+ // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00",
+ // sdf.format(k000000, out.remove()));
+ assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00",
+ sdf.format(k000000, out.remove()));
+ assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30",
+ sdf.format(k000030, out.remove()));
+ assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00",
+ sdf.format(k003000, out.remove()));
+
+ sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
+
+ // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00",
+ // sdf.format(k000000, out.remove()));
+ assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00",
+ sdf.format(k000000, out.remove()));
+ assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
+ sdf.format(k000030, out.remove()));
+ assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00",
+ sdf.format(k003000, out.remove()));
+
+ // Confirm applyPattern() reparses the pattern string.
+ sdf.applyPattern(UnicodeString("BBBB hh"));
+ // assertEquals("BBBB hh | 00:00:30", "midnight 12",
+ // sdf.format(k000030, out.remove()));
+ assertEquals("BBBB hh | 00:00:30", "at night 12",
+ sdf.format(k000030, out.remove()));
+
+ sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'"));
+ // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss",
+ // sdf.format(k000030, out.remove()));
+ assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss",
+ sdf.format(k000030, out.remove()));
+
+ sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
+ assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
+ sdf.format(k000030, out.remove()));
+}
+
+void DateFormatTest::TestDayPeriodParsing() {
+ // Some times on 2015-11-13 (UTC+0).
+ UDate k000000 = 1447372800000.0;
+ UDate k003700 = 1447375020000.0;
+ UDate k010000 = 1447376400000.0;
+ UDate k013000 = 1447378200000.0;
+ UDate k030000 = 1447383600000.0;
+ UDate k090000 = 1447405200000.0;
+ UDate k120000 = 1447416000000.0;
+ UDate k130000 = 1447419600000.0;
+ UDate k133700 = 1447421820000.0;
+ UDate k150000 = 1447426800000.0;
+ UDate k190000 = 1447441200000.0;
+ UDate k193000 = 1447443000000.0;
+ UDate k200000 = 1447444800000.0;
+ UDate k210000 = 1447448400000.0;
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ SimpleDateFormat sdf(UnicodeString(), errorCode);
+ if (U_FAILURE(errorCode)) {
+ dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+ return;
+ }
+ const TimeZone *tz = TimeZone::getGMT();
+ sdf.setTimeZone(*tz);
+ UnicodeString out;
+
+ // 'B' -- flexible day periods
+ // A day period on its own parses to the center of that period.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd B"));
+ assertEquals("yyyy-MM-dd B | 2015-11-13 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd B | 2015-11-13 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
+ assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon",
+ k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode));
+ assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening",
+ k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode));
+ assertEquals("yyyy-MM-dd B | 2015-11-13 at night",
+ k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode));
+
+ // If time and day period are consistent with each other then time is parsed accordingly.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night",
+ k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon",
+ k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning",
+ k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night",
+ k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
+
+ // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
+ // to be in 24-hour format).
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
+
+ // Hour 0 is synonymous with hour 12 when parsed with 'h'.
+ // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
+
+ // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
+
+ // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
+ // day period into account in parsing.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night",
+ k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon",
+ k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning",
+ k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night",
+ k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
+
+ // If a 12-hour time and the day period don't agree with each other, time is parsed as close
+ // to the given day period as possible.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+
+ // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon",
+ k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode));
+ // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
+ assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night",
+ k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode));
+
+ // 'b' -- fixed day periods (AM, PM, midnight, noon)
+ // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
+ // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd b"));
+ assertEquals("yyyy-MM-dd b | 2015-11-13 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd b | 2015-11-13 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
+
+ // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM",
+ k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM",
+ k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode));
+
+ // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+
+ // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
+ // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
+ assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon",
+ k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
+
+ // Hour 0 is synonymous with hour 12 when parsed with 'h'.
+ // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight",
+ k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon",
+ k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
+
+ // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
+ assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon",
+ k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
+
+ // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
+ // the version that's closer to the period given.
+ sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight",
+ k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode));
+ assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon",
+ k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode));
+}