Eliminate GregorianCalendar usage

This commit is contained in:
Tim Chevalier 2024-06-18 12:36:45 -07:00
parent c42fe17a3a
commit 2c97c1273f
4 changed files with 52 additions and 64 deletions

View file

@ -218,6 +218,22 @@ namespace message2 {
return number::NumberFormatter::withLocale(locale).formatDecimal(toFormat, errorCode);
}
TimeZone* DateInfo::createTimeZone(UErrorCode& errorCode) const {
NULL_ON_ERROR(errorCode);
TimeZone* tz;
if (zoneName.length() == 0) {
tz = TimeZone::createDefault();
} else {
tz = TimeZone::createTimeZone(zoneName);
}
if (tz == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
}
return tz;
}
DateFormat* defaultDateTimeInstance(const Locale& locale, UErrorCode& errorCode) {
NULL_ON_ERROR(errorCode);
LocalPointer<DateFormat> df(DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::SHORT, locale));
@ -228,34 +244,6 @@ namespace message2 {
return df.orphan();
}
GregorianCalendar* DateInfo::createGregorianCalendar(UErrorCode& errorCode) const {
NULL_ON_ERROR(errorCode);
LocalPointer<GregorianCalendar> cal(new GregorianCalendar(errorCode));
if (!cal.isValid()) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
}
// Copy info from this
// Non-Gregorian calendars not implemented yet
U_ASSERT(calendarName.length() == 0);
cal->setTime(date, errorCode);
// If time zone is present...
if (zoneName.length() > 0) {
if (zoneName == UnicodeString("UTC")) {
cal->setTimeZone(*TimeZone::getGMT());
} else {
LocalPointer<TimeZone> tz(TimeZone::createTimeZone(zoneName));
if (!tz.isValid()) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
}
cal->setTimeZone(*tz);
}
}
return cal.orphan();
}
void formatDateWithDefaults(const Locale& locale,
const DateInfo& dateInfo,
UnicodeString& result,
@ -269,9 +257,9 @@ namespace message2 {
// Non-Gregorian calendars not supported yet
U_ASSERT(dateInfo.calendarName.length() == 0);
LocalPointer<GregorianCalendar> cal(dateInfo.createGregorianCalendar(errorCode));
df->adoptTimeZone(dateInfo.createTimeZone(errorCode));
CHECK_ERROR(errorCode);
df->format(*cal, result, nullptr, errorCode);
df->format(dateInfo.date, result, nullptr, errorCode);
}
// Called when output is required and the contents are an unevaluated `Formattable`;

View file

@ -1089,8 +1089,10 @@ static bool hasTzOffset(const UnicodeString& sourceStr) {
// Note: `calendar` option to :datetime not implemented yet;
// Gregorian calendar is assumed
static GregorianCalendar* createCalendarFromDateString(const UnicodeString& sourceStr, UErrorCode& errorCode) {
NULL_ON_ERROR(errorCode);
static DateInfo createDateInfoFromString(const UnicodeString& sourceStr, UErrorCode& errorCode) {
if (U_FAILURE(errorCode)) {
return {};
}
UDate absoluteDate;
@ -1116,7 +1118,9 @@ static GregorianCalendar* createCalendarFromDateString(const UnicodeString& sour
}
tryPatterns(noTimeZone, errorCode);
// Failure -- can't parse this string
NULL_ON_ERROR(errorCode);
if (U_FAILURE(errorCode)) {
return {};
}
// Success -- now handle the time zone part
if (isGMT) {
noTimeZone += UnicodeString("GMT");
@ -1127,19 +1131,31 @@ static GregorianCalendar* createCalendarFromDateString(const UnicodeString& sour
offsetPart = sourceStr.tempSubString(indexOfSign, sourceStr.length());
}
}
LocalPointer<GregorianCalendar> cal(new GregorianCalendar(errorCode));
NULL_ON_ERROR(errorCode);
cal->setTime(absoluteDate, errorCode);
const TimeZone* tz;
if (hasTimeZone) {
if (isGMT) {
cal->setTimeZone(*TimeZone::getGMT());
tz = TimeZone::getGMT();
} else {
LocalPointer<SimpleTimeZone> tz(createTimeZonePart(offsetPart, errorCode));
NULL_ON_ERROR(errorCode);
cal->adoptTimeZone(tz.orphan());
tz = createTimeZonePart(offsetPart, errorCode);
}
} else {
tz = TimeZone::createDefault();
}
return cal.orphan();
if (tz == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
}
if (U_FAILURE(errorCode)) {
return {};
}
UnicodeString tzID;
// This doesn't work for offsets -- TODO
// tz.getIanaID(timeZoneId, timeZoneName, errorCode);
tz->getID(tzID);
// Empty string for Gregorian calendar (default);
// `:datetime` `calendar` option not implemented yet,
// so other calendars aren't implemented
return { absoluteDate, tzID, {} };
}
FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&& toFormat,
@ -1331,29 +1347,17 @@ FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&&
const UnicodeString& sourceStr = source.getString(errorCode);
U_ASSERT(U_SUCCESS(errorCode));
LocalPointer<GregorianCalendar> cal(createCalendarFromDateString(sourceStr, errorCode));
DateInfo dateInfo = createDateInfoFromString(sourceStr, errorCode);
if (U_FAILURE(errorCode)) {
errorCode = U_MF_OPERAND_MISMATCH_ERROR;
return {};
}
df->adoptTimeZone(dateInfo.createTimeZone(errorCode));
// Use the parsed date as the source value
// in the returned FormattedPlaceholder; this is necessary
// so the date can be re-formatted
df->format(*cal, result, 0, errorCode);
// Construct DateInfo from Date
UDate absoluteDate = cal->getTime(errorCode);
const TimeZone& tz = cal->getTimeZone();
UnicodeString timeZoneId;
tz.getID(timeZoneId);
UnicodeString timeZoneName;
// This doesn't work for offsets -- TODO
// tz.getIanaID(timeZoneId, timeZoneName, errorCode);
// Empty string for Gregorian calendar (default);
// `:datetime` `calendar` option not implemented yet,
// so other calendars aren't implemented
DateInfo dateInfo = {absoluteDate, timeZoneId, {}}; // Should be timeZoneName, but getIanaID() doesn't work for strings like GMT+03:30
df->format(dateInfo.date, result, 0, errorCode);
toFormat = FormattedPlaceholder(message2::Formattable(std::move(dateInfo)),
toFormat.getFallback());
break;
@ -1362,11 +1366,8 @@ FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&&
const DateInfo* dateInfo = source.getDate(errorCode);
U_ASSERT(U_SUCCESS(errorCode));
LocalPointer<GregorianCalendar> cal(dateInfo->createGregorianCalendar(errorCode));
if (U_FAILURE(errorCode)) {
return {};
}
df->format(*cal, result, 0, errorCode);
df->adoptTimeZone(dateInfo->createTimeZone(errorCode));
df->format(dateInfo->date, result, 0, errorCode);
if (U_FAILURE(errorCode)) {
if (errorCode == U_ILLEGAL_ARGUMENT_ERROR) {
errorCode = U_MF_OPERAND_MISMATCH_ERROR;

View file

@ -15,7 +15,6 @@
#if !UCONFIG_NO_MF2
#include "unicode/chariter.h"
#include "unicode/gregocal.h"
#include "unicode/numberformatter.h"
#include "unicode/messageformat2_data_model_names.h"
#include "unicode/smpdtfmt.h"
@ -115,7 +114,7 @@ namespace message2 {
// Empty if not specified; proleptic Gregorian (8601) calendar is default
UnicodeString calendarName;
GregorianCalendar* createGregorianCalendar(UErrorCode&) const;
TimeZone* createTimeZone(UErrorCode&) const;
};
/**

View file

@ -8,7 +8,7 @@
#if !UCONFIG_NO_MF2
#include "unicode/calendar.h"
#include "unicode/gregocal.h"
#include "messageformat2test.h"
using namespace icu::message2;