From 863582c2a48de428389b2b2b615daf9c92b2636d Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Fri, 31 Jul 2020 05:37:50 +0000 Subject: [PATCH] ICU-20465 Calendar/DateFormat listen to tz extension See #1176 --- icu4c/source/i18n/calendar.cpp | 2 +- icu4c/source/i18n/cecal.cpp | 2 +- icu4c/source/i18n/chnsecal.cpp | 4 +- icu4c/source/i18n/gregocal.cpp | 2 +- icu4c/source/i18n/hebrwcal.cpp | 2 +- icu4c/source/i18n/indiancal.cpp | 2 +- icu4c/source/i18n/islamcal.cpp | 2 +- icu4c/source/i18n/persncal.cpp | 2 +- icu4c/source/i18n/smpdtfmt.cpp | 3 +- icu4c/source/i18n/timezone.cpp | 18 ++++ icu4c/source/i18n/unicode/timezone.h | 11 +++ icu4c/source/test/intltest/caltest.cpp | 52 +++++++++++ icu4c/source/test/intltest/caltest.h | 2 + icu4c/source/test/intltest/dtfmttst.cpp | 65 ++++++++++++++ icu4c/source/test/intltest/dtfmttst.h | 2 + .../core/src/com/ibm/icu/util/CECalendar.java | 4 +- .../core/src/com/ibm/icu/util/Calendar.java | 4 +- .../src/com/ibm/icu/util/ChineseCalendar.java | 4 +- .../com/ibm/icu/util/EthiopicCalendar.java | 4 +- .../com/ibm/icu/util/GregorianCalendar.java | 4 +- .../src/com/ibm/icu/util/HebrewCalendar.java | 4 +- .../src/com/ibm/icu/util/IndianCalendar.java | 4 +- .../src/com/ibm/icu/util/IslamicCalendar.java | 4 +- .../src/com/ibm/icu/util/PersianCalendar.java | 4 +- .../core/src/com/ibm/icu/util/TimeZone.java | 28 ++++++ .../test/calendar/CalendarRegressionTest.java | 64 ++++++++++++++ .../icu/dev/test/format/DateFormatTest.java | 87 +++++++++++++++++++ 27 files changed, 358 insertions(+), 28 deletions(-) diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 981f09c5740..9497a85fd05 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -870,7 +870,7 @@ Calendar::createInstance(const TimeZone& zone, UErrorCode& success) Calendar* U_EXPORT2 Calendar::createInstance(const Locale& aLocale, UErrorCode& success) { - return createInstance(TimeZone::createDefault(), aLocale, success); + return createInstance(TimeZone::forLocaleOrDefault(aLocale), aLocale, success); } // ------------------------------------- Adopting diff --git a/icu4c/source/i18n/cecal.cpp b/icu4c/source/i18n/cecal.cpp index 00faa8ac07a..cb97c40a3c7 100644 --- a/icu4c/source/i18n/cecal.cpp +++ b/icu4c/source/i18n/cecal.cpp @@ -49,7 +49,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = { //------------------------------------------------------------------------- CECalendar::CECalendar(const Locale& aLocale, UErrorCode& success) -: Calendar(TimeZone::createDefault(), aLocale, success) +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success) { setTimeInMillis(getNow(), success); } diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp index 4c038127159..f8fb4a40f14 100644 --- a/icu4c/source/i18n/chnsecal.cpp +++ b/icu4c/source/i18n/chnsecal.cpp @@ -123,7 +123,7 @@ ChineseCalendar* ChineseCalendar::clone() const { } ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success) -: Calendar(TimeZone::createDefault(), aLocale, success), +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success), isLeapYear(FALSE), fEpochYear(CHINESE_EPOCH_YEAR), fZoneAstroCalc(getChineseCalZoneAstroCalc()) @@ -133,7 +133,7 @@ ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success) ChineseCalendar::ChineseCalendar(const Locale& aLocale, int32_t epochYear, const TimeZone* zoneAstroCalc, UErrorCode &success) -: Calendar(TimeZone::createDefault(), aLocale, success), +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success), isLeapYear(FALSE), fEpochYear(epochYear), fZoneAstroCalc(zoneAstroCalc) diff --git a/icu4c/source/i18n/gregocal.cpp b/icu4c/source/i18n/gregocal.cpp index 6b15171c12b..7ca58268456 100644 --- a/icu4c/source/i18n/gregocal.cpp +++ b/icu4c/source/i18n/gregocal.cpp @@ -185,7 +185,7 @@ fIsGregorian(TRUE), fInvertGregorian(FALSE) // ------------------------------------- GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status) -: Calendar(TimeZone::createDefault(), aLocale, status), +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, status), fGregorianCutover(kPapalCutover), fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582), fIsGregorian(TRUE), fInvertGregorian(FALSE) diff --git a/icu4c/source/i18n/hebrwcal.cpp b/icu4c/source/i18n/hebrwcal.cpp index c8fb8a16795..2b68587c9ee 100644 --- a/icu4c/source/i18n/hebrwcal.cpp +++ b/icu4c/source/i18n/hebrwcal.cpp @@ -155,7 +155,7 @@ U_NAMESPACE_BEGIN * @internal */ HebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success) -: Calendar(TimeZone::createDefault(), aLocale, success) +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success) { setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. diff --git a/icu4c/source/i18n/indiancal.cpp b/icu4c/source/i18n/indiancal.cpp index f1ab853b948..bf5da585e21 100644 --- a/icu4c/source/i18n/indiancal.cpp +++ b/icu4c/source/i18n/indiancal.cpp @@ -40,7 +40,7 @@ IndianCalendar* IndianCalendar::clone() const { } IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success) - : Calendar(TimeZone::createDefault(), aLocale, success) + : Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success) { setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. } diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp index 582b3365a64..fefe9b41938 100644 --- a/icu4c/source/i18n/islamcal.cpp +++ b/icu4c/source/i18n/islamcal.cpp @@ -232,7 +232,7 @@ IslamicCalendar* IslamicCalendar::clone() const { } IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECalculationType type) -: Calendar(TimeZone::createDefault(), aLocale, success), +: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success), cType(type) { setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. diff --git a/icu4c/source/i18n/persncal.cpp b/icu4c/source/i18n/persncal.cpp index 26fd294ceeb..d30577f337f 100644 --- a/icu4c/source/i18n/persncal.cpp +++ b/icu4c/source/i18n/persncal.cpp @@ -79,7 +79,7 @@ PersianCalendar* PersianCalendar::clone() const { } PersianCalendar::PersianCalendar(const Locale& aLocale, UErrorCode& success) - : Calendar(TimeZone::createDefault(), aLocale, success) + : Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success) { setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. } diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index d704642b053..8beadd6eca3 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -848,7 +848,8 @@ Calendar* SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status) { if(!U_FAILURE(status)) { - fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status); + fCalendar = Calendar::createInstance( + adoptZone ? adoptZone : TimeZone::forLocaleOrDefault(locale), locale, status); } return fCalendar; } diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 284334ebf7e..78f538ccecd 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -579,6 +579,24 @@ TimeZone::createDefault() // ------------------------------------- +TimeZone* U_EXPORT2 +TimeZone::forLocaleOrDefault(const Locale& locale) +{ + char buffer[ULOC_KEYWORDS_CAPACITY] = ""; + UErrorCode localStatus = U_ZERO_ERROR; + int32_t count = locale.getKeywordValue("timezone", buffer, sizeof(buffer), localStatus); + if (U_FAILURE(localStatus) || localStatus == U_STRING_NOT_TERMINATED_WARNING) { + // the "timezone" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default. + count = 0; + } + if (count > 0) { + return TimeZone::createTimeZone(UnicodeString(buffer, count, US_INV)); + } + return TimeZone::createDefault(); +} + +// ------------------------------------- + void U_EXPORT2 TimeZone::adoptDefault(TimeZone* zone) { diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h index 433e3b5c466..e53aa7c850b 100644 --- a/icu4c/source/i18n/unicode/timezone.h +++ b/icu4c/source/i18n/unicode/timezone.h @@ -317,6 +317,17 @@ public: */ static TimeZone* U_EXPORT2 createDefault(void); + /** + * If the locale contains the timezone keyword, creates a copy of that TimeZone. + * Otherwise, create the default timezone. + * + * @param locale a locale which may contains 'timezone' keyword/value. + * @return A TimeZone. Clients are responsible for deleting the time zone + * object returned. + * @internal + */ + static TimeZone* U_EXPORT2 forLocaleOrDefault(const Locale& locale); + /** * Sets the default time zone (i.e., what's returned by createDefault()) to be the * specified time zone. If NULL is specified for the time zone, the default time diff --git a/icu4c/source/test/intltest/caltest.cpp b/icu4c/source/test/intltest/caltest.cpp index 02a064489ed..25f5f72ce2b 100644 --- a/icu4c/source/test/intltest/caltest.cpp +++ b/icu4c/source/test/intltest/caltest.cpp @@ -346,6 +346,13 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, TestChineseCalendarMapping(); } break; + case 37: + name = "TestTimeZoneInLocale"; + if(exec) { + logln("TestTimeZoneInLocale---"); logln(""); + TestTimeZoneInLocale(); + } + break; default: name = ""; break; } } @@ -2807,6 +2814,51 @@ void CalendarTest::TestCloneLocale(void) { TEST_CHECK_STATUS; } +void CalendarTest::TestTimeZoneInLocale(void) { + const char *tests[][3] = { + { "en-u-tz-usden", "America/Denver", "gregorian" }, + { "es-u-tz-usden", "America/Denver", "gregorian" }, + { "ms-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "zh-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "fr-u-ca-buddhist-tz-phmnl", "Asia/Manila", "buddhist" }, + { "th-u-ca-chinese-tz-gblon", "Europe/London", "chinese" }, + { "de-u-ca-coptic-tz-ciabj", "Africa/Abidjan", "coptic" }, + { "ja-u-ca-dangi-tz-hkhkg", "Asia/Hong_Kong", "dangi" }, + { "da-u-ca-ethioaa-tz-ruunera", "Asia/Ust-Nera", "ethiopic-amete-alem" }, + { "ko-u-ca-ethiopic-tz-cvrai", "Atlantic/Cape_Verde", "ethiopic" }, + { "fil-u-ca-gregory-tz-aubne", "Australia/Brisbane", "gregorian" }, + { "fa-u-ca-hebrew-tz-brrbr", "America/Rio_Branco", "hebrew" }, + { "gr-u-ca-indian-tz-lccas", "America/St_Lucia", "indian" }, + { "or-u-ca-islamic-tz-cayyn", "America/Swift_Current", "islamic" }, + { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" }, + { "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" }, + { "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" }, + { "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" }, + { "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" }, + { "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" }, + { "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" }, + { "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" }, + }; + + for (int32_t i = 0; i < UPRV_LENGTHOF(tests); ++i) { + UErrorCode status = U_ZERO_ERROR; + const char **testLine = tests[i]; + Locale locale(testLine[0]); + UnicodeString expected(testLine[1], -1, US_INV); + UnicodeString actual; + + LocalPointer calendar( + Calendar::createInstance(locale, status)); + if (failure(status, "Calendar::createInstance", TRUE)) continue; + + assertEquals("TimeZone from Calendar::createInstance", + expected, calendar->getTimeZone().getID(actual)); + + assertEquals("Calendar Type from Calendar::createInstance", + testLine[2], calendar->getType()); + } +} + void CalendarTest::setAndTestCalendar(Calendar* cal, int32_t initMonth, int32_t initDay, int32_t initYear, UErrorCode& status) { cal->clear(); cal->setLenient(FALSE); diff --git a/icu4c/source/test/intltest/caltest.h b/icu4c/source/test/intltest/caltest.h index f85abf9d886..a3d9e1330c7 100644 --- a/icu4c/source/test/intltest/caltest.h +++ b/icu4c/source/test/intltest/caltest.h @@ -242,6 +242,8 @@ public: // package void TestCloneLocale(void); + void TestTimeZoneInLocale(void); + void TestHebrewMonthValidation(void); /* diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp index 945728d5e4f..43b8a2f982d 100644 --- a/icu4c/source/test/intltest/dtfmttst.cpp +++ b/icu4c/source/test/intltest/dtfmttst.cpp @@ -88,6 +88,7 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam TESTCASE_AUTO(TestHebrewClone); TESTCASE_AUTO(TestDateFormatSymbolsClone); TESTCASE_AUTO(TestTimeZoneDisplayName); + TESTCASE_AUTO(TestTimeZoneInLocale); TESTCASE_AUTO(TestRoundtripWithCalendar); TESTCASE_AUTO(Test6338); TESTCASE_AUTO(Test6726); @@ -3442,6 +3443,70 @@ void DateFormatTest::TestTimeZoneDisplayName() } } +void DateFormatTest::TestTimeZoneInLocale() +{ + const char *tests[][3] = { + { "en-u-tz-usden", "America/Denver", "gregorian" }, + { "es-u-tz-usden", "America/Denver", "gregorian" }, + { "ms-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "zh-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "fr-u-ca-buddhist-tz-phmnl", "Asia/Manila", "buddhist" }, + { "th-u-ca-chinese-tz-gblon", "Europe/London", "chinese" }, + { "de-u-ca-coptic-tz-ciabj", "Africa/Abidjan", "coptic" }, + { "ja-u-ca-dangi-tz-hkhkg", "Asia/Hong_Kong", "dangi" }, + { "da-u-ca-ethioaa-tz-ruunera", "Asia/Ust-Nera", "ethiopic-amete-alem" }, + { "ko-u-ca-ethiopic-tz-cvrai", "Atlantic/Cape_Verde", "ethiopic" }, + { "fil-u-ca-gregory-tz-aubne", "Australia/Brisbane", "gregorian" }, + { "fa-u-ca-hebrew-tz-brrbr", "America/Rio_Branco", "hebrew" }, + { "gr-u-ca-indian-tz-lccas", "America/St_Lucia", "indian" }, + { "or-u-ca-islamic-tz-cayyn", "America/Swift_Current", "islamic" }, + { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" }, + { "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" }, + { "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" }, + { "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" }, + { "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" }, + { "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" }, + { "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" }, + { "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" }, + }; + + for (int32_t i = 0; i < UPRV_LENGTHOF(tests); ++i) { + UErrorCode status = U_ZERO_ERROR; + const char **testLine = tests[i]; + Locale locale(testLine[0]); + UnicodeString expectedTimezone(testLine[1], -1, US_INV); + UnicodeString actual; + + SimpleDateFormat smptfmt("Z", locale, status); + assertEquals("TimeZone from SimpleDateFormat constructor", + expectedTimezone, smptfmt.getTimeZone().getID(actual)); + assertEquals("Calendar from SimpleDateFormat constructor", + testLine[2], smptfmt.getCalendar()->getType()); + + LocalPointer datefmt( + DateFormat::createDateInstance(DateFormat::kDefault, locale)); + assertEquals("TimeZone from DateFormat::createDateInstance", + expectedTimezone, datefmt->getTimeZone().getID(actual)); + assertEquals("Calendar from DateFormat::createDateInstance", + testLine[2], datefmt->getCalendar()->getType()); + + LocalPointer timefmt( + DateFormat::createTimeInstance(DateFormat::kDefault, locale)); + assertEquals("TimeZone from TimeFormat::createTimeInstance", + expectedTimezone, timefmt->getTimeZone().getID(actual)); + assertEquals("Calendar from DateFormat::createTimeInstance", + testLine[2], timefmt->getCalendar()->getType()); + + LocalPointer datetimefmt( + DateFormat::createDateTimeInstance( + DateFormat::kDefault, DateFormat::kDefault, locale)); + assertEquals("TimeZone from DateTimeFormat::createDateTimeInstance", + expectedTimezone, datetimefmt->getTimeZone().getID(actual)); + assertEquals("Calendar from DateFormat::createDateTimeInstance", + testLine[2], datetimefmt->getCalendar()->getType()); + } +} + void DateFormatTest::TestRoundtripWithCalendar(void) { UErrorCode status = U_ZERO_ERROR; diff --git a/icu4c/source/test/intltest/dtfmttst.h b/icu4c/source/test/intltest/dtfmttst.h index ac369195945..eef0d224931 100644 --- a/icu4c/source/test/intltest/dtfmttst.h +++ b/icu4c/source/test/intltest/dtfmttst.h @@ -226,6 +226,8 @@ public: void TestTimeZoneDisplayName(void); + void TestTimeZoneInLocale(void); + void TestRoundtripWithCalendar(void); public: diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/CECalendar.java b/icu4j/main/classes/core/src/com/ibm/icu/util/CECalendar.java index d3271396803..f3b78a0fde3 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/CECalendar.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/CECalendar.java @@ -76,7 +76,7 @@ abstract class CECalendar extends Calendar { * @param aLocale The locale for the new calendar. */ protected CECalendar(Locale aLocale) { - this(TimeZone.getDefault(), aLocale); + this(TimeZone.forLocaleOrDefault(aLocale), aLocale); } /** @@ -86,7 +86,7 @@ abstract class CECalendar extends Calendar { * @param locale The locale for the new calendar. */ protected CECalendar(ULocale locale) { - this(TimeZone.getDefault(), locale); + this(TimeZone.forULocaleOrDefault(locale), locale); } /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java b/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java index 0a4469b8a86..4328290d2e8 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java @@ -1764,7 +1764,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableTimeZone. + * Otherwise, create the default TimeZone. + * @param locale a locale which may contains 'timezone' keyword/value. + * @return A TimeZone. Clients are responsible for deleting the + * TimeZone object returned. + * @internal + */ + public static TimeZone forULocaleOrDefault(ULocale locale) { + String tz = locale.getKeywordValue("timezone"); + return (tz == null) ? getDefault() : getTimeZone(tz); + } + + /** + * If the locale contains the timezone keyword, creates a copy of that + * TimeZone. + * Otherwise, create the default TimeZone. + * @param locale a locale which may contains 'timezone' keyword/value. + * @return A TimeZone. Clients are responsible for deleting the + * TimeZone object returned. + * @internal + */ + public static TimeZone forLocaleOrDefault(Locale locale) { + return forULocaleOrDefault(ULocale.forLocale(locale)); + } + /** * Gets the default TimeZone for this host. * The source of the default TimeZone diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CalendarRegressionTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CalendarRegressionTest.java index 41503497ecf..7dbbfb32833 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CalendarRegressionTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CalendarRegressionTest.java @@ -2555,5 +2555,69 @@ public class CalendarRegressionTest extends com.ibm.icu.dev.test.TestFmwk { errln("Fail: Expected year=" + year + ", actual=" + resultYear); } } + + @Test + public void TestTimeZoneInLocale20465() { + String TESTS[][] = { + { "en-u-tz-usden", "America/Denver", "gregorian" }, + { "es-u-tz-usden", "America/Denver", "gregorian" }, + { "ms-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "zh-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "fr-u-ca-buddhist-tz-phmnl", "Asia/Manila", "buddhist" }, + { "th-u-ca-chinese-tz-gblon", "Europe/London", "chinese" }, + { "de-u-ca-coptic-tz-ciabj", "Africa/Abidjan", "coptic" }, + { "ja-u-ca-dangi-tz-hkhkg", "Asia/Hong_Kong", "dangi" }, + { "da-u-ca-ethioaa-tz-ruunera", "Asia/Ust-Nera", "ethiopic-amete-alem" }, + { "ko-u-ca-ethiopic-tz-cvrai", "Atlantic/Cape_Verde", "ethiopic" }, + { "fil-u-ca-gregory-tz-aubne", "Australia/Brisbane", "gregorian" }, + { "fa-u-ca-hebrew-tz-brrbr", "America/Rio_Branco", "hebrew" }, + { "gr-u-ca-indian-tz-lccas", "America/St_Lucia", "indian" }, + { "or-u-ca-islamic-tz-cayyn", "America/Swift_Current", "islamic" }, + { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" }, + { "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" }, + { "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" }, + { "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" }, + { "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" }, + { "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" }, + { "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" }, + { "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" }, + }; + TimeZone other = TimeZone.getTimeZone("America/Louisville"); + for (int i = 0; i < TESTS.length; ++i) { + ULocale ulocale = new ULocale(TESTS[i][0]); + Locale locale = new Locale(TESTS[i][0]); + Calendar cal = Calendar.getInstance(locale); + assertEquals( + "TimeZone from Calendar.getInstance(Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], cal.getTimeZone().getID()); + assertEquals( + "Calendar from Calendar.getInstance(Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], cal.getType()); + + cal = Calendar.getInstance(ulocale); + assertEquals( + "TimeZone from Calendar.getInstance(ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], cal.getTimeZone().getID()); + assertEquals( + "Calendar from Calendar.getInstance(ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], cal.getType()); + + cal = Calendar.getInstance(other, locale); + assertEquals( + "TimeZone from Calendar.getInstance(TimeZone zone=\"uslui\", Locale loc=\"" + TESTS[i][0] + "\")", + other.getID(), cal.getTimeZone().getID()); + assertEquals( + "Calendar from Calendar.getInstance(TimeZone zone=\"uslui\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], cal.getType()); + + cal = Calendar.getInstance(other, ulocale); + assertEquals( + "TimeZone from Calendar.getInstance(TimeZone zone=\"uslui\", ULocale loc=\"" + TESTS[i][0] + "\")", + other.getID(), cal.getTimeZone().getID()); + assertEquals( + "Calendar from Calendar.getInstance(TimeZone zone=\"uslui\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], cal.getType()); + } + } } //eof diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java index 15cca60ae8b..d3f921503ae 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java @@ -779,6 +779,93 @@ public class DateFormatTest extends TestFmwk { } } + @Test + public void TestTimeZoneInLocale() { + String TESTS[][] = { + { "en-u-tz-usden", "America/Denver", "gregorian" }, + { "es-u-tz-usden", "America/Denver", "gregorian" }, + { "ms-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "zh-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" }, + { "fr-u-ca-buddhist-tz-phmnl", "Asia/Manila", "buddhist" }, + { "th-u-ca-chinese-tz-gblon", "Europe/London", "chinese" }, + { "de-u-ca-coptic-tz-ciabj", "Africa/Abidjan", "coptic" }, + { "ja-u-ca-dangi-tz-hkhkg", "Asia/Hong_Kong", "dangi" }, + { "da-u-ca-ethioaa-tz-ruunera", "Asia/Ust-Nera", "ethiopic-amete-alem" }, + { "ko-u-ca-ethiopic-tz-cvrai", "Atlantic/Cape_Verde", "ethiopic" }, + { "fil-u-ca-gregory-tz-aubne", "Australia/Brisbane", "gregorian" }, + { "fa-u-ca-hebrew-tz-brrbr", "America/Rio_Branco", "hebrew" }, + { "gr-u-ca-indian-tz-lccas", "America/St_Lucia", "indian" }, + { "or-u-ca-islamic-tz-cayyn", "America/Swift_Current", "islamic" }, + { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" }, + { "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" }, + { "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" }, + { "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" }, + { "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" }, + { "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" }, + { "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" }, + { "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" }, + }; + for (int i = 0; i < TESTS.length; ++i) { + ULocale ulocale = new ULocale(TESTS[i][0]); + Locale locale = new Locale(TESTS[i][0]); + SimpleDateFormat smptfmt = new SimpleDateFormat("Z", locale); + assertEquals( + "TimeZone from SimpleDateFormat(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], smptfmt.getTimeZone().getID()); + assertEquals( + "Calendar from SimpleDateFormat(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], smptfmt.getCalendar().getType()); + + smptfmt = new SimpleDateFormat("Z", "", ulocale); + assertEquals( + "TimeZone from SimpleDateFormat(\"Z\", \"\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], smptfmt.getTimeZone().getID()); + assertEquals( + "Calendar from SimpleDateFormat(\"Z\", \"\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], smptfmt.getCalendar().getType()); + + smptfmt = new SimpleDateFormat("Z", ulocale); + assertEquals( + "TimeZone from SimpleDateFormat(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], smptfmt.getTimeZone().getID()); + assertEquals( + "Calendar from SimpleDateFormat(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], smptfmt.getCalendar().getType()); + + DateFormat dfmt = DateFormat.getInstanceForSkeleton("Z", locale); + assertEquals( + "TimeZone from DateFormat.getInstanceForSkeleton(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], dfmt.getTimeZone().getID()); + assertEquals( + "Calendar from DateFormat.getInstanceForSkeleton(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], dfmt.getCalendar().getType()); + + dfmt = DateFormat.getInstanceForSkeleton("Z", ulocale); + assertEquals( + "TimeZone from DateFormat.getInstanceForSkeleton(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], dfmt.getTimeZone().getID()); + assertEquals( + "Calendar from DateFormat.getInstanceForSkeleton(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], dfmt.getCalendar().getType()); + + dfmt = DateFormat.getPatternInstance("Z", locale); + assertEquals( + "TimeZone from DateFormat.getPatternInstance(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], dfmt.getTimeZone().getID()); + assertEquals( + "Calendar from DateFormat.getPatternInstance(\"Z\", Locale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], dfmt.getCalendar().getType()); + + dfmt = DateFormat.getPatternInstance("Z", ulocale); + assertEquals( + "TimeZone from DateFormat.getPatternInstance(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][1], dfmt.getTimeZone().getID()); + assertEquals( + "Calendar from DateFormat.getPatternInstance(\"Z\", ULocale loc=\"" + TESTS[i][0] + "\")", + TESTS[i][2], dfmt.getCalendar().getType()); + } + } + private static final String GMT_BG = "\u0413\u0440\u0438\u043D\u0443\u0438\u0447"; private static final String GMT_ZH = "GMT"; //private static final String GMT_ZH = "\u683C\u6797\u5C3C\u6CBB\u6807\u51C6\u65F6\u95F4";