From 4809b7211702310adabf3f33db55806a0c2416b0 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Mon, 8 Mar 2021 19:33:55 -0800 Subject: [PATCH 01/15] Loading time_zone names from icu.dll --- stl/inc/chrono | 138 +++- stl/inc/xtzdb.h | 28 + stl/src/msvcp_atomic_wait.src | 4 + stl/src/tzdb.cpp | 284 ++++++- tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 759 ++++++++++++++++++ 7 files changed, 1213 insertions(+), 5 deletions(-) create mode 100644 tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/env.lst create mode 100644 tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp diff --git a/stl/inc/chrono b/stl/inc/chrono index de7457d2631..6f9178f7b15 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2215,6 +2215,36 @@ namespace chrono { return hours{_Ret}; } + // [time.zone.timezone] + + // TRANSITION: work in progress + class time_zone { + public: + time_zone(std::string_view _Name) : _Name(_Name) {} + + // FIXME: The standard denotes move semantics are required. Is is valid to add + // copy semantics as well to make interacting with the CRT allocator easier. + // time_zone(time_zone&&) = default; + // time_zone& operator=(time_zone&&) = default; + + _NODISCARD string_view name() const noexcept { + return _Name; + } + + private: + std::string _Name; + }; + + _NODISCARD inline bool operator==(const time_zone& _Left, const time_zone& _Right) noexcept { + return _Left.name() == _Right.name(); + } + +#ifdef __cpp_lib_concepts + _NODISCARD inline strong_ordering operator<=>(const time_zone& _Left, const time_zone& _Right) noexcept { + return _Left.name() <=> _Right.name(); + } +#endif // __cpp_lib_concepts + // [time.zone.leap] // CLASS leap_second @@ -2309,15 +2339,110 @@ namespace chrono { } #endif // __cpp_lib_concepts + // [time.zone.link] + + class time_zone_link { + public: + time_zone_link(std::string_view _Name, std::string_view _Target) : _Name(_Name), _Target(_Target) {} + + // FIXME: see comment in time_zone... + // time_zone_link(time_zone_link&&) = default; + // time_zone_link& operator=(time_zone_link&&) = default; + + string_view name() const noexcept { + return _Name; + } + + string_view target() const noexcept { + return _Target; + } + + private: + std::string _Name; + std::string _Target; + }; + + _NODISCARD inline bool operator==(const time_zone_link& _Left, const time_zone_link& _Right) noexcept { + return _Left.name() == _Right.name(); + } + +#ifdef __cpp_lib_concepts + _NODISCARD inline strong_ordering operator<=>(const time_zone_link& _Left, const time_zone_link& _Right) noexcept { + return _Left.name() <=> _Right.name(); + } +#endif // __cpp_lib_concepts + // [time.zone.db] - // TRANSITION: work in progress - // STRUCT tzdb + _NODISCARD inline string _Xtzdb_generate_current_zone() { + unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{ + __std_tzdb_get_current_zone(), &__std_tzdb_delete_current_zone}; + if (_Info == nullptr) { + _Xbad_alloc(); + } else if (_Info->_Err == __std_tzdb_error::_Win_error) { + _XGetLastError(); + } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { + _Xruntime_error("FIXME: what generic message should I use here?"); + } + + return {_Info->_Tz_name}; + } + + template + _NODISCARD const _Ty* _Locate_zone_impl(const std::vector<_Ty, _Crt_allocator<_Ty>>& _Vec, string_view _Name) { + const auto _Result = find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; }); + return _Result != _Vec.end() ? &(*_Result) : nullptr; + } + struct tzdb { + vector> time_zones; + vector> links; vector> leap_seconds; bool _All_ls_positive; + + _NODISCARD const time_zone* locate_zone(string_view _Tz_name) const { + auto _Tz = _Locate_zone_impl(time_zones, _Tz_name); + if (_Tz == nullptr) { + const auto _Link = _Locate_zone_impl(links, _Tz_name); + if (_Link != nullptr) { + _Tz = _Locate_zone_impl(time_zones, _Link->target()); + } + } + + return _Tz; + } + + _NODISCARD const time_zone* current_zone() const { + return locate_zone(_Xtzdb_generate_current_zone()); + } }; + _NODISCARD inline pair _Xtzdb_generate_time_zones() { + unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{ + __std_tzdb_get_time_zones(), &__std_tzdb_delete_time_zones}; + if (_Info == nullptr) { + _Xbad_alloc(); + } else if (_Info->_Err == __std_tzdb_error::_Win_error) { + _XGetLastError(); + } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { + _Xruntime_error("FIXME: what generic message should I use here?"); + } + + decltype(tzdb::time_zones) _Time_zones; + decltype(tzdb::links) _Time_zone_links; + for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { + const std::string_view _Name{_Info->_Names[_Idx], strlen(_Info->_Names[_Idx])}; + if (_Info->_Links[_Idx] == nullptr) { + _Time_zones.push_back(time_zone{_Name}); + } else { + const std::string_view _Target{_Info->_Links[_Idx], strlen(_Info->_Links[_Idx])}; + _Time_zone_links.push_back(time_zone_link{_Name, _Target}); + } + } + + return {_Time_zones, _Time_zone_links}; + } + _NODISCARD inline pair _Xtzdb_generate_leap_seconds( const size_t _Current_size) { // Returns empty vector if no new leap seconds are found. @@ -2407,8 +2532,10 @@ namespace chrono { tzdb_list& operator=(const tzdb_list&) = delete; tzdb_list() { + auto [_Time_zones, _Links] = _Xtzdb_generate_time_zones(); auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(0); - _Tzdb_list.emplace_front(tzdb{_STD move(_Leap_sec), _All_ls_positive}); + _Tzdb_list.emplace_front( + tzdb{_STD move(_Time_zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } _NODISCARD const tzdb& front() const noexcept { @@ -2426,7 +2553,10 @@ namespace chrono { _Unique_lock _Lk(_Tzdb_mutex); auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(_Tzdb_list.front().leap_seconds.size()); if (!_Leap_sec.empty()) { - _Tzdb_list.emplace_front(tzdb{_STD move(_Leap_sec), _All_ls_positive}); + decltype(tzdb::time_zones) _Time_zones{_Tzdb_list.front().time_zones}; + decltype(tzdb::links) _Links{_Tzdb_list.front().links}; + _Tzdb_list.emplace_front( + tzdb{_STD move(_Time_zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } return _Tzdb_list.front(); } diff --git a/stl/inc/xtzdb.h b/stl/inc/xtzdb.h index 734d050ecf4..d4b0f289cef 100644 --- a/stl/inc/xtzdb.h +++ b/stl/inc/xtzdb.h @@ -29,8 +29,36 @@ struct __std_tzdb_registry_leap_info { uint16_t _Reserved; }; +enum class __std_tzdb_error { + _Success = 0, + _Win_error = 1, + _Icu_error = 2, +}; + +struct __std_tzdb_time_zones_info { + __std_tzdb_error _Err; + size_t _Num_time_zones; + // ordered list of nullterminated time_zone/time_zone_link names + const char** _Names; + // contains corrosponding entry for every name, if: + // (_Link[i] == nullptr) then _Names[i] is a time_zone + // (_Link[i] != nullptr) then _Names[i] is a time_zone_link to time_zone with name _Link[i] + const char** _Links; +}; + +struct __std_tzdb_current_zone_info { + __std_tzdb_error _Err; + const char* _Tz_name; +}; + _EXTERN_C +_NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept; +void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept; + +_NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept; +void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* _Info) noexcept; + __std_tzdb_registry_leap_info* __stdcall __std_tzdb_get_reg_leap_seconds( size_t _Prev_reg_ls_size, size_t* _Current_reg_ls_size) noexcept; diff --git a/stl/src/msvcp_atomic_wait.src b/stl/src/msvcp_atomic_wait.src index 2c7b1b76b33..cd8f13dcaf1 100644 --- a/stl/src/msvcp_atomic_wait.src +++ b/stl/src/msvcp_atomic_wait.src @@ -30,5 +30,9 @@ EXPORTS __std_parallel_algorithms_hw_threads __std_release_shared_mutex_for_instance __std_submit_threadpool_work + __std_tzdb_delete_current_zone + __std_tzdb_delete_time_zones + __std_tzdb_get_current_zone __std_tzdb_get_reg_leap_seconds + __std_tzdb_get_time_zones __std_wait_for_threadpool_work_callbacks diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index f49ff2ff792..636aab2c5f3 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -1,15 +1,297 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include +#include +#include +#include #include +#define NOMINMAX +#include +#include + #include #pragma comment(lib, "Advapi32") +namespace { + enum class _Icu_api_level : unsigned long { + __not_set, + __detecting, + __has_failed, + __has_icu_addresses, + }; + + struct _Icu_functions_table { + _STD atomic _Pfn_ucal_getDefaultTimeZone{nullptr}; + _STD atomic _Pfn_ucal_openTimeZoneIDEnumeration{nullptr}; + _STD atomic _Pfn_uenum_close{nullptr}; + _STD atomic _Pfn_uenum_count{nullptr}; + _STD atomic _Pfn_uenum_unext{nullptr}; + _STD atomic<_Icu_api_level> _Api_level{_Icu_api_level::__not_set}; + }; + + _Icu_functions_table _Icu_functions; + + template + void _Load_address(const HMODULE _Module, _STD atomic& _Stored_Pfn, LPCSTR _Fn_name, DWORD& _Last_error) { + const auto _Pfn = reinterpret_cast(GetProcAddress(_Module, _Fn_name)); + if (_Pfn != nullptr) { + _Stored_Pfn.store(_Pfn, _STD memory_order_relaxed); + } else { + _Last_error = GetLastError(); + } + } + + // FIXME: Inspired from what I found in atomic.cpp. Is this overkill, I wasn't sure what to do + // with race conditions and static state. I didn't want to LoadLibraryExW twice. + _NODISCARD _Icu_api_level _Init_icu_functions(_Icu_api_level _Level) noexcept { + while (!_Icu_functions._Api_level.compare_exchange_weak(_Level, _Icu_api_level::__detecting)) { + if (_Level > _Icu_api_level::__detecting) { + return _Level; + } + } + + _Level = _Icu_api_level::__has_failed; + + const HMODULE _Icu_module = LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (_Icu_module != nullptr) { + // collect at least one error if any GetProcAddress call fails + DWORD _Last_error{0}; + _Load_address( + _Icu_module, _Icu_functions._Pfn_ucal_getDefaultTimeZone, "ucal_getDefaultTimeZone", _Last_error); + _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_openTimeZoneIDEnumeration, + "ucal_openTimeZoneIDEnumeration", _Last_error); + _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_close, "uenum_close", _Last_error); + _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_count, "uenum_count", _Last_error); + _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_unext, "uenum_unext", _Last_error); + if (_Last_error == ERROR_SUCCESS) { + _Level = _Icu_api_level::__has_icu_addresses; + } else { + // reset last-error in-case a later GetProcAddress resets it + SetLastError(_Last_error); + } + } + + _Icu_functions._Api_level.store(_Level, _STD memory_order_release); + return _Level; + } + + _NODISCARD _Icu_api_level _Acquire_icu_functions() noexcept { + auto _Level = _Icu_functions._Api_level.load(_STD memory_order_acquire); + if (_Level <= _Icu_api_level::__detecting) { + _Level = _Init_icu_functions(_Level); + } + + return _Level; + } + + _NODISCARD int32_t __icu_ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) noexcept { + const auto _Fun = _Icu_functions._Pfn_ucal_getDefaultTimeZone.load(_STD memory_order_relaxed); + return _Fun(result, resultCapacity, ec); + } + + _NODISCARD UEnumeration* __icu_ucal_openTimeZoneIDEnumeration( + USystemTimeZoneType zoneType, const char* region, const int32_t* rawOffset, UErrorCode* ec) { + const auto _Fun = _Icu_functions._Pfn_ucal_openTimeZoneIDEnumeration.load(_STD memory_order_relaxed); + return _Fun(zoneType, region, rawOffset, ec); + } + + _NODISCARD void __icu_uenum_close(UEnumeration* en) { + const auto _Fun = _Icu_functions._Pfn_uenum_close.load(_STD memory_order_relaxed); + return _Fun(en); + } + + _NODISCARD int32_t __icu_uenum_count(UEnumeration* en, UErrorCode* ec) { + const auto _Fun = _Icu_functions._Pfn_uenum_count.load(_STD memory_order_relaxed); + return _Fun(en, ec); + } + + _NODISCARD const UChar* __icu_uenum_unext(UEnumeration* en, int32_t* resultLength, UErrorCode* status) { + const auto _Fun = _Icu_functions._Pfn_uenum_unext.load(_STD memory_order_relaxed); + return _Fun(en, resultLength, status); + } + + struct _Tz_link { + const char* _Target; + const char* _Name; + }; + + // FIXME: Likely not the final implementation just here to open a design discussion on + // how to handle time_zone_link. See test.cpp for further details on the issue. + static const _Tz_link _Known_links[] = { + // clang-format off + // Target // Name + {"Pacific/Auckland", "Antarctica/McMurdo"}, + {"Africa/Maputo", "Africa/Lusaka"} + // clang-format on + }; + + _NODISCARD const char* _Allocate_wide_to_narrow( + const char16_t* _Input, int _Input_len, __std_tzdb_error& _Err) noexcept { + const auto _Code_page = __std_fs_code_page(); + const auto _Input_as_wchar = reinterpret_cast(_Input); + // FIXME: Is is ok to pull in xfilesystem_abi.h and use these here? + const auto _Count_result = __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, nullptr, 0); + if (_Count_result._Err != __std_win_error::_Success) { + _Err = __std_tzdb_error::_Win_error; + return nullptr; + } + + auto* _Data = new (_STD nothrow) char[_Count_result._Len + 1]; + if (_Data == nullptr) { + return nullptr; + } + + _Data[_Count_result._Len] = '\0'; + + const auto _Result = + __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, _Data, _Count_result._Len); + if (_Result._Err != __std_win_error::_Success) { + _Err = __std_tzdb_error::_Win_error; + delete[] _Data; + return nullptr; + } + + return _Data; + } + +} // namespace + _EXTERN_C +_NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept { + // On exit--- + // *_Info == nullptr --> bad_alloc() + // _Info->_Err == _Win_error --> failed, call GetLastError() + // _Info->_Err == _Icu_error --> runtime_error interacting with ICU + _STD unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{ + new (_STD nothrow) __std_tzdb_time_zones_info{}, &__std_tzdb_delete_time_zones}; + if (_Info == nullptr) { + return nullptr; + } + + if (_Acquire_icu_functions() < _Icu_api_level::__has_icu_addresses) { + _Info->_Err = __std_tzdb_error::_Win_error; + return _Info.release(); + } + + UErrorCode _Err{}; + _STD unique_ptr _Enum{ + __icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_CANONICAL, nullptr, nullptr, &_Err), + &__icu_uenum_close}; + if (U_FAILURE(_Err)) { + _Info->_Err = __std_tzdb_error::_Icu_error; + return _Info.release(); + } + + // uenum_count may be expensive but is required to pre allocated arrays. + int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_Err); + if (U_FAILURE(_Err)) { + _Info->_Err = __std_tzdb_error::_Icu_error; + return _Info.release(); + } + + _Info->_Num_time_zones = static_cast(_Num_time_zones); + _Info->_Names = new (_STD nothrow) const char*[_Info->_Num_time_zones]; + if (_Info->_Names == nullptr) { + return nullptr; + } + + // init to ensure __std_tzdb_delete_init_info cleanup is valid + _STD fill_n(_Info->_Names, (ptrdiff_t) _Info->_Num_time_zones, nullptr); + + _Info->_Links = new (_STD nothrow) const char*[_Info->_Num_time_zones]; + if (_Info->_Links == nullptr) { + return nullptr; + } + + // init to ensure __std_tzdb_delete_init_info cleanup is valid + _STD fill_n(_Info->_Links, _Info->_Num_time_zones, nullptr); + + for (size_t _Name_idx = 0; _Name_idx < _Info->_Num_time_zones; ++_Name_idx) { + int32_t _Elem_len{}; + const auto* _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_Err); + if (U_FAILURE(_Err) || _Elem == nullptr) { + _Info->_Err = __std_tzdb_error::_Icu_error; + return _Info.release(); + } + + _Info->_Names[_Name_idx] = _Allocate_wide_to_narrow(_Elem, _Elem_len, _Info->_Err); + if (_Info->_Names[_Name_idx] == nullptr) { + return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + } + + // ensure time_zone is not a known time_zone_link + for (const auto& _Link : _Known_links) { + if (strcmp(_Info->_Names[_Name_idx], _Link._Name) == 0) { + _Info->_Links[_Name_idx] = _Link._Target; // no need to allocate a string + } + } + } + + return _Info.release(); +} + +void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept { + if (_Info != nullptr) { + if (_Info->_Names != nullptr) { + for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; _Idx++) { + if (_Info->_Names[_Idx] != nullptr) { + delete[] _Info->_Names[_Idx]; + } + } + + delete[] _Info->_Names; + _Info->_Names = nullptr; + } + + if (_Info->_Links != nullptr) { + delete[] _Info->_Links; + _Info->_Links = nullptr; + } + } +} + +_NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept { + // On exit--- + // *_Info == nullptr --> bad_alloc() + // _Info->_Err == _Win_error --> failed, call GetLastError() + // _Info->_Err == _Icu_error --> runtime_error interacting with ICU + _STD unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{ + new (_STD nothrow) __std_tzdb_current_zone_info{}, &__std_tzdb_delete_current_zone}; + if (_Info == nullptr) { + return nullptr; + } + + if (_Acquire_icu_functions() < _Icu_api_level::__has_icu_addresses) { + _Info->_Err = __std_tzdb_error::_Win_error; + return _Info.release(); + } + + UErrorCode _Err{}; + char16_t _Id_buf[256]; + const auto _Id_buf_len = __icu_ucal_getDefaultTimeZone(_Id_buf, sizeof(_Id_buf), &_Err); + if (U_FAILURE(_Err) || _Id_buf_len == 0) { + _Info->_Err = __std_tzdb_error::_Icu_error; + return _Info.release(); + } + + _Info->_Tz_name = _Allocate_wide_to_narrow(_Id_buf, static_cast(_Id_buf_len), _Info->_Err); + if (_Info->_Tz_name == nullptr) { + return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + } + + return _Info.release(); +} + +void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* _Info) noexcept { + if (_Info) { + delete[] _Info->_Tz_name; + _Info->_Tz_name = nullptr; + } +} + __std_tzdb_registry_leap_info* __stdcall __std_tzdb_get_reg_leap_seconds( const size_t prev_reg_ls_size, size_t* const current_reg_ls_size) noexcept { // On exit--- diff --git a/tests/std/test.lst b/tests/std/test.lst index e5866c93af1..3b7270fd45a 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -235,6 +235,7 @@ tests\P0355R7_calendars_and_time_zones_dates_literals tests\P0355R7_calendars_and_time_zones_hms tests\P0355R7_calendars_and_time_zones_io tests\P0355R7_calendars_and_time_zones_time_point_and_durations +tests\P0355R7_calendars_and_time_zones_time_zones tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0408R7_efficient_access_to_stringbuf_buffer diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp new file mode 100644 index 00000000000..dee8d355a1c --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp @@ -0,0 +1,759 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +void test_time_zone_and_link(const tzdb& tzdb, string_view tz_name, string_view tz_link_name) { + const auto orginal_tz = tzdb.locate_zone(tz_name); + assert(orginal_tz != nullptr); + assert(orginal_tz->name() == tz_name); + + const auto linked_tz = tzdb.locate_zone(tz_link_name); + assert(linked_tz != nullptr); + assert(linked_tz->name() == tz_name); + assert(orginal_tz == linked_tz); + + const auto tz_link = _Locate_zone_impl(tzdb.links, tz_link_name); + assert(tz_link != nullptr); + assert(tz_link->name() == tz_link_name); + assert(tz_link->target() == tz_name); + assert(tzdb.locate_zone(tz_link->target()) == orginal_tz); + + assert(_Locate_zone_impl(tzdb.time_zones, tz_name) != nullptr); + assert(_Locate_zone_impl(tzdb.time_zones, tz_link_name) == nullptr); + assert(_Locate_zone_impl(tzdb.links, tz_name) == nullptr); +} + +void timezone_names_test() { + const auto& tzdb = get_tzdb(); + + test_time_zone_and_link(tzdb, "Africa/Maputo", "Africa/Lusaka"); + test_time_zone_and_link(tzdb, "Pacific/Auckland", "Antarctica/McMurdo"); + + const auto current_zone = tzdb.current_zone(); + assert(current_zone != nullptr); + assert(current_zone->name().empty() == false); + + assert(tzdb.locate_zone("Non/Existent") == nullptr); + + // Abbreviations should not be time_zones or time_zone_links + assert(tzdb.locate_zone("PST") == nullptr); + assert(tzdb.locate_zone("AEST") == nullptr); + + // Comparison operators + const time_zone tz1{"Earlier"}; + const time_zone tz2{"Earlier"}; + const time_zone tz3{"Later"}; + assert(tz1 == tz2); + assert(tz1 != tz3); +#ifdef __cpp_lib_concepts + assert(tz1 <=> tz2 == strong_ordering::equal); + assert(tz1 <=> tz3 == strong_ordering::less); + assert(tz3 <=> tz1 == strong_ordering::greater); +#endif // __cpp_lib_concepts + + const time_zone_link link1{"Earlier", "Target"}; + const time_zone_link link2{"Earlier", "Is"}; + const time_zone_link link3{"Later", "Ignored"}; + assert(link1 == link2); + assert(link1 != link3); +#ifdef __cpp_lib_concepts + assert(link1 <=> link2 == strong_ordering::equal); + assert(link1 <=> link3 == strong_ordering::less); + assert(link3 <=> link1 == strong_ordering::greater); +#endif // __cpp_lib_concepts +} + +// FIXME: This is an illustration of the gaps/difference between database and ICU timezones. +// I don't think this would be the best thing to actually test as it is changes. +// Tz_status::Time_zone => IANA time_zone +// Tz_status::Time_zone_link => IANA time_zone_link +// Tz_status::Canonical => ICU time_zone, these include "some" IANA links and are +// treated as regular zones for API calls. +// Tz_status::Any => You can request all timezones. In the ICU non-canonical +// timezones are links to canoncial timezones but annoyingly: +// 1) some match IANA link other do not +// 2) some of these links match actual IANA timezones +// 3) they have lots of aliases unrelated to anything in the IANA +enum Tz_status { Time_zone, Time_zone_link, Absent, Canonical, Any }; + +void validate_time_zone(string_view name, Tz_status db_status, Tz_status icu_status) { + (void) db_status; // Used to illustrate expected value in IANA + + const auto& tzdb = get_tzdb(); + switch (icu_status) { + case Tz_status::Time_zone: + case Tz_status::Canonical: // using USystemTimeZoneType::UCAL_ZONE_TYPE_CANONICAL + assert(_Locate_zone_impl(tzdb.time_zones, name) != nullptr); + assert(_Locate_zone_impl(tzdb.links, name) == nullptr); + break; + case Tz_status::Time_zone_link: + assert(_Locate_zone_impl(tzdb.time_zones, name) == nullptr); + assert(_Locate_zone_impl(tzdb.links, name) != nullptr); + break; + case Tz_status::Absent: + assert(_Locate_zone_impl(tzdb.time_zones, name) == nullptr); + assert(_Locate_zone_impl(tzdb.links, name) == nullptr); + break; + case Tz_status::Any: // using USystemTimeZoneType::UCAL_ZONE_TYPE_ANY + default: + break; + } +} + +void all_timezone_names() { + // List generated from a script using IANA database (version 2021a) and ICU (Win 10.0.19042 Build 19042) + // clang-format off + // Name IANA status ICU status + validate_time_zone("ACT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("AET", Tz_status::Absent, Tz_status::Any); + validate_time_zone("AGT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("ART", Tz_status::Absent, Tz_status::Any); + validate_time_zone("AST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Africa/Abidjan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Accra", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Addis_Ababa", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Algiers", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Asmara", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Africa/Asmera", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Bamako", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Bangui", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Banjul", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Bissau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Blantyre", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Brazzaville", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Bujumbura", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Cairo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Casablanca", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Ceuta", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Conakry", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Dakar", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Dar_es_Salaam", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Djibouti", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Douala", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/El_Aaiun", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Freetown", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Gaborone", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Harare", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Johannesburg", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Juba", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Kampala", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Khartoum", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Kigali", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Kinshasa", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Lagos", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Libreville", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Lome", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Luanda", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Lubumbashi", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Lusaka", Tz_status::Time_zone_link, Tz_status::Time_zone_link); // Tz_status::Canonical. Changed for testing + validate_time_zone("Africa/Malabo", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Maputo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Maseru", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Mbabane", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Mogadishu", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Monrovia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Nairobi", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Ndjamena", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Niamey", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Nouakchott", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Ouagadougou", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Porto-Novo", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Africa/Sao_Tome", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Timbuktu", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Africa/Tripoli", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Tunis", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Africa/Windhoek", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Adak", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Anchorage", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Anguilla", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Antigua", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Araguaina", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/Buenos_Aires", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Argentina/Catamarca", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Argentina/ComodRivadavia",Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Argentina/Cordoba", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Argentina/Jujuy", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Argentina/La_Rioja", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/Mendoza", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Argentina/Rio_Gallegos", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/Salta", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/San_Juan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/San_Luis", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/Tucuman", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Argentina/Ushuaia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Aruba", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Asuncion", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Atikokan", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Atka", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Bahia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Bahia_Banderas", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Barbados", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Belem", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Belize", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Blanc-Sablon", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Boa_Vista", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Bogota", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Boise", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Buenos_Aires", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Cambridge_Bay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Campo_Grande", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Cancun", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Caracas", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Catamarca", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Cayenne", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Cayman", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Chicago", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Chihuahua", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Coral_Harbour", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Cordoba", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Costa_Rica", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Creston", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Cuiaba", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Curacao", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Danmarkshavn", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Dawson", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Dawson_Creek", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Denver", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Detroit", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Dominica", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Edmonton", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Eirunepe", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/El_Salvador", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Ensenada", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Fort_Nelson", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Fort_Wayne", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Fortaleza", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Glace_Bay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Godthab", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Goose_Bay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Grand_Turk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Grenada", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Guadeloupe", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Guatemala", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Guayaquil", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Guyana", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Halifax", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Havana", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Hermosillo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Indianapolis", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Indiana/Knox", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Marengo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Petersburg", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Tell_City", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Vevay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Vincennes", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indiana/Winamac", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Indianapolis", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Inuvik", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Iqaluit", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Jamaica", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Jujuy", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Juneau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Kentucky/Louisville", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("America/Kentucky/Monticello", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Knox_IN", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Kralendijk", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/La_Paz", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Lima", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Los_Angeles", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Louisville", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Lower_Princes", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Maceio", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Managua", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Manaus", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Marigot", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Martinique", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Matamoros", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Mazatlan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Mendoza", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Menominee", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Merida", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Metlakatla", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Mexico_City", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Miquelon", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Moncton", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Monterrey", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Montevideo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Montreal", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Montserrat", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Nassau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/New_York", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Nipigon", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Nome", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Noronha", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/North_Dakota/Beulah", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/North_Dakota/Center", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/North_Dakota/New_Salem", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Nuuk", Tz_status::Time_zone, Tz_status::Absent); + validate_time_zone("America/Ojinaga", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Panama", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Pangnirtung", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Paramaribo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Phoenix", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Port-au-Prince", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Port_of_Spain", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Porto_Acre", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Porto_Velho", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Puerto_Rico", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Punta_Arenas", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Rainy_River", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Rankin_Inlet", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Recife", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Regina", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Resolute", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Rio_Branco", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Rosario", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Santa_Isabel", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Santarem", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Santiago", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Santo_Domingo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Sao_Paulo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Scoresbysund", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Shiprock", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Sitka", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/St_Barthelemy", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/St_Johns", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/St_Kitts", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/St_Lucia", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/St_Thomas", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/St_Vincent", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Swift_Current", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Tegucigalpa", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Thule", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Thunder_Bay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Tijuana", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Toronto", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Tortola", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("America/Vancouver", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Virgin", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("America/Whitehorse", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Winnipeg", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Yakutat", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("America/Yellowknife", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Casey", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Davis", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/DumontDUrville", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Macquarie", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Mawson", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/McMurdo", Tz_status::Time_zone_link, Tz_status::Time_zone_link);; // Tz_status::Canonical. Changed for testing + validate_time_zone("Antarctica/Palmer", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Rothera", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/South_Pole", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Antarctica/Syowa", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Troll", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Antarctica/Vostok", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Arctic/Longyearbyen", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Aden", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Almaty", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Amman", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Anadyr", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Aqtau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Aqtobe", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ashgabat", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ashkhabad", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Atyrau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Baghdad", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Bahrain", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Baku", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Bangkok", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Barnaul", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Beirut", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Bishkek", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Brunei", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Calcutta", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Chita", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Choibalsan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Chongqing", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Chungking", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Colombo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Dacca", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Damascus", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Dhaka", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Dili", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Dubai", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Dushanbe", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Famagusta", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Gaza", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Harbin", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Hebron", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ho_Chi_Minh", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Asia/Hong_Kong", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Hovd", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Irkutsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Istanbul", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Jakarta", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Jayapura", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Jerusalem", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kabul", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kamchatka", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Karachi", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kashgar", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Kathmandu", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Asia/Katmandu", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Khandyga", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kolkata", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Asia/Krasnoyarsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kuala_Lumpur", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kuching", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Kuwait", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Macao", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Macau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Magadan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Makassar", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Manila", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Muscat", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Nicosia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Novokuznetsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Novosibirsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Omsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Oral", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Phnom_Penh", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Pontianak", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Pyongyang", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Qatar", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Qostanay", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Qyzylorda", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Rangoon", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Riyadh", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Saigon", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Sakhalin", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Samarkand", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Seoul", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Shanghai", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Singapore", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Srednekolymsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Taipei", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tashkent", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tbilisi", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tehran", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tel_Aviv", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Thimbu", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Thimphu", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tokyo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Tomsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ujung_Pandang", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Ulaanbaatar", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ulan_Bator", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Asia/Urumqi", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Ust-Nera", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Vientiane", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Asia/Vladivostok", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Yakutsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Yangon", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Asia/Yekaterinburg", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Asia/Yerevan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Azores", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Bermuda", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Canary", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Cape_Verde", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Faeroe", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Atlantic/Faroe", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Atlantic/Jan_Mayen", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Atlantic/Madeira", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/Reykjavik", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/South_Georgia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Atlantic/St_Helena", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Atlantic/Stanley", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/ACT", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Adelaide", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Brisbane", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Broken_Hill", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Canberra", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Currie", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Australia/Darwin", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Eucla", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Hobart", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/LHI", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Lindeman", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Lord_Howe", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Melbourne", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/NSW", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/North", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Perth", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Queensland", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/South", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Sydney", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Australia/Tasmania", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Victoria", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/West", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Australia/Yancowinna", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("BET", Tz_status::Absent, Tz_status::Any); + validate_time_zone("BST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Brazil/Acre", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Brazil/DeNoronha", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Brazil/East", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Brazil/West", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("CAT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("CET", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("CNT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("CST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("CST6CDT", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("CTT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Canada/Atlantic", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Central", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/East-Saskatchewan", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Canada/Eastern", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Mountain", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Newfoundland", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Pacific", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Saskatchewan", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Canada/Yukon", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Chile/Continental", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Chile/EasterIsland", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Cuba", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("EAT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("ECT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("EET", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("EST", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("EST5EDT", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Egypt", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Eire", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Etc/GMT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+0", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Etc/GMT+1", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+10", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+11", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+12", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+2", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+3", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+4", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+5", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+6", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+7", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+8", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT+9", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-0", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Etc/GMT-1", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-10", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-11", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-12", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-13", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-14", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-2", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-3", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-4", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-5", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-6", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-7", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-8", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT-9", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/GMT0", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Etc/Greenwich", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Etc/UCT", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Etc/UTC", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Etc/Universal", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Etc/Zulu", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Europe/Amsterdam", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Andorra", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Astrakhan", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Athens", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Belfast", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Europe/Belgrade", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Berlin", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Bratislava", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Brussels", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Bucharest", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Budapest", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Busingen", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Chisinau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Copenhagen", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Dublin", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Gibraltar", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Guernsey", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Helsinki", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Isle_of_Man", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Istanbul", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Jersey", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Kaliningrad", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Kiev", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Kirov", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Lisbon", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Ljubljana", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/London", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Luxembourg", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Madrid", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Malta", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Mariehamn", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Minsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Monaco", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Moscow", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Nicosia", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Europe/Oslo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Paris", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Podgorica", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Prague", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Riga", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Rome", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Samara", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/San_Marino", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Sarajevo", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Saratov", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Simferopol", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Skopje", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Sofia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Stockholm", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Tallinn", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Tirane", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Tiraspol", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Europe/Ulyanovsk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Uzhgorod", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Vaduz", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Vatican", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Vienna", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Vilnius", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Volgograd", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Warsaw", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Zagreb", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Europe/Zaporozhye", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Europe/Zurich", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Factory", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("GB", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("GB-Eire", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("GMT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("GMT+0", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("GMT-0", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("GMT0", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Greenwich", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("HST", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Hongkong", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("IET", Tz_status::Absent, Tz_status::Any); + validate_time_zone("IST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Iceland", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Indian/Antananarivo", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Indian/Chagos", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Christmas", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Cocos", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Comoro", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Indian/Kerguelen", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Mahe", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Maldives", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Mauritius", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Indian/Mayotte", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Indian/Reunion", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Iran", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Israel", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("JST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Jamaica", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Japan", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Kwajalein", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Libya", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("MET", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("MIT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("MST", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("MST7MDT", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Mexico/BajaNorte", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Mexico/BajaSur", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Mexico/General", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("NET", Tz_status::Absent, Tz_status::Any); + validate_time_zone("NST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("NZ", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("NZ-CHAT", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Navajo", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("PLT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("PNT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("PRC", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("PRT", Tz_status::Absent, Tz_status::Any); + validate_time_zone("PST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("PST8PDT", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Apia", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Auckland", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Bougainville", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Chatham", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Chuuk", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Pacific/Easter", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Efate", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Enderbury", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Fakaofo", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Fiji", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Funafuti", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Galapagos", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Gambier", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Guadalcanal", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Guam", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Honolulu", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Johnston", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Pacific/Kiritimati", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Kosrae", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Kwajalein", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Majuro", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Marquesas", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Midway", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Pacific/Nauru", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Niue", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Norfolk", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Noumea", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Pago_Pago", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Palau", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Pitcairn", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Pohnpei", Tz_status::Time_zone, Tz_status::Any); + validate_time_zone("Pacific/Ponape", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Pacific/Port_Moresby", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Rarotonga", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Saipan", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Pacific/Samoa", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Pacific/Tahiti", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Tarawa", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Tongatapu", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Truk", Tz_status::Time_zone_link, Tz_status::Canonical); + validate_time_zone("Pacific/Wake", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Wallis", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Pacific/Yap", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Poland", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Portugal", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("ROC", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("ROK", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("SST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("Singapore", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("SystemV/AST4", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/AST4ADT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/CST6", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/CST6CDT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/EST5", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/EST5EDT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/HST10", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/MST7", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/MST7MDT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/PST8", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/PST8PDT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/YST9", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("SystemV/YST9YDT", Tz_status::Absent, Tz_status::Canonical); + validate_time_zone("Turkey", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("UCT", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Alaska", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Aleutian", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Arizona", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Central", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/East-Indiana", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Eastern", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Hawaii", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Indiana-Starke", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Michigan", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Mountain", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Pacific", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("US/Pacific-New", Tz_status::Absent, Tz_status::Any); + validate_time_zone("US/Samoa", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("UTC", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("Universal", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("VST", Tz_status::Absent, Tz_status::Any); + validate_time_zone("W-SU", Tz_status::Time_zone_link, Tz_status::Any); + validate_time_zone("WET", Tz_status::Time_zone, Tz_status::Canonical); + validate_time_zone("Zulu", Tz_status::Time_zone_link, Tz_status::Any); + // clang-format on +} + +bool test() { + timezone_names_test(); + all_timezone_names(); + + return true; +} + +int main() { + test(); +} From 98312d85d91f4c64cd3c049f6563a28130ef3cd0 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Mon, 8 Mar 2021 20:28:26 -0800 Subject: [PATCH 02/15] formatting --- .../P0355R7_calendars_and_time_zones_time_zones/test.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp index dee8d355a1c..ee2b5ebb428 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp @@ -151,7 +151,8 @@ void all_timezone_names() { validate_time_zone("Africa/Lome", Tz_status::Time_zone_link, Tz_status::Canonical); validate_time_zone("Africa/Luanda", Tz_status::Time_zone_link, Tz_status::Canonical); validate_time_zone("Africa/Lubumbashi", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Lusaka", Tz_status::Time_zone_link, Tz_status::Time_zone_link); // Tz_status::Canonical. Changed for testing + // vvv Tz_status::Canonical. Changed for testing vvv + validate_time_zone("Africa/Lusaka", Tz_status::Time_zone_link, Tz_status::Time_zone_link); validate_time_zone("Africa/Malabo", Tz_status::Time_zone_link, Tz_status::Canonical); validate_time_zone("Africa/Maputo", Tz_status::Time_zone, Tz_status::Canonical); validate_time_zone("Africa/Maseru", Tz_status::Time_zone_link, Tz_status::Canonical); @@ -341,7 +342,8 @@ void all_timezone_names() { validate_time_zone("Antarctica/DumontDUrville", Tz_status::Time_zone, Tz_status::Canonical); validate_time_zone("Antarctica/Macquarie", Tz_status::Time_zone, Tz_status::Canonical); validate_time_zone("Antarctica/Mawson", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/McMurdo", Tz_status::Time_zone_link, Tz_status::Time_zone_link);; // Tz_status::Canonical. Changed for testing + // vvv Tz_status::Canonical. Changed for testing vvv + validate_time_zone("Antarctica/McMurdo", Tz_status::Time_zone_link, Tz_status::Time_zone_link); validate_time_zone("Antarctica/Palmer", Tz_status::Time_zone, Tz_status::Canonical); validate_time_zone("Antarctica/Rothera", Tz_status::Time_zone, Tz_status::Canonical); validate_time_zone("Antarctica/South_Pole", Tz_status::Time_zone_link, Tz_status::Any); From cf0df74e12d13790767daf60928f949081bb9ab6 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Tue, 9 Mar 2021 10:42:48 -0800 Subject: [PATCH 03/15] Addressed feedback and fixed tests. --- stl/inc/chrono | 64 ++++++++++--------- stl/inc/xtzdb.h | 4 +- stl/src/tzdb.cpp | 58 ++++++++--------- .../test.cpp | 17 ++++- 4 files changed, 78 insertions(+), 65 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 6f9178f7b15..c1bfe875fdb 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2220,19 +2220,17 @@ namespace chrono { // TRANSITION: work in progress class time_zone { public: - time_zone(std::string_view _Name) : _Name(_Name) {} + explicit time_zone(string_view _Name_) : _Name(_Name_) {} - // FIXME: The standard denotes move semantics are required. Is is valid to add - // copy semantics as well to make interacting with the CRT allocator easier. - // time_zone(time_zone&&) = default; - // time_zone& operator=(time_zone&&) = default; + time_zone(time_zone&&) = default; + time_zone& operator=(time_zone&&) = default; _NODISCARD string_view name() const noexcept { return _Name; } private: - std::string _Name; + string _Name; }; _NODISCARD inline bool operator==(const time_zone& _Left, const time_zone& _Right) noexcept { @@ -2343,23 +2341,22 @@ namespace chrono { class time_zone_link { public: - time_zone_link(std::string_view _Name, std::string_view _Target) : _Name(_Name), _Target(_Target) {} + explicit time_zone_link(string_view _Name_, string_view _Target_) : _Name(_Name_), _Target(_Target_) {} - // FIXME: see comment in time_zone... - // time_zone_link(time_zone_link&&) = default; - // time_zone_link& operator=(time_zone_link&&) = default; + time_zone_link(time_zone_link&&) = default; + time_zone_link& operator=(time_zone_link&&) = default; - string_view name() const noexcept { + _NODISCARD string_view name() const noexcept { return _Name; } - string_view target() const noexcept { + _NODISCARD string_view target() const noexcept { return _Target; } private: - std::string _Name; - std::string _Target; + string _Name; + string _Target; }; _NODISCARD inline bool operator==(const time_zone_link& _Left, const time_zone_link& _Right) noexcept { @@ -2382,22 +2379,22 @@ namespace chrono { } else if (_Info->_Err == __std_tzdb_error::_Win_error) { _XGetLastError(); } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { - _Xruntime_error("FIXME: what generic message should I use here?"); + _Xruntime_error("Internal error loading IANA database information"); } return {_Info->_Tz_name}; } template - _NODISCARD const _Ty* _Locate_zone_impl(const std::vector<_Ty, _Crt_allocator<_Ty>>& _Vec, string_view _Name) { - const auto _Result = find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; }); - return _Result != _Vec.end() ? &(*_Result) : nullptr; + _NODISCARD const _Ty* _Locate_zone_impl(const vector<_Ty>& _Vec, string_view _Name) { + const auto _Result = _STD find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; }); + return _Result != _Vec.end() ? &*_Result : nullptr; } struct tzdb { - vector> time_zones; - vector> links; - vector> leap_seconds; + vector time_zones; + vector links; + vector leap_seconds; bool _All_ls_positive; _NODISCARD const time_zone* locate_zone(string_view _Tz_name) const { @@ -2425,22 +2422,22 @@ namespace chrono { } else if (_Info->_Err == __std_tzdb_error::_Win_error) { _XGetLastError(); } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { - _Xruntime_error("FIXME: what generic message should I use here?"); + _Xruntime_error("Internal error loading IANA database information"); } decltype(tzdb::time_zones) _Time_zones; decltype(tzdb::links) _Time_zone_links; for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { - const std::string_view _Name{_Info->_Names[_Idx], strlen(_Info->_Names[_Idx])}; + const string_view _Name{_Info->_Names[_Idx]}; if (_Info->_Links[_Idx] == nullptr) { - _Time_zones.push_back(time_zone{_Name}); + _Time_zones.emplace_back(_Name); } else { - const std::string_view _Target{_Info->_Links[_Idx], strlen(_Info->_Links[_Idx])}; - _Time_zone_links.push_back(time_zone_link{_Name, _Target}); + const string_view _Target{_Info->_Links[_Idx]}; + _Time_zone_links.emplace_back(_Name, _Target); } } - return {_Time_zones, _Time_zone_links}; + return {_STD move(_Time_zones), _STD move(_Time_zone_links)}; } _NODISCARD inline pair _Xtzdb_generate_leap_seconds( @@ -2516,7 +2513,7 @@ namespace chrono { } } - return {_Leap_sec_info, _All_ls_positive}; + return {_STD move(_Leap_sec_info), _All_ls_positive}; } // TRANSITION: work in progress @@ -2553,8 +2550,15 @@ namespace chrono { _Unique_lock _Lk(_Tzdb_mutex); auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(_Tzdb_list.front().leap_seconds.size()); if (!_Leap_sec.empty()) { - decltype(tzdb::time_zones) _Time_zones{_Tzdb_list.front().time_zones}; - decltype(tzdb::links) _Links{_Tzdb_list.front().links}; + const auto& _Tzdb = _Tzdb_list.front(); + vector _Time_zones; + _STD transform(_Tzdb.time_zones.begin(), _Tzdb.time_zones.end(), _STD back_inserter(_Time_zones), + [](const auto& _Tz) { return time_zone{_Tz.name()}; }); + vector _Links; + _STD transform( + _Tzdb.links.begin(), _Tzdb.links.end(), _STD back_inserter(_Links), [](const auto& _Link) { + return time_zone_link{_Link.name(), _Link.target()}; + }); _Tzdb_list.emplace_front( tzdb{_STD move(_Time_zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } diff --git a/stl/inc/xtzdb.h b/stl/inc/xtzdb.h index d4b0f289cef..b623337059a 100644 --- a/stl/inc/xtzdb.h +++ b/stl/inc/xtzdb.h @@ -38,9 +38,9 @@ enum class __std_tzdb_error { struct __std_tzdb_time_zones_info { __std_tzdb_error _Err; size_t _Num_time_zones; - // ordered list of nullterminated time_zone/time_zone_link names + // ordered list of null-terminated time_zone/time_zone_link names const char** _Names; - // contains corrosponding entry for every name, if: + // contains corresponding entry for every name, if: // (_Link[i] == nullptr) then _Names[i] is a time_zone // (_Link[i] != nullptr) then _Names[i] is a time_zone_link to time_zone with name _Link[i] const char** _Links; diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index 636aab2c5f3..71944207cdb 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -3,10 +3,11 @@ #include #include +#include #include #include -#define NOMINMAX +#define NOMINMAX // TODO: remove #include #include @@ -16,10 +17,10 @@ namespace { enum class _Icu_api_level : unsigned long { - __not_set, - __detecting, - __has_failed, - __has_icu_addresses, + _Not_set, + _Detecting, + _Has_failed, + _Has_icu_addresses, }; struct _Icu_functions_table { @@ -28,7 +29,7 @@ namespace { _STD atomic _Pfn_uenum_close{nullptr}; _STD atomic _Pfn_uenum_count{nullptr}; _STD atomic _Pfn_uenum_unext{nullptr}; - _STD atomic<_Icu_api_level> _Api_level{_Icu_api_level::__not_set}; + _STD atomic<_Icu_api_level> _Api_level{_Icu_api_level::_Not_set}; }; _Icu_functions_table _Icu_functions; @@ -46,13 +47,13 @@ namespace { // FIXME: Inspired from what I found in atomic.cpp. Is this overkill, I wasn't sure what to do // with race conditions and static state. I didn't want to LoadLibraryExW twice. _NODISCARD _Icu_api_level _Init_icu_functions(_Icu_api_level _Level) noexcept { - while (!_Icu_functions._Api_level.compare_exchange_weak(_Level, _Icu_api_level::__detecting)) { - if (_Level > _Icu_api_level::__detecting) { + while (!_Icu_functions._Api_level.compare_exchange_weak(_Level, _Icu_api_level::_Detecting)) { + if (_Level > _Icu_api_level::_Detecting) { return _Level; } } - _Level = _Icu_api_level::__has_failed; + _Level = _Icu_api_level::_Has_failed; const HMODULE _Icu_module = LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if (_Icu_module != nullptr) { @@ -66,7 +67,7 @@ namespace { _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_count, "uenum_count", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_unext, "uenum_unext", _Last_error); if (_Last_error == ERROR_SUCCESS) { - _Level = _Icu_api_level::__has_icu_addresses; + _Level = _Icu_api_level::_Has_icu_addresses; } else { // reset last-error in-case a later GetProcAddress resets it SetLastError(_Last_error); @@ -79,7 +80,7 @@ namespace { _NODISCARD _Icu_api_level _Acquire_icu_functions() noexcept { auto _Level = _Icu_functions._Api_level.load(_STD memory_order_acquire); - if (_Level <= _Icu_api_level::__detecting) { + if (_Level <= _Icu_api_level::_Detecting) { _Level = _Init_icu_functions(_Level); } @@ -114,16 +115,16 @@ namespace { struct _Tz_link { const char* _Target; - const char* _Name; + _STD string_view _Name; }; // FIXME: Likely not the final implementation just here to open a design discussion on // how to handle time_zone_link. See test.cpp for further details on the issue. - static const _Tz_link _Known_links[] = { + constexpr _Tz_link _Known_links[] = { // clang-format off // Target // Name {"Pacific/Auckland", "Antarctica/McMurdo"}, - {"Africa/Maputo", "Africa/Lusaka"} + {"Africa/Maputo", "Africa/Lusaka"}, // clang-format on }; @@ -138,7 +139,7 @@ namespace { return nullptr; } - auto* _Data = new (_STD nothrow) char[_Count_result._Len + 1]; + _STD unique_ptr _Data{new (_STD nothrow) char[_Count_result._Len + 1]}; if (_Data == nullptr) { return nullptr; } @@ -146,14 +147,13 @@ namespace { _Data[_Count_result._Len] = '\0'; const auto _Result = - __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, _Data, _Count_result._Len); + __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, _Data.get(), _Count_result._Len); if (_Result._Err != __std_win_error::_Success) { _Err = __std_tzdb_error::_Win_error; - delete[] _Data; return nullptr; } - return _Data; + return _Data.release(); } } // namespace @@ -171,7 +171,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return nullptr; } - if (_Acquire_icu_functions() < _Icu_api_level::__has_icu_addresses) { + if (_Acquire_icu_functions() < _Icu_api_level::_Has_icu_addresses) { _Info->_Err = __std_tzdb_error::_Win_error; return _Info.release(); } @@ -199,7 +199,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe } // init to ensure __std_tzdb_delete_init_info cleanup is valid - _STD fill_n(_Info->_Names, (ptrdiff_t) _Info->_Num_time_zones, nullptr); + _STD fill_n(_Info->_Names, static_cast(_Info->_Num_time_zones), nullptr); _Info->_Links = new (_STD nothrow) const char*[_Info->_Num_time_zones]; if (_Info->_Links == nullptr) { @@ -207,7 +207,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe } // init to ensure __std_tzdb_delete_init_info cleanup is valid - _STD fill_n(_Info->_Links, _Info->_Num_time_zones, nullptr); + _STD fill_n(_Info->_Links, static_cast(_Info->_Num_time_zones), nullptr); for (size_t _Name_idx = 0; _Name_idx < _Info->_Num_time_zones; ++_Name_idx) { int32_t _Elem_len{}; @@ -224,7 +224,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe // ensure time_zone is not a known time_zone_link for (const auto& _Link : _Known_links) { - if (strcmp(_Info->_Names[_Name_idx], _Link._Name) == 0) { + if (_Link._Name == _Info->_Names[_Name_idx]) { _Info->_Links[_Name_idx] = _Link._Target; // no need to allocate a string } } @@ -236,20 +236,16 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept { if (_Info != nullptr) { if (_Info->_Names != nullptr) { - for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; _Idx++) { - if (_Info->_Names[_Idx] != nullptr) { - delete[] _Info->_Names[_Idx]; - } + for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { + delete[] _Info->_Names[_Idx]; } delete[] _Info->_Names; _Info->_Names = nullptr; } - if (_Info->_Links != nullptr) { - delete[] _Info->_Links; - _Info->_Links = nullptr; - } + delete[] _Info->_Links; + _Info->_Links = nullptr; } } @@ -264,7 +260,7 @@ _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() return nullptr; } - if (_Acquire_icu_functions() < _Icu_api_level::__has_icu_addresses) { + if (_Acquire_icu_functions() < _Icu_api_level::_Has_icu_addresses) { _Info->_Err = __std_tzdb_error::_Win_error; return _Info.release(); } diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp index cc8b5a8096c..2513aec54dc 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp @@ -378,6 +378,19 @@ static_assert(is_clock_v); static_assert(is_clock_v); static_assert(is_clock_v); +tzdb copy_tzdb() { + const auto& my_tzdb = get_tzdb_list().front(); + vector time_zones; + vector links; + _STD transform(my_tzdb.time_zones.begin(), my_tzdb.time_zones.end(), _STD back_inserter(time_zones), + [](const auto& _Tz) { return time_zone{_Tz.name()}; }); + _STD transform(my_tzdb.links.begin(), my_tzdb.links.end(), _STD back_inserter(links), [](const auto& link) { + return time_zone_link{link.name(), link.target()}; + }); + + return {_STD move(time_zones), _STD move(links), my_tzdb.leap_seconds, my_tzdb._All_ls_positive}; +} + int main() { assert(test_leap_second()); static_assert(test_leap_second()); @@ -408,7 +421,7 @@ int main() { // a negative leap second when the accumulated offset is positive { - auto my_tzdb = get_tzdb_list().front(); + auto my_tzdb = copy_tzdb(); auto& leap_vec = my_tzdb.leap_seconds; leap_vec.erase(leap_vec.begin() + 27, leap_vec.end()); leap_vec.emplace_back(sys_days{1d / January / 2020y}, false, leap_vec.back()._Elapsed()); @@ -434,7 +447,7 @@ int main() { // positive and negative leap seconds when the accumulated offset is negative { - auto my_tzdb = get_tzdb_list().front(); + auto my_tzdb = copy_tzdb(); auto& leap_vec = my_tzdb.leap_seconds; leap_vec.erase(leap_vec.begin() + 27, leap_vec.end()); for (int i = 0; i < 30; ++i) { From d89b26fd01314107a7300f5815b331d641df44ec Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Tue, 9 Mar 2021 19:25:19 -0800 Subject: [PATCH 04/15] Removed manual link map and altered tests. --- azure-devops/native-build-test.yml | 2 +- azure-devops/run-tests.yml | 2 +- stl/src/tzdb.cpp | 73 +- .../test.cpp | 702 +----------------- 4 files changed, 62 insertions(+), 717 deletions(-) diff --git a/azure-devops/native-build-test.yml b/azure-devops/native-build-test.yml index 17fa03732ae..e3cf652dc46 100644 --- a/azure-devops/native-build-test.yml +++ b/azure-devops/native-build-test.yml @@ -11,7 +11,7 @@ parameters: default: buildOutputLocation - name: numShards type: number - default: 8 + default: 1 jobs: - job: '${{ parameters.targetPlatform }}' variables: diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml index a247bfc43c4..ad4a79e3b1a 100644 --- a/azure-devops/run-tests.yml +++ b/azure-devops/run-tests.yml @@ -27,7 +27,7 @@ steps: script: | call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo - ctest -V + python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std --filter P0355R7_calendars_and_time_zones_time_zones:00 -v env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: PublishTestResults@2 displayName: 'Publish Tests' diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index 71944207cdb..1e06868475c 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -2,15 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include +#include #include #include #include #include -#define NOMINMAX // TODO: remove -#include -#include - #include #pragma comment(lib, "Advapi32") @@ -24,6 +22,7 @@ namespace { }; struct _Icu_functions_table { + _STD atomic _Pfn_ucal_getCanonicalTimeZoneID{nullptr}; _STD atomic _Pfn_ucal_getDefaultTimeZone{nullptr}; _STD atomic _Pfn_ucal_openTimeZoneIDEnumeration{nullptr}; _STD atomic _Pfn_uenum_close{nullptr}; @@ -59,6 +58,8 @@ namespace { if (_Icu_module != nullptr) { // collect at least one error if any GetProcAddress call fails DWORD _Last_error{0}; + _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_getCanonicalTimeZoneID, "ucal_getCanonicalTimeZoneID", + _Last_error); _Load_address( _Icu_module, _Icu_functions._Pfn_ucal_getDefaultTimeZone, "ucal_getDefaultTimeZone", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_openTimeZoneIDEnumeration, @@ -87,6 +88,12 @@ namespace { return _Level; } + _NODISCARD int32_t __icu_ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, UChar* result, + int32_t resultCapacity, UBool* isSystemID, UErrorCode* status) noexcept { + const auto _Fun = _Icu_functions._Pfn_ucal_getCanonicalTimeZoneID.load(_STD memory_order_relaxed); + return _Fun(id, len, result, resultCapacity, isSystemID, status); + } + _NODISCARD int32_t __icu_ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) noexcept { const auto _Fun = _Icu_functions._Pfn_ucal_getDefaultTimeZone.load(_STD memory_order_relaxed); return _Fun(result, resultCapacity, ec); @@ -113,21 +120,6 @@ namespace { return _Fun(en, resultLength, status); } - struct _Tz_link { - const char* _Target; - _STD string_view _Name; - }; - - // FIXME: Likely not the final implementation just here to open a design discussion on - // how to handle time_zone_link. See test.cpp for further details on the issue. - constexpr _Tz_link _Known_links[] = { - // clang-format off - // Target // Name - {"Pacific/Auckland", "Antarctica/McMurdo"}, - {"Africa/Maputo", "Africa/Lusaka"}, - // clang-format on - }; - _NODISCARD const char* _Allocate_wide_to_narrow( const char16_t* _Input, int _Input_len, __std_tzdb_error& _Err) noexcept { const auto _Code_page = __std_fs_code_page(); @@ -176,18 +168,18 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return _Info.release(); } - UErrorCode _Err{}; + UErrorCode _UErr{}; _STD unique_ptr _Enum{ - __icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_CANONICAL, nullptr, nullptr, &_Err), + __icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_ANY, nullptr, nullptr, &_UErr), &__icu_uenum_close}; - if (U_FAILURE(_Err)) { + if (U_FAILURE(_UErr)) { _Info->_Err = __std_tzdb_error::_Icu_error; return _Info.release(); } // uenum_count may be expensive but is required to pre allocated arrays. - int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_Err); - if (U_FAILURE(_Err)) { + int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_UErr); + if (U_FAILURE(_UErr)) { _Info->_Err = __std_tzdb_error::_Icu_error; return _Info.release(); } @@ -211,8 +203,8 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe for (size_t _Name_idx = 0; _Name_idx < _Info->_Num_time_zones; ++_Name_idx) { int32_t _Elem_len{}; - const auto* _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_Err); - if (U_FAILURE(_Err) || _Elem == nullptr) { + const auto* _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_UErr); + if (U_FAILURE(_UErr) || _Elem == nullptr) { _Info->_Err = __std_tzdb_error::_Icu_error; return _Info.release(); } @@ -222,10 +214,21 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; } - // ensure time_zone is not a known time_zone_link - for (const auto& _Link : _Known_links) { - if (_Link._Name == _Info->_Names[_Name_idx]) { - _Info->_Links[_Name_idx] = _Link._Target; // no need to allocate a string + UBool _Is_system{}; + // FIXME: what is the right size here and is it ok to stack allocate. + char16_t _Link_buf[256]; + const auto _Link_buf_len = + __icu_ucal_getCanonicalTimeZoneID(_Elem, _Elem_len, _Link_buf, sizeof(_Link_buf), &_Is_system, &_UErr); + if (U_FAILURE(_UErr) || _Link_buf_len == 0) { + _Info->_Err = __std_tzdb_error::_Icu_error; + return _Info.release(); + } + + if (_STD u16string_view{_Elem, static_cast(_Elem_len)} + != _STD u16string_view{_Link_buf, static_cast(_Link_buf_len)}) { + _Info->_Links[_Name_idx] = _Allocate_wide_to_narrow(_Link_buf, _Link_buf_len, _Info->_Err); + if (_Info->_Links[_Name_idx] == nullptr) { + return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; } } } @@ -244,8 +247,14 @@ void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) n _Info->_Names = nullptr; } - delete[] _Info->_Links; - _Info->_Links = nullptr; + if (_Info->_Links != nullptr) { + for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { + delete[] _Info->_Links[_Idx]; + } + + delete[] _Info->_Names; + _Info->_Names = nullptr; + } } } diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp index ee2b5ebb428..4a5a74e061a 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include using namespace std; using namespace std::chrono; @@ -32,8 +34,8 @@ void test_time_zone_and_link(const tzdb& tzdb, string_view tz_name, string_view void timezone_names_test() { const auto& tzdb = get_tzdb(); - test_time_zone_and_link(tzdb, "Africa/Maputo", "Africa/Lusaka"); - test_time_zone_and_link(tzdb, "Pacific/Auckland", "Antarctica/McMurdo"); + test_time_zone_and_link(tzdb, "Asia/Thimphu", "Asia/Thimbu"); + test_time_zone_and_link(tzdb, "America/Tijuana", "America/Ensenada"); const auto current_zone = tzdb.current_zone(); assert(current_zone != nullptr); @@ -42,7 +44,7 @@ void timezone_names_test() { assert(tzdb.locate_zone("Non/Existent") == nullptr); // Abbreviations should not be time_zones or time_zone_links - assert(tzdb.locate_zone("PST") == nullptr); + assert(tzdb.locate_zone("PDT") == nullptr); assert(tzdb.locate_zone("AEST") == nullptr); // Comparison operators @@ -67,691 +69,25 @@ void timezone_names_test() { assert(link1 <=> link3 == strong_ordering::less); assert(link3 <=> link1 == strong_ordering::greater); #endif // __cpp_lib_concepts -} - -// FIXME: This is an illustration of the gaps/difference between database and ICU timezones. -// I don't think this would be the best thing to actually test as it is changes. -// Tz_status::Time_zone => IANA time_zone -// Tz_status::Time_zone_link => IANA time_zone_link -// Tz_status::Canonical => ICU time_zone, these include "some" IANA links and are -// treated as regular zones for API calls. -// Tz_status::Any => You can request all timezones. In the ICU non-canonical -// timezones are links to canoncial timezones but annoyingly: -// 1) some match IANA link other do not -// 2) some of these links match actual IANA timezones -// 3) they have lots of aliases unrelated to anything in the IANA -enum Tz_status { Time_zone, Time_zone_link, Absent, Canonical, Any }; -void validate_time_zone(string_view name, Tz_status db_status, Tz_status icu_status) { - (void) db_status; // Used to illustrate expected value in IANA + // FIXME: add a link to an issue. These may change overtime and might have to be removed from tests. - const auto& tzdb = get_tzdb(); - switch (icu_status) { - case Tz_status::Time_zone: - case Tz_status::Canonical: // using USystemTimeZoneType::UCAL_ZONE_TYPE_CANONICAL - assert(_Locate_zone_impl(tzdb.time_zones, name) != nullptr); - assert(_Locate_zone_impl(tzdb.links, name) == nullptr); - break; - case Tz_status::Time_zone_link: - assert(_Locate_zone_impl(tzdb.time_zones, name) == nullptr); - assert(_Locate_zone_impl(tzdb.links, name) != nullptr); - break; - case Tz_status::Absent: - assert(_Locate_zone_impl(tzdb.time_zones, name) == nullptr); - assert(_Locate_zone_impl(tzdb.links, name) == nullptr); - break; - case Tz_status::Any: // using USystemTimeZoneType::UCAL_ZONE_TYPE_ANY - default: - break; - } -} - -void all_timezone_names() { - // List generated from a script using IANA database (version 2021a) and ICU (Win 10.0.19042 Build 19042) - // clang-format off - // Name IANA status ICU status - validate_time_zone("ACT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("AET", Tz_status::Absent, Tz_status::Any); - validate_time_zone("AGT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("ART", Tz_status::Absent, Tz_status::Any); - validate_time_zone("AST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Africa/Abidjan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Accra", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Addis_Ababa", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Algiers", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Asmara", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Africa/Asmera", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Bamako", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Bangui", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Banjul", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Bissau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Blantyre", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Brazzaville", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Bujumbura", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Cairo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Casablanca", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Ceuta", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Conakry", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Dakar", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Dar_es_Salaam", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Djibouti", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Douala", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/El_Aaiun", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Freetown", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Gaborone", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Harare", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Johannesburg", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Juba", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Kampala", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Khartoum", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Kigali", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Kinshasa", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Lagos", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Libreville", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Lome", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Luanda", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Lubumbashi", Tz_status::Time_zone_link, Tz_status::Canonical); - // vvv Tz_status::Canonical. Changed for testing vvv - validate_time_zone("Africa/Lusaka", Tz_status::Time_zone_link, Tz_status::Time_zone_link); - validate_time_zone("Africa/Malabo", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Maputo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Maseru", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Mbabane", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Mogadishu", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Monrovia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Nairobi", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Ndjamena", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Niamey", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Nouakchott", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Ouagadougou", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Porto-Novo", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Africa/Sao_Tome", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Timbuktu", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Africa/Tripoli", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Tunis", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Africa/Windhoek", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Adak", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Anchorage", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Anguilla", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Antigua", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Araguaina", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/Buenos_Aires", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Argentina/Catamarca", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Argentina/ComodRivadavia",Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Argentina/Cordoba", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Argentina/Jujuy", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Argentina/La_Rioja", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/Mendoza", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Argentina/Rio_Gallegos", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/Salta", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/San_Juan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/San_Luis", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/Tucuman", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Argentina/Ushuaia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Aruba", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Asuncion", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Atikokan", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Atka", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Bahia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Bahia_Banderas", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Barbados", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Belem", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Belize", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Blanc-Sablon", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Boa_Vista", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Bogota", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Boise", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Buenos_Aires", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Cambridge_Bay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Campo_Grande", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Cancun", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Caracas", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Catamarca", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Cayenne", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Cayman", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Chicago", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Chihuahua", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Coral_Harbour", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Cordoba", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Costa_Rica", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Creston", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Cuiaba", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Curacao", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Danmarkshavn", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Dawson", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Dawson_Creek", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Denver", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Detroit", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Dominica", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Edmonton", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Eirunepe", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/El_Salvador", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Ensenada", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Fort_Nelson", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Fort_Wayne", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Fortaleza", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Glace_Bay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Godthab", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Goose_Bay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Grand_Turk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Grenada", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Guadeloupe", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Guatemala", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Guayaquil", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Guyana", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Halifax", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Havana", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Hermosillo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Indianapolis", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Indiana/Knox", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Marengo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Petersburg", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Tell_City", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Vevay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Vincennes", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indiana/Winamac", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Indianapolis", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Inuvik", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Iqaluit", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Jamaica", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Jujuy", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Juneau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Kentucky/Louisville", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("America/Kentucky/Monticello", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Knox_IN", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Kralendijk", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/La_Paz", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Lima", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Los_Angeles", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Louisville", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Lower_Princes", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Maceio", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Managua", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Manaus", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Marigot", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Martinique", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Matamoros", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Mazatlan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Mendoza", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Menominee", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Merida", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Metlakatla", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Mexico_City", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Miquelon", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Moncton", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Monterrey", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Montevideo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Montreal", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Montserrat", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Nassau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/New_York", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Nipigon", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Nome", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Noronha", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/North_Dakota/Beulah", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/North_Dakota/Center", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/North_Dakota/New_Salem", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Nuuk", Tz_status::Time_zone, Tz_status::Absent); - validate_time_zone("America/Ojinaga", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Panama", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Pangnirtung", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Paramaribo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Phoenix", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Port-au-Prince", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Port_of_Spain", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Porto_Acre", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Porto_Velho", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Puerto_Rico", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Punta_Arenas", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Rainy_River", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Rankin_Inlet", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Recife", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Regina", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Resolute", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Rio_Branco", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Rosario", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Santa_Isabel", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Santarem", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Santiago", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Santo_Domingo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Sao_Paulo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Scoresbysund", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Shiprock", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Sitka", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/St_Barthelemy", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/St_Johns", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/St_Kitts", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/St_Lucia", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/St_Thomas", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/St_Vincent", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Swift_Current", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Tegucigalpa", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Thule", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Thunder_Bay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Tijuana", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Toronto", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Tortola", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("America/Vancouver", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Virgin", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("America/Whitehorse", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Winnipeg", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Yakutat", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("America/Yellowknife", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Casey", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Davis", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/DumontDUrville", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Macquarie", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Mawson", Tz_status::Time_zone, Tz_status::Canonical); - // vvv Tz_status::Canonical. Changed for testing vvv - validate_time_zone("Antarctica/McMurdo", Tz_status::Time_zone_link, Tz_status::Time_zone_link); - validate_time_zone("Antarctica/Palmer", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Rothera", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/South_Pole", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Antarctica/Syowa", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Troll", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Antarctica/Vostok", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Arctic/Longyearbyen", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Aden", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Almaty", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Amman", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Anadyr", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Aqtau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Aqtobe", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ashgabat", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ashkhabad", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Atyrau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Baghdad", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Bahrain", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Baku", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Bangkok", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Barnaul", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Beirut", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Bishkek", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Brunei", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Calcutta", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Chita", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Choibalsan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Chongqing", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Chungking", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Colombo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Dacca", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Damascus", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Dhaka", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Dili", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Dubai", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Dushanbe", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Famagusta", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Gaza", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Harbin", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Hebron", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ho_Chi_Minh", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Asia/Hong_Kong", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Hovd", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Irkutsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Istanbul", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Jakarta", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Jayapura", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Jerusalem", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kabul", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kamchatka", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Karachi", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kashgar", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Kathmandu", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Asia/Katmandu", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Khandyga", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kolkata", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Asia/Krasnoyarsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kuala_Lumpur", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kuching", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Kuwait", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Macao", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Macau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Magadan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Makassar", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Manila", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Muscat", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Nicosia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Novokuznetsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Novosibirsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Omsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Oral", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Phnom_Penh", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Pontianak", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Pyongyang", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Qatar", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Qostanay", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Qyzylorda", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Rangoon", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Riyadh", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Saigon", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Sakhalin", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Samarkand", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Seoul", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Shanghai", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Singapore", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Srednekolymsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Taipei", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tashkent", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tbilisi", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tehran", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tel_Aviv", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Thimbu", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Thimphu", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tokyo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Tomsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ujung_Pandang", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Ulaanbaatar", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ulan_Bator", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Asia/Urumqi", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Ust-Nera", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Vientiane", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Asia/Vladivostok", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Yakutsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Yangon", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Asia/Yekaterinburg", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Asia/Yerevan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Azores", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Bermuda", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Canary", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Cape_Verde", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Faeroe", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Atlantic/Faroe", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Atlantic/Jan_Mayen", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Atlantic/Madeira", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/Reykjavik", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/South_Georgia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Atlantic/St_Helena", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Atlantic/Stanley", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/ACT", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Adelaide", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Brisbane", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Broken_Hill", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Canberra", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Currie", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Australia/Darwin", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Eucla", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Hobart", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/LHI", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Lindeman", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Lord_Howe", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Melbourne", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/NSW", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/North", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Perth", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Queensland", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/South", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Sydney", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Australia/Tasmania", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Victoria", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/West", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Australia/Yancowinna", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("BET", Tz_status::Absent, Tz_status::Any); - validate_time_zone("BST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Brazil/Acre", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Brazil/DeNoronha", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Brazil/East", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Brazil/West", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("CAT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("CET", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("CNT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("CST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("CST6CDT", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("CTT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Canada/Atlantic", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Central", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/East-Saskatchewan", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Canada/Eastern", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Mountain", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Newfoundland", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Pacific", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Saskatchewan", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Canada/Yukon", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Chile/Continental", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Chile/EasterIsland", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Cuba", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("EAT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("ECT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("EET", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("EST", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("EST5EDT", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Egypt", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Eire", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Etc/GMT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+0", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Etc/GMT+1", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+10", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+11", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+12", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+2", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+3", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+4", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+5", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+6", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+7", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+8", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT+9", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-0", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Etc/GMT-1", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-10", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-11", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-12", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-13", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-14", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-2", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-3", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-4", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-5", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-6", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-7", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-8", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT-9", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/GMT0", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Etc/Greenwich", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Etc/UCT", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Etc/UTC", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Etc/Universal", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Etc/Zulu", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Europe/Amsterdam", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Andorra", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Astrakhan", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Athens", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Belfast", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Europe/Belgrade", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Berlin", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Bratislava", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Brussels", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Bucharest", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Budapest", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Busingen", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Chisinau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Copenhagen", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Dublin", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Gibraltar", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Guernsey", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Helsinki", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Isle_of_Man", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Istanbul", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Jersey", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Kaliningrad", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Kiev", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Kirov", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Lisbon", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Ljubljana", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/London", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Luxembourg", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Madrid", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Malta", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Mariehamn", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Minsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Monaco", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Moscow", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Nicosia", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Europe/Oslo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Paris", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Podgorica", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Prague", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Riga", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Rome", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Samara", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/San_Marino", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Sarajevo", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Saratov", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Simferopol", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Skopje", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Sofia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Stockholm", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Tallinn", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Tirane", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Tiraspol", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Europe/Ulyanovsk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Uzhgorod", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Vaduz", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Vatican", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Vienna", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Vilnius", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Volgograd", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Warsaw", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Zagreb", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Europe/Zaporozhye", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Europe/Zurich", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Factory", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("GB", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("GB-Eire", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("GMT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("GMT+0", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("GMT-0", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("GMT0", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Greenwich", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("HST", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Hongkong", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("IET", Tz_status::Absent, Tz_status::Any); - validate_time_zone("IST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Iceland", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Indian/Antananarivo", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Indian/Chagos", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Christmas", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Cocos", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Comoro", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Indian/Kerguelen", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Mahe", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Maldives", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Mauritius", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Indian/Mayotte", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Indian/Reunion", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Iran", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Israel", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("JST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Jamaica", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Japan", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Kwajalein", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Libya", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("MET", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("MIT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("MST", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("MST7MDT", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Mexico/BajaNorte", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Mexico/BajaSur", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Mexico/General", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("NET", Tz_status::Absent, Tz_status::Any); - validate_time_zone("NST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("NZ", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("NZ-CHAT", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Navajo", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("PLT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("PNT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("PRC", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("PRT", Tz_status::Absent, Tz_status::Any); - validate_time_zone("PST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("PST8PDT", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Apia", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Auckland", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Bougainville", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Chatham", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Chuuk", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Pacific/Easter", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Efate", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Enderbury", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Fakaofo", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Fiji", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Funafuti", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Galapagos", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Gambier", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Guadalcanal", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Guam", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Honolulu", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Johnston", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Pacific/Kiritimati", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Kosrae", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Kwajalein", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Majuro", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Marquesas", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Midway", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Pacific/Nauru", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Niue", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Norfolk", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Noumea", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Pago_Pago", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Palau", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Pitcairn", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Pohnpei", Tz_status::Time_zone, Tz_status::Any); - validate_time_zone("Pacific/Ponape", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Pacific/Port_Moresby", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Rarotonga", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Saipan", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Pacific/Samoa", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Pacific/Tahiti", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Tarawa", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Tongatapu", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Truk", Tz_status::Time_zone_link, Tz_status::Canonical); - validate_time_zone("Pacific/Wake", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Wallis", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Pacific/Yap", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Poland", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Portugal", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("ROC", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("ROK", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("SST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("Singapore", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("SystemV/AST4", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/AST4ADT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/CST6", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/CST6CDT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/EST5", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/EST5EDT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/HST10", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/MST7", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/MST7MDT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/PST8", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/PST8PDT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/YST9", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("SystemV/YST9YDT", Tz_status::Absent, Tz_status::Canonical); - validate_time_zone("Turkey", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("UCT", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Alaska", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Aleutian", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Arizona", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Central", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/East-Indiana", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Eastern", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Hawaii", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Indiana-Starke", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Michigan", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Mountain", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Pacific", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("US/Pacific-New", Tz_status::Absent, Tz_status::Any); - validate_time_zone("US/Samoa", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("UTC", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("Universal", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("VST", Tz_status::Absent, Tz_status::Any); - validate_time_zone("W-SU", Tz_status::Time_zone_link, Tz_status::Any); - validate_time_zone("WET", Tz_status::Time_zone, Tz_status::Canonical); - validate_time_zone("Zulu", Tz_status::Time_zone_link, Tz_status::Any); - // clang-format on + // these are some example in which the ICU.dll and IANA database diverge in what they consider a zone or a link + assert(_Locate_zone_impl(tzdb.links, "Atlantic/Faroe") != nullptr); // is a time_zone in IANA + assert(_Locate_zone_impl(tzdb.time_zones, "Africa/Addis_Ababa") != nullptr); // is a time_zone_link in IANA + assert(_Locate_zone_impl(tzdb.links, "PST") != nullptr); // time_zone_link does not exist in IANA + assert(_Locate_zone_impl(tzdb.links, "Africa/Asmara") != nullptr); // matches IANA but target is wrong + assert(_Locate_zone_impl(tzdb.links, "Africa/Asmara")->target() == "Africa/Asmera"); // target == Africa/Nairobi + assert(_Locate_zone_impl(tzdb.time_zones, "America/Nuuk") == nullptr); // does not exist in ICU (very rare) } bool test() { - timezone_names_test(); - all_timezone_names(); + try { + timezone_names_test(); + } catch (exception& ex) { + std::cout << "Test threw exception: " << ex.what() << "\n"; + assert(false); + } return true; } From 8a01d01c2ee9dfc4e116ac3129b0747e5c6c9b8c Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Tue, 9 Mar 2021 19:32:01 -0800 Subject: [PATCH 05/15] 121 chars in test script hacks :( --- azure-devops/run-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml index ad4a79e3b1a..bcd81c0b33e 100644 --- a/azure-devops/run-tests.yml +++ b/azure-devops/run-tests.yml @@ -27,7 +27,8 @@ steps: script: | call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo - python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std --filter P0355R7_calendars_and_time_zones_time_zones:00 -v + python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std --filter + P0355R7_calendars_and_time_zones_time_zones:00 -v env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: PublishTestResults@2 displayName: 'Publish Tests' From 20b141f222dc1609935e694fdd719b18b90b5774 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Tue, 9 Mar 2021 19:38:32 -0800 Subject: [PATCH 06/15] Try again with tests --- azure-devops/run-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml index bcd81c0b33e..2ed9450b83b 100644 --- a/azure-devops/run-tests.yml +++ b/azure-devops/run-tests.yml @@ -27,8 +27,7 @@ steps: script: | call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo - python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std --filter - P0355R7_calendars_and_time_zones_time_zones:00 -v + python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std -v --filter time_zones_time_zones:00 env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: PublishTestResults@2 displayName: 'Publish Tests' From e2b4163a49bf4ed41802dd569f8c734e5a28d7b8 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Tue, 9 Mar 2021 20:08:37 -0800 Subject: [PATCH 07/15] Test should run now --- azure-devops/run-tests.yml | 2 +- azure-pipelines.yml | 142 ++++++++++++++++++------------------- tests/CMakeLists.txt | 4 +- 3 files changed, 75 insertions(+), 73 deletions(-) diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml index 2ed9450b83b..a247bfc43c4 100644 --- a/azure-devops/run-tests.yml +++ b/azure-devops/run-tests.yml @@ -27,7 +27,7 @@ steps: script: | call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo - python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std -v --filter time_zones_time_zones:00 + ctest -V env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: PublishTestResults@2 displayName: 'Publish Tests' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8e8832a925f..25c42f397c9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,53 +11,53 @@ variables: pool: 'StlBuild-2021-03-02' stages: - - stage: Code_Format - displayName: 'Code Format' - jobs: - - job: Code_Format_Validation - timeoutInMinutes: 90 - displayName: 'Validation' - variables: - buildOutputLocation: 'D:\tools' - steps: - - script: | - if exist "$(tmpDir)" ( - rmdir /S /Q $(tmpDir) - ) - mkdir $(tmpDir) - displayName: 'Setup TMP Directory' - - checkout: self - clean: true - submodules: false - - script: | - if exist "$(buildOutputLocation)" ( - rmdir /S /Q "$(buildOutputLocation)" - ) - call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=amd64 -arch=amd64 -no_logo - cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ - -S $(Build.SourcesDirectory)\tools -B $(buildOutputLocation) - cmake --build $(buildOutputLocation) - displayName: 'Build Support Tools' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: BatchScript@1 - displayName: 'Enforce clang-format' - timeoutInMinutes: 60 - condition: succeededOrFailed() - inputs: - filename: 'azure-devops/enforce-clang-format.cmd' - failOnStandardError: true - arguments: '$(buildOutputLocation)/parallelize/parallelize.exe' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: BatchScript@1 - displayName: 'Validate Files' - timeoutInMinutes: 2 - condition: succeededOrFailed() - inputs: - filename: 'azure-devops/validate-files.cmd' - failOnStandardError: true - arguments: '$(buildOutputLocation)/validate/validate.exe' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + # - stage: Code_Format + # displayName: 'Code Format' + # jobs: + # - job: Code_Format_Validation + # timeoutInMinutes: 90 + # displayName: 'Validation' + # variables: + # buildOutputLocation: 'D:\tools' + # steps: + # - script: | + # if exist "$(tmpDir)" ( + # rmdir /S /Q $(tmpDir) + # ) + # mkdir $(tmpDir) + # displayName: 'Setup TMP Directory' + # - checkout: self + # clean: true + # submodules: false + # - script: | + # if exist "$(buildOutputLocation)" ( + # rmdir /S /Q "$(buildOutputLocation)" + # ) + # call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ + # -host_arch=amd64 -arch=amd64 -no_logo + # cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ + # -S $(Build.SourcesDirectory)\tools -B $(buildOutputLocation) + # cmake --build $(buildOutputLocation) + # displayName: 'Build Support Tools' + # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + # - task: BatchScript@1 + # displayName: 'Enforce clang-format' + # timeoutInMinutes: 60 + # condition: succeededOrFailed() + # inputs: + # filename: 'azure-devops/enforce-clang-format.cmd' + # failOnStandardError: true + # arguments: '$(buildOutputLocation)/parallelize/parallelize.exe' + # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + # - task: BatchScript@1 + # displayName: 'Validate Files' + # timeoutInMinutes: 2 + # condition: succeededOrFailed() + # inputs: + # filename: 'azure-devops/validate-files.cmd' + # failOnStandardError: true + # arguments: '$(buildOutputLocation)/validate/validate.exe' + # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - stage: Build_And_Test_x86 dependsOn: Code_Format @@ -68,29 +68,29 @@ stages: targetPlatform: x86 vsDevCmdArch: x86 - - stage: Build_And_Test_x64 - dependsOn: Build_And_Test_x86 - displayName: 'Build and Test' - jobs: - - template: azure-devops/native-build-test.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 + # - stage: Build_And_Test_x64 + # dependsOn: Build_And_Test_x86 + # displayName: 'Build and Test' + # jobs: + # - template: azure-devops/native-build-test.yml + # parameters: + # targetPlatform: x64 + # vsDevCmdArch: amd64 - - stage: Build_ARM - dependsOn: Build_And_Test_x86 - displayName: 'Build' - jobs: - - template: azure-devops/cross-build.yml - parameters: - targetPlatform: arm - vsDevCmdArch: arm + # - stage: Build_ARM + # dependsOn: Build_And_Test_x86 + # displayName: 'Build' + # jobs: + # - template: azure-devops/cross-build.yml + # parameters: + # targetPlatform: arm + # vsDevCmdArch: arm - - stage: Build_ARM64 - dependsOn: Build_And_Test_x86 - displayName: 'Build' - jobs: - - template: azure-devops/cross-build.yml - parameters: - targetPlatform: arm64 - vsDevCmdArch: arm64 + # - stage: Build_ARM64 + # dependsOn: Build_And_Test_x86 + # displayName: 'Build' + # jobs: + # - template: azure-devops/cross-build.yml + # parameters: + # targetPlatform: arm64 + # vsDevCmdArch: arm64 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 76a64ab60d2..d3119723b45 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,6 +31,8 @@ endif() get_property(STL_LIT_TEST_DIRS GLOBAL PROPERTY STL_LIT_TEST_DIRS) list(APPEND STL_LIT_COMMAND "${STL_LIT_OUTPUT}" "${LIT_FLAGS}" - "${STL_LIT_TEST_DIRS}") + "${STL_LIT_TEST_DIRS}" + "--filter" + "P0355R7_calendars_and_time_zones_time_zones:00") add_test(NAME stl COMMAND ${Python_EXECUTABLE} ${STL_LIT_COMMAND} COMMAND_EXPAND_LISTS) From 90e692a72ff70bebfcbf3c0e8de92f0233bc00de Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Wed, 10 Mar 2021 11:36:35 -0800 Subject: [PATCH 08/15] I think my previous changes got flagged? --- azure-devops/cross-build.yml | 2 +- azure-pipelines.yml | 142 +++++++++++++++++------------------ 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/azure-devops/cross-build.yml b/azure-devops/cross-build.yml index 6cbcb08adb6..b9ee34adcca 100644 --- a/azure-devops/cross-build.yml +++ b/azure-devops/cross-build.yml @@ -14,7 +14,7 @@ parameters: default: buildOutputLocation - name: numShards type: number - default: 8 + default: 1 jobs: - job: '${{ parameters.targetPlatform }}' variables: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 25c42f397c9..8e8832a925f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,53 +11,53 @@ variables: pool: 'StlBuild-2021-03-02' stages: - # - stage: Code_Format - # displayName: 'Code Format' - # jobs: - # - job: Code_Format_Validation - # timeoutInMinutes: 90 - # displayName: 'Validation' - # variables: - # buildOutputLocation: 'D:\tools' - # steps: - # - script: | - # if exist "$(tmpDir)" ( - # rmdir /S /Q $(tmpDir) - # ) - # mkdir $(tmpDir) - # displayName: 'Setup TMP Directory' - # - checkout: self - # clean: true - # submodules: false - # - script: | - # if exist "$(buildOutputLocation)" ( - # rmdir /S /Q "$(buildOutputLocation)" - # ) - # call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - # -host_arch=amd64 -arch=amd64 -no_logo - # cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ - # -S $(Build.SourcesDirectory)\tools -B $(buildOutputLocation) - # cmake --build $(buildOutputLocation) - # displayName: 'Build Support Tools' - # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - # - task: BatchScript@1 - # displayName: 'Enforce clang-format' - # timeoutInMinutes: 60 - # condition: succeededOrFailed() - # inputs: - # filename: 'azure-devops/enforce-clang-format.cmd' - # failOnStandardError: true - # arguments: '$(buildOutputLocation)/parallelize/parallelize.exe' - # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - # - task: BatchScript@1 - # displayName: 'Validate Files' - # timeoutInMinutes: 2 - # condition: succeededOrFailed() - # inputs: - # filename: 'azure-devops/validate-files.cmd' - # failOnStandardError: true - # arguments: '$(buildOutputLocation)/validate/validate.exe' - # env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - stage: Code_Format + displayName: 'Code Format' + jobs: + - job: Code_Format_Validation + timeoutInMinutes: 90 + displayName: 'Validation' + variables: + buildOutputLocation: 'D:\tools' + steps: + - script: | + if exist "$(tmpDir)" ( + rmdir /S /Q $(tmpDir) + ) + mkdir $(tmpDir) + displayName: 'Setup TMP Directory' + - checkout: self + clean: true + submodules: false + - script: | + if exist "$(buildOutputLocation)" ( + rmdir /S /Q "$(buildOutputLocation)" + ) + call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ + -host_arch=amd64 -arch=amd64 -no_logo + cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ + -S $(Build.SourcesDirectory)\tools -B $(buildOutputLocation) + cmake --build $(buildOutputLocation) + displayName: 'Build Support Tools' + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - task: BatchScript@1 + displayName: 'Enforce clang-format' + timeoutInMinutes: 60 + condition: succeededOrFailed() + inputs: + filename: 'azure-devops/enforce-clang-format.cmd' + failOnStandardError: true + arguments: '$(buildOutputLocation)/parallelize/parallelize.exe' + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - task: BatchScript@1 + displayName: 'Validate Files' + timeoutInMinutes: 2 + condition: succeededOrFailed() + inputs: + filename: 'azure-devops/validate-files.cmd' + failOnStandardError: true + arguments: '$(buildOutputLocation)/validate/validate.exe' + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - stage: Build_And_Test_x86 dependsOn: Code_Format @@ -68,29 +68,29 @@ stages: targetPlatform: x86 vsDevCmdArch: x86 - # - stage: Build_And_Test_x64 - # dependsOn: Build_And_Test_x86 - # displayName: 'Build and Test' - # jobs: - # - template: azure-devops/native-build-test.yml - # parameters: - # targetPlatform: x64 - # vsDevCmdArch: amd64 + - stage: Build_And_Test_x64 + dependsOn: Build_And_Test_x86 + displayName: 'Build and Test' + jobs: + - template: azure-devops/native-build-test.yml + parameters: + targetPlatform: x64 + vsDevCmdArch: amd64 - # - stage: Build_ARM - # dependsOn: Build_And_Test_x86 - # displayName: 'Build' - # jobs: - # - template: azure-devops/cross-build.yml - # parameters: - # targetPlatform: arm - # vsDevCmdArch: arm + - stage: Build_ARM + dependsOn: Build_And_Test_x86 + displayName: 'Build' + jobs: + - template: azure-devops/cross-build.yml + parameters: + targetPlatform: arm + vsDevCmdArch: arm - # - stage: Build_ARM64 - # dependsOn: Build_And_Test_x86 - # displayName: 'Build' - # jobs: - # - template: azure-devops/cross-build.yml - # parameters: - # targetPlatform: arm64 - # vsDevCmdArch: arm64 + - stage: Build_ARM64 + dependsOn: Build_And_Test_x86 + displayName: 'Build' + jobs: + - template: azure-devops/cross-build.yml + parameters: + targetPlatform: arm64 + vsDevCmdArch: arm64 From d123f58c2d376d5ae9ffc9049699a629740f2322 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Wed, 10 Mar 2021 11:49:52 -0800 Subject: [PATCH 09/15] Trying to get output from tests. --- tests/CMakeLists.txt | 1 + .../tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d3119723b45..134781c8e3b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,7 @@ get_property(STL_LIT_TEST_DIRS GLOBAL PROPERTY STL_LIT_TEST_DIRS) list(APPEND STL_LIT_COMMAND "${STL_LIT_OUTPUT}" "${LIT_FLAGS}" "${STL_LIT_TEST_DIRS}" + "-v" "--filter" "P0355R7_calendars_and_time_zones_time_zones:00") diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp index 4a5a74e061a..3c3fef7799a 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp @@ -85,7 +85,7 @@ bool test() { try { timezone_names_test(); } catch (exception& ex) { - std::cout << "Test threw exception: " << ex.what() << "\n"; + std::cerr << "Test threw exception: " << ex.what() << "\n"; assert(false); } From 812abb7a15ced29f20b85a5d76eb16fda9fec607 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 9 Mar 2021 20:32:46 -0800 Subject: [PATCH 10/15] Win10 20H2 VMSS. --- azure-devops/create-vmss.ps1 | 12 +++++++----- azure-pipelines.yml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/azure-devops/create-vmss.ps1 b/azure-devops/create-vmss.ps1 index 64fa971fdc8..a927b1cc164 100644 --- a/azure-devops/create-vmss.ps1 +++ b/azure-devops/create-vmss.ps1 @@ -25,7 +25,9 @@ $Prefix = 'StlBuild-' + (Get-Date -Format 'yyyy-MM-dd') $VMSize = 'Standard_D32ds_v4' $ProtoVMName = 'PROTOTYPE' $LiveVMPrefix = 'BUILD' -$WindowsServerSku = '2019-Datacenter' +$ImagePublisher = 'MicrosoftWindowsDesktop' +$ImageOffer = 'Windows-10' +$ImageSku = '20h2-ent-g2' $ProgressActivity = 'Creating Scale Set' $TotalProgress = 12 @@ -268,9 +270,9 @@ $VM = Set-AzVMOperatingSystem ` $VM = Add-AzVMNetworkInterface -VM $VM -Id $Nic.Id $VM = Set-AzVMSourceImage ` -VM $VM ` - -PublisherName 'MicrosoftWindowsServer' ` - -Offer 'WindowsServer' ` - -Skus $WindowsServerSku ` + -PublisherName $ImagePublisher ` + -Offer $ImageOffer ` + -Skus $ImageSku ` -Version latest $VM = Set-AzVMBootDiagnostic -VM $VM -Disable @@ -340,7 +342,7 @@ Set-AzVM ` $VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $ProtoVMName $PrototypeOSDiskName = $VM.StorageProfile.OsDisk.Name -$ImageConfig = New-AzImageConfig -Location $Location -SourceVirtualMachineId $VM.ID +$ImageConfig = New-AzImageConfig -Location $Location -SourceVirtualMachineId $VM.ID -HyperVGeneration 'V2' $Image = New-AzImage -Image $ImageConfig -ImageName $ProtoVMName -ResourceGroupName $ResourceGroupName #################################################################################################### diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8e8832a925f..9c0fa71b56e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,7 +8,7 @@ variables: buildOutputLocation: 'D:\build' vcpkgLocation: '$(Build.SourcesDirectory)/vcpkg' -pool: 'StlBuild-2021-03-02' +pool: 'StlBuild-2021-03-09-win10' stages: - stage: Code_Format From 9086249f60927e4e1fe9b867f605a4d755734517 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Wed, 10 Mar 2021 13:41:53 -0800 Subject: [PATCH 11/15] Reverted CI test hacks --- azure-devops/cross-build.yml | 2 +- azure-devops/native-build-test.yml | 2 +- tests/CMakeLists.txt | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/azure-devops/cross-build.yml b/azure-devops/cross-build.yml index b9ee34adcca..6cbcb08adb6 100644 --- a/azure-devops/cross-build.yml +++ b/azure-devops/cross-build.yml @@ -14,7 +14,7 @@ parameters: default: buildOutputLocation - name: numShards type: number - default: 1 + default: 8 jobs: - job: '${{ parameters.targetPlatform }}' variables: diff --git a/azure-devops/native-build-test.yml b/azure-devops/native-build-test.yml index e3cf652dc46..17fa03732ae 100644 --- a/azure-devops/native-build-test.yml +++ b/azure-devops/native-build-test.yml @@ -11,7 +11,7 @@ parameters: default: buildOutputLocation - name: numShards type: number - default: 1 + default: 8 jobs: - job: '${{ parameters.targetPlatform }}' variables: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 134781c8e3b..76a64ab60d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,9 +31,6 @@ endif() get_property(STL_LIT_TEST_DIRS GLOBAL PROPERTY STL_LIT_TEST_DIRS) list(APPEND STL_LIT_COMMAND "${STL_LIT_OUTPUT}" "${LIT_FLAGS}" - "${STL_LIT_TEST_DIRS}" - "-v" - "--filter" - "P0355R7_calendars_and_time_zones_time_zones:00") + "${STL_LIT_TEST_DIRS}") add_test(NAME stl COMMAND ${Python_EXECUTABLE} ${STL_LIT_COMMAND} COMMAND_EXPAND_LISTS) From d246223bae8b341cfa0a5c61de971a679a09da93 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Wed, 10 Mar 2021 22:56:29 -0800 Subject: [PATCH 12/15] Feedback and error handling. --- stl/src/tzdb.cpp | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index 1e06868475c..7457d0cff64 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -43,8 +43,6 @@ namespace { } } - // FIXME: Inspired from what I found in atomic.cpp. Is this overkill, I wasn't sure what to do - // with race conditions and static state. I didn't want to LoadLibraryExW twice. _NODISCARD _Icu_api_level _Init_icu_functions(_Icu_api_level _Level) noexcept { while (!_Icu_functions._Api_level.compare_exchange_weak(_Level, _Icu_api_level::_Detecting)) { if (_Level > _Icu_api_level::_Detecting) { @@ -57,7 +55,7 @@ namespace { const HMODULE _Icu_module = LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if (_Icu_module != nullptr) { // collect at least one error if any GetProcAddress call fails - DWORD _Last_error{0}; + DWORD _Last_error{ERROR_SUCCESS}; _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_getCanonicalTimeZoneID, "ucal_getCanonicalTimeZoneID", _Last_error); _Load_address( @@ -70,7 +68,7 @@ namespace { if (_Last_error == ERROR_SUCCESS) { _Level = _Icu_api_level::_Has_icu_addresses; } else { - // reset last-error in-case a later GetProcAddress resets it + // reset last error code for thread in-case a later GetProcAddress resets it SetLastError(_Last_error); } } @@ -124,7 +122,6 @@ namespace { const char16_t* _Input, int _Input_len, __std_tzdb_error& _Err) noexcept { const auto _Code_page = __std_fs_code_page(); const auto _Input_as_wchar = reinterpret_cast(_Input); - // FIXME: Is is ok to pull in xfilesystem_abi.h and use these here? const auto _Count_result = __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, nullptr, 0); if (_Count_result._Err != __std_win_error::_Success) { _Err = __std_tzdb_error::_Win_error; @@ -148,13 +145,25 @@ namespace { return _Data.release(); } + template + _NODISCARD constexpr _Ty* _Report_error(_STD unique_ptr<_Ty, _Dtor>& _Info, __std_tzdb_error _Err) { + _Info->_Err = _Err; + return _Info.release(); + } + + template + _NODISCARD constexpr _Ty* _Propagate_error(_STD unique_ptr<_Ty, _Dtor>& _Info) { + // a bad_alloc() returns nullptr and does not set __std_tzdb_error + return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + } + } // namespace _EXTERN_C _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept { // On exit--- - // *_Info == nullptr --> bad_alloc() + // _Info == nullptr --> bad_alloc() // _Info->_Err == _Win_error --> failed, call GetLastError() // _Info->_Err == _Icu_error --> runtime_error interacting with ICU _STD unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{ @@ -164,8 +173,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe } if (_Acquire_icu_functions() < _Icu_api_level::_Has_icu_addresses) { - _Info->_Err = __std_tzdb_error::_Win_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Win_error); } UErrorCode _UErr{}; @@ -173,15 +181,13 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe __icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_ANY, nullptr, nullptr, &_UErr), &__icu_uenum_close}; if (U_FAILURE(_UErr)) { - _Info->_Err = __std_tzdb_error::_Icu_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Icu_error); } - // uenum_count may be expensive but is required to pre allocated arrays. + // uenum_count may be expensive but is required to pre-allocate arrays. int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_UErr); if (U_FAILURE(_UErr)) { - _Info->_Err = __std_tzdb_error::_Icu_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Icu_error); } _Info->_Num_time_zones = static_cast(_Num_time_zones); @@ -190,7 +196,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return nullptr; } - // init to ensure __std_tzdb_delete_init_info cleanup is valid + // init to ensure __std_tzdb_delete_time_zones() cleanup is valid _STD fill_n(_Info->_Names, static_cast(_Info->_Num_time_zones), nullptr); _Info->_Links = new (_STD nothrow) const char*[_Info->_Num_time_zones]; @@ -198,37 +204,34 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return nullptr; } - // init to ensure __std_tzdb_delete_init_info cleanup is valid + // init to ensure __std_tzdb_delete_time_zones() cleanup is valid _STD fill_n(_Info->_Links, static_cast(_Info->_Num_time_zones), nullptr); for (size_t _Name_idx = 0; _Name_idx < _Info->_Num_time_zones; ++_Name_idx) { int32_t _Elem_len{}; const auto* _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_UErr); if (U_FAILURE(_UErr) || _Elem == nullptr) { - _Info->_Err = __std_tzdb_error::_Icu_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Icu_error); } _Info->_Names[_Name_idx] = _Allocate_wide_to_narrow(_Elem, _Elem_len, _Info->_Err); if (_Info->_Names[_Name_idx] == nullptr) { - return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + return _Propagate_error(_Info); } UBool _Is_system{}; - // FIXME: what is the right size here and is it ok to stack allocate. char16_t _Link_buf[256]; const auto _Link_buf_len = __icu_ucal_getCanonicalTimeZoneID(_Elem, _Elem_len, _Link_buf, sizeof(_Link_buf), &_Is_system, &_UErr); if (U_FAILURE(_UErr) || _Link_buf_len == 0) { - _Info->_Err = __std_tzdb_error::_Icu_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Icu_error); } if (_STD u16string_view{_Elem, static_cast(_Elem_len)} != _STD u16string_view{_Link_buf, static_cast(_Link_buf_len)}) { _Info->_Links[_Name_idx] = _Allocate_wide_to_narrow(_Link_buf, _Link_buf_len, _Info->_Err); if (_Info->_Links[_Name_idx] == nullptr) { - return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + return _Propagate_error(_Info); } } } @@ -260,7 +263,7 @@ void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) n _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept { // On exit--- - // *_Info == nullptr --> bad_alloc() + // _Info == nullptr --> bad_alloc() // _Info->_Err == _Win_error --> failed, call GetLastError() // _Info->_Err == _Icu_error --> runtime_error interacting with ICU _STD unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{ @@ -270,21 +273,19 @@ _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() } if (_Acquire_icu_functions() < _Icu_api_level::_Has_icu_addresses) { - _Info->_Err = __std_tzdb_error::_Win_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Win_error); } UErrorCode _Err{}; char16_t _Id_buf[256]; const auto _Id_buf_len = __icu_ucal_getDefaultTimeZone(_Id_buf, sizeof(_Id_buf), &_Err); if (U_FAILURE(_Err) || _Id_buf_len == 0) { - _Info->_Err = __std_tzdb_error::_Icu_error; - return _Info.release(); + return _Report_error(_Info, __std_tzdb_error::_Icu_error); } _Info->_Tz_name = _Allocate_wide_to_narrow(_Id_buf, static_cast(_Id_buf_len), _Info->_Err); if (_Info->_Tz_name == nullptr) { - return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + return _Propagate_error(_Info); } return _Info.release(); From b6b045598e891b29d5b73d1068c6bc6b3e9aa8e6 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Thu, 11 Mar 2021 15:58:32 -0800 Subject: [PATCH 13/15] Version, error handling and feedback --- stl/inc/chrono | 35 ++++++----- stl/inc/xtzdb.h | 2 + stl/src/tzdb.cpp | 60 ++++++++++++++++--- .../test.cpp | 6 +- .../test.cpp | 26 +++++--- 5 files changed, 95 insertions(+), 34 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index c1bfe875fdb..d62210e67ac 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -2217,7 +2217,7 @@ namespace chrono { // [time.zone.timezone] - // TRANSITION: work in progress + // CLASS time_zone class time_zone { public: explicit time_zone(string_view _Name_) : _Name(_Name_) {} @@ -2339,6 +2339,7 @@ namespace chrono { // [time.zone.link] + // CLASS time_zone_link class time_zone_link { public: explicit time_zone_link(string_view _Name_, string_view _Target_) : _Name(_Name_), _Target(_Target_) {} @@ -2388,24 +2389,30 @@ namespace chrono { template _NODISCARD const _Ty* _Locate_zone_impl(const vector<_Ty>& _Vec, string_view _Name) { const auto _Result = _STD find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; }); - return _Result != _Vec.end() ? &*_Result : nullptr; + return _Result == _Vec.end() ? nullptr : &*_Result; } + // STRUCT tzdb struct tzdb { - vector time_zones; + string version; + vector zones; vector links; vector leap_seconds; bool _All_ls_positive; _NODISCARD const time_zone* locate_zone(string_view _Tz_name) const { - auto _Tz = _Locate_zone_impl(time_zones, _Tz_name); + auto _Tz = _Locate_zone_impl(zones, _Tz_name); if (_Tz == nullptr) { const auto _Link = _Locate_zone_impl(links, _Tz_name); if (_Link != nullptr) { - _Tz = _Locate_zone_impl(time_zones, _Link->target()); + _Tz = _Locate_zone_impl(zones, _Link->target()); } } + if (_Tz == nullptr) { + _Xruntime_error("unable to locate time_zone with given name"); + } + return _Tz; } @@ -2414,7 +2421,7 @@ namespace chrono { } }; - _NODISCARD inline pair _Xtzdb_generate_time_zones() { + _NODISCARD inline tuple _Xtzdb_generate_time_zones() { unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{ __std_tzdb_get_time_zones(), &__std_tzdb_delete_time_zones}; if (_Info == nullptr) { @@ -2425,7 +2432,7 @@ namespace chrono { _Xruntime_error("Internal error loading IANA database information"); } - decltype(tzdb::time_zones) _Time_zones; + decltype(tzdb::zones) _Time_zones; decltype(tzdb::links) _Time_zone_links; for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { const string_view _Name{_Info->_Names[_Idx]}; @@ -2437,7 +2444,7 @@ namespace chrono { } } - return {_STD move(_Time_zones), _STD move(_Time_zone_links)}; + return {_Info->_Version, _STD move(_Time_zones), _STD move(_Time_zone_links)}; } _NODISCARD inline pair _Xtzdb_generate_leap_seconds( @@ -2529,10 +2536,10 @@ namespace chrono { tzdb_list& operator=(const tzdb_list&) = delete; tzdb_list() { - auto [_Time_zones, _Links] = _Xtzdb_generate_time_zones(); + auto [_Version, _Zones, _Links] = _Xtzdb_generate_time_zones(); auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(0); - _Tzdb_list.emplace_front( - tzdb{_STD move(_Time_zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); + _Tzdb_list.emplace_front(tzdb{ + _STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } _NODISCARD const tzdb& front() const noexcept { @@ -2551,8 +2558,8 @@ namespace chrono { auto [_Leap_sec, _All_ls_positive] = _Xtzdb_generate_leap_seconds(_Tzdb_list.front().leap_seconds.size()); if (!_Leap_sec.empty()) { const auto& _Tzdb = _Tzdb_list.front(); - vector _Time_zones; - _STD transform(_Tzdb.time_zones.begin(), _Tzdb.time_zones.end(), _STD back_inserter(_Time_zones), + vector _Zones; + _STD transform(_Tzdb.zones.begin(), _Tzdb.zones.end(), _STD back_inserter(_Zones), [](const auto& _Tz) { return time_zone{_Tz.name()}; }); vector _Links; _STD transform( @@ -2560,7 +2567,7 @@ namespace chrono { return time_zone_link{_Link.name(), _Link.target()}; }); _Tzdb_list.emplace_front( - tzdb{_STD move(_Time_zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); + tzdb{_Tzdb.version, _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } return _Tzdb_list.front(); } diff --git a/stl/inc/xtzdb.h b/stl/inc/xtzdb.h index b623337059a..03cb8b831d6 100644 --- a/stl/inc/xtzdb.h +++ b/stl/inc/xtzdb.h @@ -37,6 +37,8 @@ enum class __std_tzdb_error { struct __std_tzdb_time_zones_info { __std_tzdb_error _Err; + // timezone data version currently being used + const char* _Version; size_t _Num_time_zones; // ordered list of null-terminated time_zone/time_zone_link names const char** _Names; diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index 7457d0cff64..a5a15845fb6 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -24,6 +24,7 @@ namespace { struct _Icu_functions_table { _STD atomic _Pfn_ucal_getCanonicalTimeZoneID{nullptr}; _STD atomic _Pfn_ucal_getDefaultTimeZone{nullptr}; + _STD atomic _Pfn_ucal_getTZDataVersion{nullptr}; _STD atomic _Pfn_ucal_openTimeZoneIDEnumeration{nullptr}; _STD atomic _Pfn_uenum_close{nullptr}; _STD atomic _Pfn_uenum_count{nullptr}; @@ -62,6 +63,7 @@ namespace { _Icu_module, _Icu_functions._Pfn_ucal_getDefaultTimeZone, "ucal_getDefaultTimeZone", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_openTimeZoneIDEnumeration, "ucal_openTimeZoneIDEnumeration", _Last_error); + _Load_address(_Icu_module, _Icu_functions._Pfn_ucal_getTZDataVersion, "ucal_getTZDataVersion", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_close, "uenum_close", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_count, "uenum_count", _Last_error); _Load_address(_Icu_module, _Icu_functions._Pfn_uenum_unext, "uenum_unext", _Last_error); @@ -103,6 +105,11 @@ namespace { return _Fun(zoneType, region, rawOffset, ec); } + _NODISCARD const char* __icu_ucal_getTZDataVersion(UErrorCode* status) { + const auto _Fun = _Icu_functions._Pfn_ucal_getTZDataVersion.load(_STD memory_order_relaxed); + return _Fun(status); + } + _NODISCARD void __icu_uenum_close(UEnumeration* en) { const auto _Fun = _Icu_functions._Pfn_uenum_close.load(_STD memory_order_relaxed); return _Fun(en); @@ -145,6 +152,38 @@ namespace { return _Data.release(); } + _NODISCARD _STD unique_ptr _Get_canonical_id( + const char16_t* _Id, int32_t _Len, int32_t& _Result_len, __std_tzdb_error& _Err) { + static constexpr int32_t _Link_buf_len = 32; + _STD unique_ptr _Link_buf{new (_STD nothrow) char16_t[_Link_buf_len]}; + if (_Link_buf == nullptr) { + return nullptr; + } + + UErrorCode _UErr{U_ZERO_ERROR}; + UBool _Is_system{}; + _Result_len = __icu_ucal_getCanonicalTimeZoneID(_Id, _Len, _Link_buf.get(), _Link_buf_len, &_Is_system, &_UErr); + if (_UErr == U_BUFFER_OVERFLOW_ERROR && _Result_len > 0) { + _Link_buf.reset(new (_STD nothrow) char16_t[_Result_len + 1]); + if (_Link_buf == nullptr) { + return nullptr; + } + + _UErr = U_ZERO_ERROR; // reset error. + _Result_len = + __icu_ucal_getCanonicalTimeZoneID(_Id, _Len, _Link_buf.get(), _Result_len, &_Is_system, &_UErr); + if (U_FAILURE(_UErr)) { + _Err = __std_tzdb_error::_Icu_error; + return nullptr; + } + } else if (U_FAILURE(_UErr) || _Result_len <= 0) { + _Err = __std_tzdb_error::_Icu_error; + return nullptr; + } + + return _Link_buf; + } + template _NODISCARD constexpr _Ty* _Report_error(_STD unique_ptr<_Ty, _Dtor>& _Info, __std_tzdb_error _Err) { _Info->_Err = _Err; @@ -176,7 +215,12 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return _Report_error(_Info, __std_tzdb_error::_Win_error); } - UErrorCode _UErr{}; + UErrorCode _UErr{U_ZERO_ERROR}; + _Info->_Version = __icu_ucal_getTZDataVersion(&_UErr); + if (U_FAILURE(_UErr)) { + return _Report_error(_Info, __std_tzdb_error::_Icu_error); + } + _STD unique_ptr _Enum{ __icu_ucal_openTimeZoneIDEnumeration(USystemTimeZoneType::UCAL_ZONE_TYPE_ANY, nullptr, nullptr, &_UErr), &__icu_uenum_close}; @@ -219,17 +263,15 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return _Propagate_error(_Info); } - UBool _Is_system{}; - char16_t _Link_buf[256]; - const auto _Link_buf_len = - __icu_ucal_getCanonicalTimeZoneID(_Elem, _Elem_len, _Link_buf, sizeof(_Link_buf), &_Is_system, &_UErr); - if (U_FAILURE(_UErr) || _Link_buf_len == 0) { - return _Report_error(_Info, __std_tzdb_error::_Icu_error); + int32_t _Link_len{}; + const auto _Link = _Get_canonical_id(_Elem, _Elem_len, _Link_len, _Info->_Err); + if (_Link == nullptr) { + return _Propagate_error(_Info); } if (_STD u16string_view{_Elem, static_cast(_Elem_len)} - != _STD u16string_view{_Link_buf, static_cast(_Link_buf_len)}) { - _Info->_Links[_Name_idx] = _Allocate_wide_to_narrow(_Link_buf, _Link_buf_len, _Info->_Err); + != _STD u16string_view{_Link.get(), static_cast(_Link_len)}) { + _Info->_Links[_Name_idx] = _Allocate_wide_to_narrow(_Link.get(), _Link_len, _Info->_Err); if (_Info->_Links[_Name_idx] == nullptr) { return _Propagate_error(_Info); } diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp index 2513aec54dc..63b37298abd 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp @@ -380,15 +380,15 @@ static_assert(is_clock_v); tzdb copy_tzdb() { const auto& my_tzdb = get_tzdb_list().front(); - vector time_zones; + vector zones; vector links; - _STD transform(my_tzdb.time_zones.begin(), my_tzdb.time_zones.end(), _STD back_inserter(time_zones), + _STD transform(my_tzdb.zones.begin(), my_tzdb.zones.end(), _STD back_inserter(zones), [](const auto& _Tz) { return time_zone{_Tz.name()}; }); _STD transform(my_tzdb.links.begin(), my_tzdb.links.end(), _STD back_inserter(links), [](const auto& link) { return time_zone_link{link.name(), link.target()}; }); - return {_STD move(time_zones), _STD move(links), my_tzdb.leap_seconds, my_tzdb._All_ls_positive}; + return {my_tzdb.version, _STD move(zones), _STD move(links), my_tzdb.leap_seconds, my_tzdb._All_ls_positive}; } int main() { diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp index 3c3fef7799a..04ced25c095 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_zones/test.cpp @@ -26,14 +26,24 @@ void test_time_zone_and_link(const tzdb& tzdb, string_view tz_name, string_view assert(tz_link->target() == tz_name); assert(tzdb.locate_zone(tz_link->target()) == orginal_tz); - assert(_Locate_zone_impl(tzdb.time_zones, tz_name) != nullptr); - assert(_Locate_zone_impl(tzdb.time_zones, tz_link_name) == nullptr); + assert(_Locate_zone_impl(tzdb.zones, tz_name) != nullptr); + assert(_Locate_zone_impl(tzdb.zones, tz_link_name) == nullptr); assert(_Locate_zone_impl(tzdb.links, tz_name) == nullptr); } +void try_locate_invalid_zone(const tzdb& tzdb, string_view name) { + try { + (void) tzdb.locate_zone(name); + assert(false); + } catch (runtime_error) { + } +} + void timezone_names_test() { const auto& tzdb = get_tzdb(); + assert(tzdb.version.empty() == false); + test_time_zone_and_link(tzdb, "Asia/Thimphu", "Asia/Thimbu"); test_time_zone_and_link(tzdb, "America/Tijuana", "America/Ensenada"); @@ -41,11 +51,11 @@ void timezone_names_test() { assert(current_zone != nullptr); assert(current_zone->name().empty() == false); - assert(tzdb.locate_zone("Non/Existent") == nullptr); + try_locate_invalid_zone(tzdb, "Non/Existent"); // Abbreviations should not be time_zones or time_zone_links - assert(tzdb.locate_zone("PDT") == nullptr); - assert(tzdb.locate_zone("AEST") == nullptr); + try_locate_invalid_zone(tzdb, "PDT"); + try_locate_invalid_zone(tzdb, "AEST"); // Comparison operators const time_zone tz1{"Earlier"}; @@ -74,18 +84,18 @@ void timezone_names_test() { // these are some example in which the ICU.dll and IANA database diverge in what they consider a zone or a link assert(_Locate_zone_impl(tzdb.links, "Atlantic/Faroe") != nullptr); // is a time_zone in IANA - assert(_Locate_zone_impl(tzdb.time_zones, "Africa/Addis_Ababa") != nullptr); // is a time_zone_link in IANA + assert(_Locate_zone_impl(tzdb.zones, "Africa/Addis_Ababa") != nullptr); // is a time_zone_link in IANA assert(_Locate_zone_impl(tzdb.links, "PST") != nullptr); // time_zone_link does not exist in IANA assert(_Locate_zone_impl(tzdb.links, "Africa/Asmara") != nullptr); // matches IANA but target is wrong assert(_Locate_zone_impl(tzdb.links, "Africa/Asmara")->target() == "Africa/Asmera"); // target == Africa/Nairobi - assert(_Locate_zone_impl(tzdb.time_zones, "America/Nuuk") == nullptr); // does not exist in ICU (very rare) + assert(_Locate_zone_impl(tzdb.zones, "America/Nuuk") == nullptr); // does not exist in ICU (very rare) } bool test() { try { timezone_names_test(); } catch (exception& ex) { - std::cerr << "Test threw exception: " << ex.what() << "\n"; + cerr << "Test threw exception: " << ex.what() << "\n"; assert(false); } From 9068de9a714c789f7c646ebb410c095ef202a6a4 Mon Sep 17 00:00:00 2001 From: Daniel Winsor Date: Thu, 11 Mar 2021 18:16:37 -0800 Subject: [PATCH 14/15] More feedback --- stl/inc/xtzdb.h | 4 +- stl/src/tzdb.cpp | 111 +++++++++++++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/stl/inc/xtzdb.h b/stl/inc/xtzdb.h index 03cb8b831d6..abd6aeaeb82 100644 --- a/stl/inc/xtzdb.h +++ b/stl/inc/xtzdb.h @@ -43,8 +43,8 @@ struct __std_tzdb_time_zones_info { // ordered list of null-terminated time_zone/time_zone_link names const char** _Names; // contains corresponding entry for every name, if: - // (_Link[i] == nullptr) then _Names[i] is a time_zone - // (_Link[i] != nullptr) then _Names[i] is a time_zone_link to time_zone with name _Link[i] + // (_Links[i] == nullptr) then _Names[i] is a time_zone + // (_Links[i] != nullptr) then _Names[i] is a time_zone_link to time_zone with name _Links[i] const char** _Links; }; diff --git a/stl/src/tzdb.cpp b/stl/src/tzdb.cpp index a5a15845fb6..ab065abdeec 100644 --- a/stl/src/tzdb.cpp +++ b/stl/src/tzdb.cpp @@ -34,9 +34,10 @@ namespace { _Icu_functions_table _Icu_functions; - template - void _Load_address(const HMODULE _Module, _STD atomic& _Stored_Pfn, LPCSTR _Fn_name, DWORD& _Last_error) { - const auto _Pfn = reinterpret_cast(GetProcAddress(_Module, _Fn_name)); + template + void _Load_address( + const HMODULE _Module, _STD atomic<_Ty>& _Stored_Pfn, LPCSTR _Fn_name, DWORD& _Last_error) noexcept { + const auto _Pfn = reinterpret_cast<_Ty>(GetProcAddress(_Module, _Fn_name)); if (_Pfn != nullptr) { _Stored_Pfn.store(_Pfn, _STD memory_order_relaxed); } else { @@ -45,7 +46,8 @@ namespace { } _NODISCARD _Icu_api_level _Init_icu_functions(_Icu_api_level _Level) noexcept { - while (!_Icu_functions._Api_level.compare_exchange_weak(_Level, _Icu_api_level::_Detecting)) { + while (!_Icu_functions._Api_level.compare_exchange_weak( + _Level, _Icu_api_level::_Detecting, _STD memory_order_acq_rel)) { if (_Level > _Icu_api_level::_Detecting) { return _Level; } @@ -70,7 +72,7 @@ namespace { if (_Last_error == ERROR_SUCCESS) { _Level = _Icu_api_level::_Has_icu_addresses; } else { - // reset last error code for thread in-case a later GetProcAddress resets it + // reset last error code for thread in case a later GetProcAddress resets it SetLastError(_Last_error); } } @@ -100,33 +102,33 @@ namespace { } _NODISCARD UEnumeration* __icu_ucal_openTimeZoneIDEnumeration( - USystemTimeZoneType zoneType, const char* region, const int32_t* rawOffset, UErrorCode* ec) { + USystemTimeZoneType zoneType, const char* region, const int32_t* rawOffset, UErrorCode* ec) noexcept { const auto _Fun = _Icu_functions._Pfn_ucal_openTimeZoneIDEnumeration.load(_STD memory_order_relaxed); return _Fun(zoneType, region, rawOffset, ec); } - _NODISCARD const char* __icu_ucal_getTZDataVersion(UErrorCode* status) { + _NODISCARD const char* __icu_ucal_getTZDataVersion(UErrorCode* status) noexcept { const auto _Fun = _Icu_functions._Pfn_ucal_getTZDataVersion.load(_STD memory_order_relaxed); return _Fun(status); } - _NODISCARD void __icu_uenum_close(UEnumeration* en) { + _NODISCARD void __icu_uenum_close(UEnumeration* en) noexcept { const auto _Fun = _Icu_functions._Pfn_uenum_close.load(_STD memory_order_relaxed); return _Fun(en); } - _NODISCARD int32_t __icu_uenum_count(UEnumeration* en, UErrorCode* ec) { + _NODISCARD int32_t __icu_uenum_count(UEnumeration* en, UErrorCode* ec) noexcept { const auto _Fun = _Icu_functions._Pfn_uenum_count.load(_STD memory_order_relaxed); return _Fun(en, ec); } - _NODISCARD const UChar* __icu_uenum_unext(UEnumeration* en, int32_t* resultLength, UErrorCode* status) { + _NODISCARD const UChar* __icu_uenum_unext(UEnumeration* en, int32_t* resultLength, UErrorCode* status) noexcept { const auto _Fun = _Icu_functions._Pfn_uenum_unext.load(_STD memory_order_relaxed); return _Fun(en, resultLength, status); } _NODISCARD const char* _Allocate_wide_to_narrow( - const char16_t* _Input, int _Input_len, __std_tzdb_error& _Err) noexcept { + const char16_t* const _Input, const int _Input_len, __std_tzdb_error& _Err) noexcept { const auto _Code_page = __std_fs_code_page(); const auto _Input_as_wchar = reinterpret_cast(_Input); const auto _Count_result = __std_fs_convert_wide_to_narrow(_Code_page, _Input_as_wchar, _Input_len, nullptr, 0); @@ -153,8 +155,8 @@ namespace { } _NODISCARD _STD unique_ptr _Get_canonical_id( - const char16_t* _Id, int32_t _Len, int32_t& _Result_len, __std_tzdb_error& _Err) { - static constexpr int32_t _Link_buf_len = 32; + const char16_t* _Id, const int32_t _Len, int32_t& _Result_len, __std_tzdb_error& _Err) noexcept { + constexpr int32_t _Link_buf_len = 32; _STD unique_ptr _Link_buf{new (_STD nothrow) char16_t[_Link_buf_len]}; if (_Link_buf == nullptr) { return nullptr; @@ -184,25 +186,55 @@ namespace { return _Link_buf; } - template - _NODISCARD constexpr _Ty* _Report_error(_STD unique_ptr<_Ty, _Dtor>& _Info, __std_tzdb_error _Err) { + _NODISCARD _STD unique_ptr _Get_default_timezone( + int32_t& _Result_len, __std_tzdb_error& _Err) noexcept { + constexpr int32_t _Name_buf_len = 32; + _STD unique_ptr _Name_buf{new (_STD nothrow) char16_t[_Name_buf_len]}; + if (_Name_buf == nullptr) { + return nullptr; + } + + UErrorCode _UErr{U_ZERO_ERROR}; + _Result_len = __icu_ucal_getDefaultTimeZone(_Name_buf.get(), _Name_buf_len, &_UErr); + if (_UErr == U_BUFFER_OVERFLOW_ERROR && _Result_len > 0) { + _Name_buf.reset(new (_STD nothrow) char16_t[_Result_len + 1]); + if (_Name_buf == nullptr) { + return nullptr; + } + + _UErr = U_ZERO_ERROR; // reset error. + _Result_len = __icu_ucal_getDefaultTimeZone(_Name_buf.get(), _Name_buf_len, &_UErr); + if (U_FAILURE(_UErr)) { + _Err = __std_tzdb_error::_Icu_error; + return nullptr; + } + } else if (U_FAILURE(_UErr) || _Result_len <= 0) { + _Err = __std_tzdb_error::_Icu_error; + return nullptr; + } + + return _Name_buf; + } + + template + _NODISCARD _Ty* _Report_error(_STD unique_ptr<_Ty, _Dx>& _Info, __std_tzdb_error _Err) { _Info->_Err = _Err; return _Info.release(); } - template - _NODISCARD constexpr _Ty* _Propagate_error(_STD unique_ptr<_Ty, _Dtor>& _Info) { - // a bad_alloc() returns nullptr and does not set __std_tzdb_error - return _Info->_Err != __std_tzdb_error::_Success ? _Info.release() : nullptr; + template + _NODISCARD _Ty* _Propagate_error(_STD unique_ptr<_Ty, _Dx>& _Info) { + // a bad_alloc returns nullptr and does not set __std_tzdb_error + return _Info->_Err == __std_tzdb_error::_Success ? nullptr : _Info.release(); } -} // namespace +} // unnamed namespace _EXTERN_C _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept { // On exit--- - // _Info == nullptr --> bad_alloc() + // _Info == nullptr --> bad_alloc // _Info->_Err == _Win_error --> failed, call GetLastError() // _Info->_Err == _Icu_error --> runtime_error interacting with ICU _STD unique_ptr<__std_tzdb_time_zones_info, decltype(&__std_tzdb_delete_time_zones)> _Info{ @@ -229,31 +261,27 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe } // uenum_count may be expensive but is required to pre-allocate arrays. - int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_UErr); + const int32_t _Num_time_zones = __icu_uenum_count(_Enum.get(), &_UErr); if (U_FAILURE(_UErr)) { return _Report_error(_Info, __std_tzdb_error::_Icu_error); } _Info->_Num_time_zones = static_cast(_Num_time_zones); - _Info->_Names = new (_STD nothrow) const char*[_Info->_Num_time_zones]; + // value-init to ensure __std_tzdb_delete_time_zones() cleanup is valid + _Info->_Names = new (_STD nothrow) const char* [_Info->_Num_time_zones] {}; if (_Info->_Names == nullptr) { return nullptr; } - // init to ensure __std_tzdb_delete_time_zones() cleanup is valid - _STD fill_n(_Info->_Names, static_cast(_Info->_Num_time_zones), nullptr); - - _Info->_Links = new (_STD nothrow) const char*[_Info->_Num_time_zones]; + // value-init to ensure __std_tzdb_delete_time_zones() cleanup is valid + _Info->_Links = new (_STD nothrow) const char* [_Info->_Num_time_zones] {}; if (_Info->_Links == nullptr) { return nullptr; } - // init to ensure __std_tzdb_delete_time_zones() cleanup is valid - _STD fill_n(_Info->_Links, static_cast(_Info->_Num_time_zones), nullptr); - for (size_t _Name_idx = 0; _Name_idx < _Info->_Num_time_zones; ++_Name_idx) { int32_t _Elem_len{}; - const auto* _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_UErr); + const auto* const _Elem = __icu_uenum_unext(_Enum.get(), &_Elem_len, &_UErr); if (U_FAILURE(_UErr) || _Elem == nullptr) { return _Report_error(_Info, __std_tzdb_error::_Icu_error); } @@ -281,7 +309,7 @@ _NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noe return _Info.release(); } -void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept { +void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* const _Info) noexcept { if (_Info != nullptr) { if (_Info->_Names != nullptr) { for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { @@ -297,15 +325,15 @@ void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) n delete[] _Info->_Links[_Idx]; } - delete[] _Info->_Names; - _Info->_Names = nullptr; + delete[] _Info->_Links; + _Info->_Links = nullptr; } } } _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept { // On exit--- - // _Info == nullptr --> bad_alloc() + // _Info == nullptr --> bad_alloc // _Info->_Err == _Win_error --> failed, call GetLastError() // _Info->_Err == _Icu_error --> runtime_error interacting with ICU _STD unique_ptr<__std_tzdb_current_zone_info, decltype(&__std_tzdb_delete_current_zone)> _Info{ @@ -318,14 +346,13 @@ _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() return _Report_error(_Info, __std_tzdb_error::_Win_error); } - UErrorCode _Err{}; - char16_t _Id_buf[256]; - const auto _Id_buf_len = __icu_ucal_getDefaultTimeZone(_Id_buf, sizeof(_Id_buf), &_Err); - if (U_FAILURE(_Err) || _Id_buf_len == 0) { - return _Report_error(_Info, __std_tzdb_error::_Icu_error); + int32_t _Id_len{}; + const auto _Id_name = _Get_default_timezone(_Id_len, _Info->_Err); + if (_Id_name == nullptr) { + return _Propagate_error(_Info); } - _Info->_Tz_name = _Allocate_wide_to_narrow(_Id_buf, static_cast(_Id_buf_len), _Info->_Err); + _Info->_Tz_name = _Allocate_wide_to_narrow(_Id_name.get(), _Id_len, _Info->_Err); if (_Info->_Tz_name == nullptr) { return _Propagate_error(_Info); } @@ -333,7 +360,7 @@ _NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() return _Info.release(); } -void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* _Info) noexcept { +void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* const _Info) noexcept { if (_Info) { delete[] _Info->_Tz_name; _Info->_Tz_name = nullptr; From 1eb6fa04b8e03d6a2147f4da402ab72970e84968 Mon Sep 17 00:00:00 2001 From: d-winsor Date: Fri, 12 Mar 2021 12:08:41 -0800 Subject: [PATCH 15/15] Remove qualifiers from test Co-authored-by: mnatsuhara <46756417+mnatsuhara@users.noreply.github.com> --- .../tests/P0355R7_calendars_and_time_zones_clocks/test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp index 63b37298abd..e4f17ac061d 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp @@ -382,13 +382,13 @@ tzdb copy_tzdb() { const auto& my_tzdb = get_tzdb_list().front(); vector zones; vector links; - _STD transform(my_tzdb.zones.begin(), my_tzdb.zones.end(), _STD back_inserter(zones), + transform(my_tzdb.zones.begin(), my_tzdb.zones.end(), back_inserter(zones), [](const auto& _Tz) { return time_zone{_Tz.name()}; }); - _STD transform(my_tzdb.links.begin(), my_tzdb.links.end(), _STD back_inserter(links), [](const auto& link) { + transform(my_tzdb.links.begin(), my_tzdb.links.end(), back_inserter(links), [](const auto& link) { return time_zone_link{link.name(), link.target()}; }); - return {my_tzdb.version, _STD move(zones), _STD move(links), my_tzdb.leap_seconds, my_tzdb._All_ls_positive}; + return {my_tzdb.version, move(zones), move(links), my_tzdb.leap_seconds, my_tzdb._All_ls_positive}; } int main() {