mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 17:01:16 +00:00
Cache DateFormat objects in the DateTimeFactory object and lazily initialize them
This commit is contained in:
parent
6c20aea7c5
commit
d45f9e9b8e
3 changed files with 61 additions and 16 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "messageformat2_function_registry_internal.h"
|
||||
#include "messageformat2_macros.h"
|
||||
#include "hash.h"
|
||||
#include "mutex.h"
|
||||
#include "number_types.h"
|
||||
#include "uvector.h" // U_ASSERT
|
||||
|
||||
|
@ -1001,49 +1002,64 @@ static DateFormat::EStyle stringToStyle(UnicodeString option, UErrorCode& errorC
|
|||
Formatter* StandardFunctions::DateTimeFactory::createFormatter(const Locale& locale, UErrorCode& errorCode) {
|
||||
NULL_ON_ERROR(errorCode);
|
||||
|
||||
Formatter* result = new StandardFunctions::DateTime(locale, type);
|
||||
Formatter* result = new StandardFunctions::DateTime(locale, *this, type);
|
||||
if (result == nullptr) {
|
||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static UDate tryPattern(const char* pat, const UnicodeString& sourceStr, UErrorCode& errorCode) {
|
||||
LocalPointer<DateFormat> dateParser(new SimpleDateFormat(UnicodeString(pat), errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return 0;
|
||||
static UMutex gDateTimeFactoryMutex;
|
||||
|
||||
// Lazily initialize DateFormat objects used for parsing date literals
|
||||
void StandardFunctions::DateTimeFactory::initDateParsers(UErrorCode& errorCode) {
|
||||
CHECK_ERROR(errorCode);
|
||||
|
||||
Mutex lock(&gDateTimeFactoryMutex);
|
||||
|
||||
if (dateParser.isValid()) {
|
||||
// Already initialized
|
||||
return;
|
||||
}
|
||||
return dateParser->parse(sourceStr, errorCode);
|
||||
|
||||
// Handles ISO 8601 date
|
||||
dateParser.adoptInstead(new SimpleDateFormat(UnicodeString("YYYY-MM-dd"), errorCode));
|
||||
// Handles ISO 8601 datetime without time zone
|
||||
dateTimeParser.adoptInstead(new SimpleDateFormat(UnicodeString("YYYY-MM-dd'T'HH:mm:ss"), errorCode));
|
||||
// Handles ISO 8601 datetime with 'Z' to denote UTC
|
||||
dateTimeUTCParser.adoptInstead(new SimpleDateFormat(UnicodeString("YYYY-MM-dd'T'HH:mm:ssZ"), errorCode));
|
||||
// Handles ISO 8601 datetime with timezone offset; 'zzzz' denotes timezone offset
|
||||
dateTimeZoneParser.adoptInstead(new SimpleDateFormat(UnicodeString("YYYY-MM-dd'T'HH:mm:sszzzz"), errorCode));
|
||||
}
|
||||
|
||||
// From https://github.com/unicode-org/message-format-wg/blob/main/spec/registry.md#date-and-time-operands :
|
||||
// "A date/time literal value is a non-empty string consisting of an ISO 8601 date, or
|
||||
// an ISO 8601 datetime optionally followed by a timezone offset."
|
||||
static UDate tryPatterns(const UnicodeString& sourceStr, UErrorCode& errorCode) {
|
||||
UDate StandardFunctions::DateTime::tryPatterns(const UnicodeString& sourceStr,
|
||||
UErrorCode& errorCode) const {
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return 0;
|
||||
}
|
||||
// Handle ISO 8601 datetime (tryTimeZonePatterns() handles the case
|
||||
// where a timezone offset follows)
|
||||
if (sourceStr.length() > 10) {
|
||||
return tryPattern("YYYY-MM-dd'T'HH:mm:ss", sourceStr, errorCode);
|
||||
return parent.dateTimeParser->parse(sourceStr, errorCode);
|
||||
}
|
||||
// Handle ISO 8601 date
|
||||
return tryPattern("YYYY-MM-dd", sourceStr, errorCode);
|
||||
return parent.dateParser->parse(sourceStr, errorCode);
|
||||
}
|
||||
|
||||
// See comment on tryPatterns() for spec reference
|
||||
static UDate tryTimeZonePatterns(const UnicodeString& sourceStr, UErrorCode& errorCode) {
|
||||
UDate StandardFunctions::DateTime::tryTimeZonePatterns(const UnicodeString& sourceStr,
|
||||
UErrorCode& errorCode) const {
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t len = sourceStr.length();
|
||||
if (len > 0 && sourceStr[len] == 'Z') {
|
||||
// 'Z' to handle the literal 'Z'
|
||||
return tryPattern("YYYY-MM-dd'T'HH:mm:ssZ", sourceStr, errorCode);
|
||||
return parent.dateTimeUTCParser->parse(sourceStr, errorCode);
|
||||
}
|
||||
// 'zzzz' to handle the case where the timezone offset follows the ISO 8601 datetime
|
||||
return tryPattern("YYYY-MM-dd'T'HH:mm:sszzzz", sourceStr, errorCode);
|
||||
return parent.dateTimeZoneParser->parse(sourceStr, errorCode);
|
||||
}
|
||||
|
||||
static TimeZone* createTimeZone(const DateInfo& dateInfo, UErrorCode& errorCode) {
|
||||
|
@ -1074,7 +1090,8 @@ static bool hasTzOffset(const UnicodeString& sourceStr) {
|
|||
|
||||
// Note: `calendar` option to :datetime not implemented yet;
|
||||
// Gregorian calendar is assumed
|
||||
static DateInfo createDateInfoFromString(const UnicodeString& sourceStr, UErrorCode& errorCode) {
|
||||
DateInfo StandardFunctions::DateTime::createDateInfoFromString(const UnicodeString& sourceStr,
|
||||
UErrorCode& errorCode) const {
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return {};
|
||||
}
|
||||
|
@ -1333,6 +1350,12 @@ FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&&
|
|||
const Formattable& source = toFormat.asFormattable();
|
||||
switch (source.getType()) {
|
||||
case UFMT_STRING: {
|
||||
// Lazily initialize date parsers used for parsing date literals
|
||||
parent.initDateParsers(errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const UnicodeString& sourceStr = source.getString(errorCode);
|
||||
U_ASSERT(U_SUCCESS(errorCode));
|
||||
|
||||
|
|
|
@ -64,6 +64,15 @@ namespace message2 {
|
|||
|
||||
DateTimeType type;
|
||||
DateTimeFactory(DateTimeType t) : type(t) {}
|
||||
|
||||
// Lazily initialize cached date parsers
|
||||
void initDateParsers(UErrorCode&);
|
||||
|
||||
// Cached parsers; lazily initialized
|
||||
LocalPointer<DateFormat> dateParser;
|
||||
LocalPointer<DateFormat> dateTimeParser;
|
||||
LocalPointer<DateFormat> dateTimeUTCParser;
|
||||
LocalPointer<DateFormat> dateTimeZoneParser;
|
||||
};
|
||||
|
||||
class DateTime : public Formatter {
|
||||
|
@ -75,9 +84,18 @@ namespace message2 {
|
|||
const Locale& locale;
|
||||
const DateTimeFactory::DateTimeType type;
|
||||
friend class DateTimeFactory;
|
||||
DateTime(const Locale& l, DateTimeFactory::DateTimeType t) : locale(l), type(t) {}
|
||||
DateTime(const Locale& l, DateTimeFactory& p, DateTimeFactory::DateTimeType t)
|
||||
: locale(l), type(t), parent(p) {}
|
||||
const LocalPointer<icu::DateFormat> icuFormatter;
|
||||
|
||||
// Stores the cached DateFormat objects for parsing date literals
|
||||
DateTimeFactory& parent;
|
||||
|
||||
// Methods for parsing date literals
|
||||
UDate tryPatterns(const UnicodeString&, UErrorCode&) const;
|
||||
UDate tryTimeZonePatterns(const UnicodeString&, UErrorCode&) const;
|
||||
DateInfo createDateInfoFromString(const UnicodeString&, UErrorCode&) const;
|
||||
|
||||
/*
|
||||
Looks up an option by name, first checking `opts`, then the cached options
|
||||
in `toFormat` if applicable, and finally using a default
|
||||
|
|
|
@ -132,6 +132,10 @@
|
|||
"exp": "7:23:45\u202FPM GMT+03:30",
|
||||
"params": {"d": "2024-07-02T19:23:45+03:30"},
|
||||
"comment": "This checks that an argument can be a date literal string."
|
||||
},
|
||||
{
|
||||
"src": "{|2006-01-02T15:04:06| :datetime dateStyle=long} / {|2006-01-03| :datetime dateStyle=medium}",
|
||||
"exp": "January 2, 2006 / Jan 3, 2006"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue