From 3195f2506822ced7ec00c54d094290a843cfb3d3 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Thu, 5 Mar 2015 06:34:51 +0000 Subject: [PATCH] ICU-11358 Separate host time zone detection code from the default time zone initialization code and make it public API as TimeZone::detectHostTimeZone(). X-SVN-Rev: 37148 --- icu4c/source/i18n/timezone.cpp | 87 ++++++++++++++++----------- icu4c/source/i18n/unicode/timezone.h | 19 +++++- icu4c/source/test/intltest/tztest.cpp | 7 +++ 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 3cb8a7b79bf..c6dbf445d9b 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2014, International Business Machines Corporation and +* Copyright (C) 1997-2015, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * @@ -445,21 +445,9 @@ TimeZone::createTimeZone(const UnicodeString& ID) // ------------------------------------- -/** - * Initialize DEFAULT_ZONE from the system default time zone. - * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() - * returns NULL. - */ -static void U_CALLCONV initDefault() +TimeZone* U_EXPORT2 +TimeZone::detectHostTimeZone() { - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - - // If setDefault() has already been called we can skip getting the - // default zone information from the system. - if (DEFAULT_ZONE != NULL) { - return; - } - // We access system timezone data through TPlatformUtilities, // including tzset(), timezone, and tzname[]. int32_t rawOffset = 0; @@ -468,16 +456,6 @@ static void U_CALLCONV initDefault() // First, try to create a system timezone, based // on the string ID in tzname[0]. - // NOTE: this code is safely single threaded, being only - // run via umtx_initOnce(). - // - // Some of the locale/timezone OS functions may not be thread safe, - // - // The operating system might actually use ICU to implement timezones. - // So we may have ICU calling ICU here, like on AIX. - // There shouldn't be a problem with this; initOnce does not hold a mutex - // while the init function is being run. - uprv_tzset(); // Initialize tz... system data // Get the timezone ID from the host. This function should do @@ -489,13 +467,13 @@ static void U_CALLCONV initDefault() // Invert sign because UNIX semantics are backwards rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND; - TimeZone* default_zone = NULL; + TimeZone* hostZone = NULL; /* Make sure that the string is NULL terminated to prevent BoundsChecker/Purify warnings. */ UnicodeString hostStrID(hostID, -1, US_INV); hostStrID.append((UChar)0); hostStrID.truncate(hostStrID.length()-1); - default_zone = createSystemTimeZone(hostStrID); + hostZone = createSystemTimeZone(hostStrID); #if U_PLATFORM_USES_ONLY_WIN32_API // hostID points to a heap-allocated location on Windows. @@ -503,30 +481,69 @@ static void U_CALLCONV initDefault() #endif int32_t hostIDLen = hostStrID.length(); - if (default_zone != NULL && rawOffset != default_zone->getRawOffset() + if (hostZone != NULL && rawOffset != hostZone->getRawOffset() && (3 <= hostIDLen && hostIDLen <= 4)) { // Uh oh. This probably wasn't a good id. // It was probably an ambiguous abbreviation - delete default_zone; - default_zone = NULL; + delete hostZone; + hostZone = NULL; } // Construct a fixed standard zone with the host's ID // and raw offset. - if (default_zone == NULL) { - default_zone = new SimpleTimeZone(rawOffset, hostStrID); + if (hostZone == NULL) { + hostZone = new SimpleTimeZone(rawOffset, hostStrID); } // If we _still_ don't have a time zone, use GMT. - if (default_zone == NULL) { + // + // Note: This is extremely unlikely situation. If + // new SimpleTimeZone(...) above fails, the following + // code may also fail. + if (hostZone == NULL) { const TimeZone* temptz = TimeZone::getGMT(); // If we can't use GMT, get out. if (temptz == NULL) { - return; + return NULL; } - default_zone = temptz->clone(); + hostZone = temptz->clone(); + } + + return hostZone; +} + +// ------------------------------------- + +/** + * Initialize DEFAULT_ZONE from the system default time zone. + * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() + * returns NULL. + */ +static void U_CALLCONV initDefault() +{ + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + + // If setDefault() has already been called we can skip getting the + // default zone information from the system. + if (DEFAULT_ZONE != NULL) { + return; } + + // NOTE: this code is safely single threaded, being only + // run via umtx_initOnce(). + // + // Some of the locale/timezone OS functions may not be thread safe, + // + // The operating system might actually use ICU to implement timezones. + // So we may have ICU calling ICU here, like on AIX. + // There shouldn't be a problem with this; initOnce does not hold a mutex + // while the init function is being run. + + // The code detecting the host time zone was separated from this + // and implemented as TimeZone::detectHostTimeZone() + + TimeZone *default_zone = TimeZone::detectHostTimeZone(); // The only way for DEFAULT_ZONE to be non-null at this point is if the user // made a thread-unsafe call to setDefault() or adoptDefault() in another diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h index fa4f5bf9150..c3356c9738a 100644 --- a/icu4c/source/i18n/unicode/timezone.h +++ b/icu4c/source/i18n/unicode/timezone.h @@ -1,5 +1,5 @@ /************************************************************************* -* Copyright (c) 1997-2014, International Business Machines Corporation +* Copyright (c) 1997-2015, International Business Machines Corporation * and others. All Rights Reserved. ************************************************************************** * @@ -273,6 +273,23 @@ public: static const UnicodeString U_EXPORT2 getEquivalentID(const UnicodeString& id, int32_t index); +#ifndef U_HIDE_DRAFT_API + /** + * Creates an instance of TimeZone detected from the current host + * system configuration. Note that ICU4C does not change the default + * time zone unless TimeZone::adoptDefault(TimeZone*) or + * TimeZone::setDefault(const TimeZone&) is explicitly called by a + * user. This method does not update the current ICU's default, + * and may return a different TimeZone from the one returned by + * TimeZone::createDefault(). + * + * @return A new instance of TimeZone detected from the current host system + * configuration. + * @draft ICU 55 + */ + static TimeZone* U_EXPORT2 detectHostTimeZone(); +#endif + /** * Creates a new copy of the default TimeZone for this host. Unless the default time * zone has already been set using adoptDefault() or setDefault(), the default is diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp index a9beaf1eded..fdb1a20fb75 100644 --- a/icu4c/source/test/intltest/tztest.cpp +++ b/icu4c/source/test/intltest/tztest.cpp @@ -135,6 +135,13 @@ TimeZoneTest::TestGenericAPI() infoln("WARNING: t_timezone may be incorrect. It is not a multiple of 15min.", tzoffset); } + TimeZone* hostZone = TimeZone::detectHostTimeZone(); + /* Host time zone's offset should match the offset returned by uprv_timezone() */ + if (hostZone->getRawOffset() != tzoffset * (-1000)) { + errln("FAIL: detectHostTimeZone()'s raw offset != host timezone's offset"); + } + delete hostZone; + UErrorCode status = U_ZERO_ERROR; const char* tzver = TimeZone::getTZDataVersion(status); if (U_FAILURE(status)) { -- 2.40.0