Bug 1838173: Allow to set the Gregorian change date for ISO-8601 calendars. r=platform-i18n-reviewers,dminor

Add a patch to work around <https://unicode-org.atlassian.net/jira/software/c/projects/ICU/issues/ICU-22412>.

Differential Revision: https://phabricator.services.mozilla.com/D180796
This commit is contained in:
André Bargull 2023-06-14 05:38:46 +00:00
parent 9ac4c7d32f
commit 6b464f9394
4 changed files with 107 additions and 2 deletions

View File

@ -564,4 +564,58 @@ TEST(IntlDateTimeFormat, TryFormatToParts)
ASSERT_EQ(parts.length(), 9u);
}
TEST(IntlDateTimeFormat, SetStartTimeIfGregorian)
{
DateTimeFormat::StyleBag style{};
style.date = Some(DateTimeFormat::Style::Long);
auto timeZone = Some(MakeStringSpan(u"UTC"));
// Beginning of ECMAScript time.
constexpr double StartOfTime = -8.64e15;
// Gregorian change date defaults to October 15, 1582 in ICU. Test with a date
// before the default change date, in this case January 1, 1582.
constexpr double FirstJanuary1582 = -12244089600000.0;
// One year expressed in milliseconds.
constexpr double oneYear = (365 * 24 * 60 * 60) * 1000.0;
// Test with and without explicit calendar. The start time of the calendar can
// only be adjusted for the Gregorian and the ISO-8601 calendar.
for (const char* locale : {
"en-US",
"en-US-u-ca-gregory",
"en-US-u-ca-iso8601",
}) {
auto gen = DateTimePatternGenerator::TryCreate(locale).unwrap();
auto dtFormat = DateTimeFormat::TryCreateFromStyle(
MakeStringSpan(locale), style, gen.get(), timeZone)
.unwrap();
TestBuffer<char> buffer;
// Before the default Gregorian change date, so interpreted in the Julian
// calendar, which is December 22, 1581.
dtFormat->TryFormat(FirstJanuary1582, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("December 22, 1581"));
// After default Gregorian change date, so January 1, 1583.
dtFormat->TryFormat(FirstJanuary1582 + oneYear, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("January 1, 1583"));
// Adjust the start time to use a proleptic Gregorian calendar.
dtFormat->SetStartTimeIfGregorian(StartOfTime);
// Now interpreted in proleptic Gregorian calendar at January 1, 1582.
dtFormat->TryFormat(FirstJanuary1582, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("January 1, 1582"));
// Still January 1, 1583.
dtFormat->TryFormat(FirstJanuary1582 + oneYear, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("January 1, 1583"));
}
}
} // namespace mozilla::intl

View File

@ -0,0 +1,47 @@
# Allow to set the Gregorian change date for ISO8601 calendars.
#
# ICU bug: https://unicode-org.atlassian.net/browse/ICU-22412
diff --git a/intl/icu/source/i18n/ucal.cpp b/intl/icu/source/i18n/ucal.cpp
--- a/intl/icu/source/i18n/ucal.cpp
+++ b/intl/icu/source/i18n/ucal.cpp
@@ -22,10 +22,11 @@
#include "unicode/ustring.h"
#include "unicode/strenum.h"
#include "unicode/localpointer.h"
#include "cmemory.h"
#include "cstring.h"
+#include "iso8601cal.h"
#include "ustrenum.h"
#include "uenumimp.h"
#include "ulist.h"
#include "ulocimp.h"
@@ -305,11 +306,12 @@ ucal_setGregorianChange(UCalendar *cal,
// We normally don't check "this" pointers for nullptr, but this here avoids
// compiler-generated exception-throwing code in case cal == nullptr.
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
+ if(typeid(*cpp_cal) != typeid(GregorianCalendar) &&
+ typeid(*cpp_cal) != typeid(ISO8601Calendar)) {
*pErrorCode = U_UNSUPPORTED_ERROR;
return;
}
gregocal->setGregorianChange(date, *pErrorCode);
}
@@ -327,11 +329,12 @@ ucal_getGregorianChange(const UCalendar
// We normally don't check "this" pointers for nullptr, but this here avoids
// compiler-generated exception-throwing code in case cal == nullptr.
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return (UDate)0;
}
- if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
+ if(typeid(*cpp_cal) != typeid(GregorianCalendar) &&
+ typeid(*cpp_cal) != typeid(ISO8601Calendar)) {
*pErrorCode = U_UNSUPPORTED_ERROR;
return (UDate)0;
}
return gregocal->getGregorianChange();
}

View File

@ -24,6 +24,7 @@
#include "unicode/localpointer.h"
#include "cmemory.h"
#include "cstring.h"
#include "iso8601cal.h"
#include "ustrenum.h"
#include "uenumimp.h"
#include "ulist.h"
@ -307,7 +308,8 @@ ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
if(typeid(*cpp_cal) != typeid(GregorianCalendar) &&
typeid(*cpp_cal) != typeid(ISO8601Calendar)) {
*pErrorCode = U_UNSUPPORTED_ERROR;
return;
}
@ -329,7 +331,8 @@ ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return (UDate)0;
}
if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
if(typeid(*cpp_cal) != typeid(GregorianCalendar) &&
typeid(*cpp_cal) != typeid(ISO8601Calendar)) {
*pErrorCode = U_UNSUPPORTED_ERROR;
return (UDate)0;
}

View File

@ -58,6 +58,7 @@ for patch in \
bug-1636984-append-item-dayperiod-fractional-seconds.diff \
bug-1706949-wasi-workaround.diff \
bug-1790071-ICU-22132-standardize-vtzone-output.diff \
bug-1838173-ICU-22412-start-time-iso8601.diff \
; do
echo "Applying local patch $patch"
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch