Bug 1731620 - Part 6: Add default time zone setters to mozila::intl::TimeZone. r=platform-i18n-reviewers,gregtatum

Add setters to change ICU's default time zone.
1. `SetDefaultTimeZone()` sets the default time zone from a time zone identifier.
2. `SetDefaultTimeZoneFromHostTimeZone()` synchronizes the default time zone with
   the host system's time zone.

The two new methods will be used in the next part to replace ICU calls in
`js::DateTimeInfo::internalResyncICUDefaultTimeZone()`.

Differential Revision: https://phabricator.services.mozilla.com/D126196
This commit is contained in:
André Bargull 2021-09-23 10:51:58 +00:00
Родитель 0d2aefce15
Коммит f0ef6836c5
2 изменённых файлов: 119 добавлений и 5 удалений

Просмотреть файл

@ -4,6 +4,11 @@
#include "mozilla/intl/TimeZone.h"
#include "mozilla/Vector.h"
#include <algorithm>
#include <string_view>
#include "unicode/uenum.h"
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE
# include "unicode/basictz.h"
@ -208,6 +213,97 @@ Result<int32_t, ICUError> TimeZone::GetUTCOffsetMs(int64_t aLocalMilliseconds) {
#endif
}
using TimeZoneIdentifierVector =
Vector<char16_t, TimeZone::TimeZoneIdentifierLength>;
#if !MOZ_INTL_USE_ICU_CPP_TIMEZONE
static bool IsUnknownTimeZone(const TimeZoneIdentifierVector& timeZone) {
constexpr std::string_view unknownTimeZone = UCAL_UNKNOWN_ZONE_ID;
return timeZone.length() == unknownTimeZone.length() &&
std::equal(timeZone.begin(), timeZone.end(), unknownTimeZone.begin(),
unknownTimeZone.end());
}
static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) {
// The string mustn't already be null-terminated.
MOZ_ASSERT_IF(!timeZone.empty(), timeZone.end()[-1] != '\0');
// The time zone identifier must be a null-terminated string.
if (!timeZone.append('\0')) {
return Err(ICUError::OutOfMemory);
}
UErrorCode status = U_ZERO_ERROR;
ucal_setDefaultTimeZone(timeZone.begin(), &status);
if (U_FAILURE(status)) {
return Err(ToICUError(status));
}
return Ok{};
}
#endif
Result<bool, ICUError> TimeZone::SetDefaultTimeZone(
Span<const char> aTimeZone) {
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE
icu::UnicodeString tzid(aTimeZone.data(), aTimeZone.size(), US_INV);
if (tzid.isBogus()) {
return Err(ICUError::OutOfMemory);
}
UniquePtr<icu::TimeZone> newTimeZone(icu::TimeZone::createTimeZone(tzid));
MOZ_ASSERT(newTimeZone);
if (*newTimeZone != icu::TimeZone::getUnknown()) {
// adoptDefault() takes ownership of the time zone.
icu::TimeZone::adoptDefault(newTimeZone.release());
return true;
}
#else
TimeZoneIdentifierVector tzid;
if (!tzid.append(aTimeZone.data(), aTimeZone.size())) {
return Err(ICUError::OutOfMemory);
}
// Retrieve the current default time zone in case we need to restore it.
TimeZoneIdentifierVector defaultTimeZone;
MOZ_TRY(FillVectorWithICUCall(defaultTimeZone, ucal_getDefaultTimeZone));
// Try to set the new time zone.
MOZ_TRY(mozilla::intl::SetDefaultTimeZone(tzid));
// Check if the time zone was actually applied.
TimeZoneIdentifierVector newTimeZone;
MOZ_TRY(FillVectorWithICUCall(newTimeZone, ucal_getDefaultTimeZone));
// Return if the new time zone was successfully applied.
if (!IsUnknownTimeZone(newTimeZone)) {
return true;
}
// Otherwise restore the original time zone.
MOZ_TRY(mozilla::intl::SetDefaultTimeZone(defaultTimeZone));
#endif
return false;
}
ICUResult TimeZone::SetDefaultTimeZoneFromHostTimeZone() {
#if MOZ_INTL_USE_ICU_CPP_TIMEZONE
if (icu::TimeZone* defaultZone = icu::TimeZone::detectHostTimeZone()) {
icu::TimeZone::adoptDefault(defaultZone);
}
#else
TimeZoneIdentifierVector hostTimeZone;
MOZ_TRY(FillVectorWithICUCall(hostTimeZone, ucal_getHostTimeZone));
MOZ_TRY(mozilla::intl::SetDefaultTimeZone(hostTimeZone));
#endif
return Ok{};
}
Result<SpanEnumeration<char>, ICUError> TimeZone::GetAvailableTimeZones(
const char* aRegion) {
// Get the time zones that are commonly used in the given region. Uses the

Просмотреть файл

@ -143,6 +143,28 @@ class TimeZone final {
return FillBufferWithICUCall(aBuffer, ucal_getDefaultTimeZone);
}
/**
* Set the default time zone.
*/
static Result<bool, ICUError> SetDefaultTimeZone(Span<const char> aTimeZone);
/**
* Set the default time zone using the host system's time zone.
*
* NOTE: This function is not thread-safe.
*/
static ICUResult SetDefaultTimeZoneFromHostTimeZone();
/**
* Constant for the typical maximal length of a time zone identifier.
*
* At the time of this writing 32 characters fits every supported time zone:
*
* Intl.supportedValuesOf("timeZone")
* .reduce((acc, v) => Math.max(acc, v.length), 0)
*/
static constexpr size_t TimeZoneIdentifierLength = 32;
/**
* Returns the canonical system time zone ID or the normalized custom time
* zone ID for the given time zone ID.
@ -157,11 +179,7 @@ class TimeZone final {
// ucal_getCanonicalTimeZoneID differs from other API calls and fails when
// passed a nullptr or 0 length result. Reserve some space initially so
// that a real pointer will be used in the API.
//
// At the time of this writing 32 characters fits every time zone listed
// in: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
// https://gist.github.com/gregtatum/f926de157a44e5965864da866fe71e63
if (!aBuffer.reserve(32)) {
if (!aBuffer.reserve(TimeZoneIdentifierLength)) {
return Err(ICUError::OutOfMemory);
}
}