diff --git a/icu4c/source/i18n/dtptngen.cpp b/icu4c/source/i18n/dtptngen.cpp index d7b60d34c451..63b9b707b151 100644 --- a/icu4c/source/i18n/dtptngen.cpp +++ b/icu4c/source/i18n/dtptngen.cpp @@ -756,6 +756,7 @@ void DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& destination, UErrorCode& err) { destination.clear().append(DT_DateTimeGregorianTag, -1, err); // initial default if ( U_SUCCESS(err) ) { + UErrorCode localStatus = U_ZERO_ERROR; char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; // obtain a locale that always has the calendar key value that should be used ures_getFunctionalEquivalent( @@ -767,8 +768,7 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& locale.getName(), nullptr, FALSE, - &err); - if (U_FAILURE(err)) { return; } + &localStatus); localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination // now get the calendar key value from that locale char calendarType[ULOC_KEYWORDS_CAPACITY]; @@ -777,13 +777,17 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, - &err); - if (U_FAILURE(err)) { return; } + &localStatus); + // If the input locale was invalid, don't fail with missing resource error, instead + // continue with default of Gregorian. + if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) { + err = localStatus; + return; + } if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { destination.clear().append(calendarType, -1, err); if (U_FAILURE(err)) { return; } } - err = U_ZERO_ERROR; } } diff --git a/icu4c/source/test/intltest/dtptngts.cpp b/icu4c/source/test/intltest/dtptngts.cpp index f21856821f8c..e4bd9777e968 100644 --- a/icu4c/source/test/intltest/dtptngts.cpp +++ b/icu4c/source/test/intltest/dtptngts.cpp @@ -20,9 +20,9 @@ #include "unicode/dtptngen.h" #include "unicode/ustring.h" #include "cmemory.h" +#include "cstring.h" #include "loctest.h" - // This is an API test, not a unit test. It doesn't test very many cases, and doesn't // try to test the full functionality. It just calls each function in the class and // verifies that it works on a basic level. @@ -38,6 +38,7 @@ void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool e TESTCASE(4, testC); TESTCASE(5, testSkeletonsWithDayPeriods); TESTCASE(6, testGetFieldDisplayNames); + TESTCASE(7, testFallbackWithDefaultRootLocale); default: name = ""; break; } } @@ -1259,4 +1260,31 @@ void IntlTestDateTimePatternGeneratorAPI::testGetFieldDisplayNames() { } } +void IntlTestDateTimePatternGeneratorAPI::testFallbackWithDefaultRootLocale() { + UErrorCode status = U_ZERO_ERROR; + char original[ULOC_FULLNAME_CAPACITY]; + + uprv_strcpy(original, uloc_getDefault()); + uloc_setDefault("root", &status); + if (U_FAILURE(status)) { + errln("ERROR: Failed to change the default locale to root! Default is: %s\n", uloc_getDefault()); + } + + DateTimePatternGenerator* dtpg = icu::DateTimePatternGenerator::createInstance("abcdedf", status); + + if (U_FAILURE(status)) { + errln("ERROR: expected createInstance with invalid locale to succeed. Status: %s", u_errorName(status)); + } + if (status != U_USING_DEFAULT_WARNING) { + errln("ERROR: expected createInstance to return U_USING_DEFAULT_WARNING for invalid locale and default root locale. Status: %s", u_errorName(status)); + } + + delete dtpg; + + uloc_setDefault(original, &status); + if (U_FAILURE(status)) { + errln("ERROR: Failed to change the default locale back to %s\n", original); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/dtptngts.h b/icu4c/source/test/intltest/dtptngts.h index adef0dca5cf6..6e4f9c5bf930 100644 --- a/icu4c/source/test/intltest/dtptngts.h +++ b/icu4c/source/test/intltest/dtptngts.h @@ -32,6 +32,7 @@ class IntlTestDateTimePatternGeneratorAPI : public IntlTest { void testC(); void testSkeletonsWithDayPeriods(); void testGetFieldDisplayNames(); + void testFallbackWithDefaultRootLocale(); }; #endif /* #if !UCONFIG_NO_FORMATTING */