[libc++][chrono] Loads tzdata.zi in tzdb. (#74928)
This implements the loading of the tzdata.zi file and store its contents in the tzdb struct. This adds all required members except: - the leap seconds, - the locate_zone, and - current_zone. The class time_zone is incomplete and only contains the parts needed for storing the parsed data. The class time_zone_link is fully implemented including its non-member functions. Implements parts of: - P0355 Extending <chrono> to Calendars and Time Zones - P1614 The Mothership has Landed Implements: - P1982 Rename link to time_zone_link
This commit is contained in:
parent
ded3ca224f
commit
d332d88b91
@ -180,7 +180,7 @@
|
|||||||
"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","|Complete|","16.0"
|
"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","|Complete|","16.0"
|
||||||
"`P1976R2 <https://wg21.link/P1976R2>`__","LWG","Fixed-size span construction from dynamic range","Prague","|Complete|","11.0","|ranges|"
|
"`P1976R2 <https://wg21.link/P1976R2>`__","LWG","Fixed-size span construction from dynamic range","Prague","|Complete|","11.0","|ranges|"
|
||||||
"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","* *",""
|
"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","* *",""
|
||||||
"`P1982R0 <https://wg21.link/P1982R0>`__","LWG","Rename link to time_zone_link","Prague","* *",""
|
"`P1982R0 <https://wg21.link/P1982R0>`__","LWG","Rename link to time_zone_link","Prague","|Complete|","19.0","|chrono|"
|
||||||
"`P1983R0 <https://wg21.link/P1983R0>`__","LWG","Wording for GB301, US296, US292, US291, and US283","Prague","|Complete|","15.0","|ranges|"
|
"`P1983R0 <https://wg21.link/P1983R0>`__","LWG","Wording for GB301, US296, US292, US291, and US283","Prague","|Complete|","15.0","|ranges|"
|
||||||
"`P1994R1 <https://wg21.link/P1994R1>`__","LWG","elements_view needs its own sentinel","Prague","|Complete|","16.0","|ranges|"
|
"`P1994R1 <https://wg21.link/P1994R1>`__","LWG","elements_view needs its own sentinel","Prague","|Complete|","16.0","|ranges|"
|
||||||
"`P2002R1 <https://wg21.link/P2002R1>`__","CWG","Defaulted comparison specification cleanups","Prague","* *",""
|
"`P2002R1 <https://wg21.link/P2002R1>`__","CWG","Defaulted comparison specification cleanups","Prague","* *",""
|
||||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -171,10 +171,10 @@ Section,Description,Dependencies,Assignee,Complete
|
|||||||
| `month_weekday_last <https://reviews.llvm.org/D152699>`_
|
| `month_weekday_last <https://reviews.llvm.org/D152699>`_
|
||||||
| `year_month_weekday <https://reviews.llvm.org/D152699>`_
|
| `year_month_weekday <https://reviews.llvm.org/D152699>`_
|
||||||
| `year_month_weekday_last <https://reviews.llvm.org/D152699>`_",None,Hristo Hristov,|Complete|
|
| `year_month_weekday_last <https://reviews.llvm.org/D152699>`_",None,Hristo Hristov,|Complete|
|
||||||
`[time.zone.nonmembers] <https://wg21.link/time.zone.nonmembers>`_,"`chrono::time_zone`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
`[time.zone.nonmembers] <https://wg21.link/time.zone.nonmembers>`_,"`chrono::time_zone`",A ``<chrono>`` implementation,Mark de Wever,|Complete|
|
||||||
`[time.zone.zonedtime.nonmembers] <https://wg21.link/time.zone.zonedtime.nonmembers>`_,"`chrono::zoned_time`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
`[time.zone.zonedtime.nonmembers] <https://wg21.link/time.zone.zonedtime.nonmembers>`_,"`chrono::zoned_time`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
||||||
`[time.zone.leap.nonmembers] <https://wg21.link/time.zone.leap.nonmembers>`_,"`chrono::time_leap_seconds`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
`[time.zone.leap.nonmembers] <https://wg21.link/time.zone.leap.nonmembers>`_,"`chrono::time_leap_seconds`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
||||||
`[time.zone.link.nonmembers] <https://wg21.link/time.zone.link.nonmembers>`_,"`chrono::time_zone_link`",A ``<chrono>`` implementation,Mark de Wever,|In Progress|
|
`[time.zone.link.nonmembers] <https://wg21.link/time.zone.link.nonmembers>`_,"`chrono::time_zone_link`",A ``<chrono>`` implementation,Mark de Wever,|Complete|
|
||||||
- `5.13 Clause 28: Localization library <https://wg21.link/p1614r2#clause-28-localization-library>`_,,,,
|
- `5.13 Clause 28: Localization library <https://wg21.link/p1614r2#clause-28-localization-library>`_,,,,
|
||||||
"| `[locale] <https://wg21.link/locale>`_
|
"| `[locale] <https://wg21.link/locale>`_
|
||||||
| `[locale.operators] <https://wg21.link/locale.operators>`_",| remove ops `locale <https://reviews.llvm.org/D152654>`_,None,Hristo Hristov,|Complete|
|
| `[locale.operators] <https://wg21.link/locale.operators>`_",| remove ops `locale <https://reviews.llvm.org/D152654>`_,None,Hristo Hristov,|Complete|
|
||||||
|
|
@ -291,6 +291,8 @@ set(files
|
|||||||
__chrono/steady_clock.h
|
__chrono/steady_clock.h
|
||||||
__chrono/system_clock.h
|
__chrono/system_clock.h
|
||||||
__chrono/time_point.h
|
__chrono/time_point.h
|
||||||
|
__chrono/time_zone.h
|
||||||
|
__chrono/time_zone_link.h
|
||||||
__chrono/tzdb.h
|
__chrono/tzdb.h
|
||||||
__chrono/tzdb_list.h
|
__chrono/tzdb_list.h
|
||||||
__chrono/weekday.h
|
__chrono/weekday.h
|
||||||
|
86
libcxx/include/__chrono/time_zone.h
Normal file
86
libcxx/include/__chrono/time_zone.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP___CHRONO_TIME_ZONE_H
|
||||||
|
#define _LIBCPP___CHRONO_TIME_ZONE_H
|
||||||
|
|
||||||
|
#include <version>
|
||||||
|
// Enable the contents of the header only when libc++ was built with experimental features enabled.
|
||||||
|
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
|
# include <__compare/strong_order.h>
|
||||||
|
# include <__config>
|
||||||
|
# include <__memory/unique_ptr.h>
|
||||||
|
# include <string_view>
|
||||||
|
|
||||||
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
|
# pragma GCC system_header
|
||||||
|
# endif
|
||||||
|
|
||||||
|
_LIBCPP_PUSH_MACROS
|
||||||
|
# include <__undef_macros>
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
||||||
|
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
class _LIBCPP_AVAILABILITY_TZDB time_zone {
|
||||||
|
_LIBCPP_HIDE_FROM_ABI time_zone() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class __impl; // public so it can be used by make_unique.
|
||||||
|
|
||||||
|
// The "constructor".
|
||||||
|
//
|
||||||
|
// The default constructor is private to avoid the constructor from being
|
||||||
|
// part of the ABI. Instead use an __ugly_named function as an ABI interface,
|
||||||
|
// since that gives us the ability to change it in the future.
|
||||||
|
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI static time_zone __create(unique_ptr<__impl>&& __p);
|
||||||
|
|
||||||
|
_LIBCPP_EXPORTED_FROM_ABI ~time_zone();
|
||||||
|
|
||||||
|
_LIBCPP_HIDE_FROM_ABI time_zone(time_zone&&) = default;
|
||||||
|
_LIBCPP_HIDE_FROM_ABI time_zone& operator=(time_zone&&) = default;
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); }
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept;
|
||||||
|
unique_ptr<__impl> __impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool
|
||||||
|
operator==(const time_zone& __x, const time_zone& __y) noexcept {
|
||||||
|
return __x.name() == __y.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering
|
||||||
|
operator<=>(const time_zone& __x, const time_zone& __y) noexcept {
|
||||||
|
return __x.name() <=> __y.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
|
||||||
|
// && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
_LIBCPP_POP_MACROS
|
||||||
|
|
||||||
|
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
|
#endif // _LIBCPP___CHRONO_TIME_ZONE_H
|
79
libcxx/include/__chrono/time_zone_link.h
Normal file
79
libcxx/include/__chrono/time_zone_link.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP___CHRONO_TIME_ZONE_LINK_H
|
||||||
|
#define _LIBCPP___CHRONO_TIME_ZONE_LINK_H
|
||||||
|
|
||||||
|
#include <version>
|
||||||
|
// Enable the contents of the header only when libc++ was built with experimental features enabled.
|
||||||
|
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
|
# include <__compare/strong_order.h>
|
||||||
|
# include <__config>
|
||||||
|
# include <string>
|
||||||
|
# include <string_view>
|
||||||
|
|
||||||
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
|
# pragma GCC system_header
|
||||||
|
# endif
|
||||||
|
|
||||||
|
_LIBCPP_PUSH_MACROS
|
||||||
|
# include <__undef_macros>
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
||||||
|
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
class time_zone_link {
|
||||||
|
public:
|
||||||
|
struct __constructor_tag;
|
||||||
|
_LIBCPP_NODISCARD_EXT
|
||||||
|
_LIBCPP_HIDE_FROM_ABI explicit time_zone_link(__constructor_tag&&, string_view __name, string_view __target)
|
||||||
|
: __name_{__name}, __target_{__target} {}
|
||||||
|
|
||||||
|
_LIBCPP_HIDE_FROM_ABI time_zone_link(time_zone_link&&) = default;
|
||||||
|
_LIBCPP_HIDE_FROM_ABI time_zone_link& operator=(time_zone_link&&) = default;
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name_; }
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI string_view target() const noexcept { return __target_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
string __name_;
|
||||||
|
// TODO TZDB instead of the name we can store the pointer to a zone. These
|
||||||
|
// pointers are immutable. This makes it possible to directly return a
|
||||||
|
// pointer in the time_zone in the 'locate_zone' function.
|
||||||
|
string __target_;
|
||||||
|
};
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool
|
||||||
|
operator==(const time_zone_link& __x, const time_zone_link& __y) noexcept {
|
||||||
|
return __x.name() == __y.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering
|
||||||
|
operator<=>(const time_zone_link& __x, const time_zone_link& __y) noexcept {
|
||||||
|
return __x.name() <=> __y.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
# endif //_LIBCPP_STD_VER >= 20
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
_LIBCPP_POP_MACROS
|
||||||
|
|
||||||
|
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
|
#endif // _LIBCPP___CHRONO_TIME_ZONE_LINK_H
|
@ -16,12 +16,19 @@
|
|||||||
// Enable the contents of the header only when libc++ was built with experimental features enabled.
|
// Enable the contents of the header only when libc++ was built with experimental features enabled.
|
||||||
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
|
# include <__chrono/time_zone.h>
|
||||||
|
# include <__chrono/time_zone_link.h>
|
||||||
|
# include <__config>
|
||||||
# include <string>
|
# include <string>
|
||||||
|
# include <vector>
|
||||||
|
|
||||||
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
# pragma GCC system_header
|
# pragma GCC system_header
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
_LIBCPP_PUSH_MACROS
|
||||||
|
# include <__undef_macros>
|
||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
||||||
@ -29,8 +36,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||||||
|
|
||||||
namespace chrono {
|
namespace chrono {
|
||||||
|
|
||||||
struct _LIBCPP_AVAILABILITY_TZDB tzdb {
|
struct tzdb {
|
||||||
string version;
|
string version;
|
||||||
|
vector<time_zone> zones;
|
||||||
|
vector<time_zone_link> links;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chrono
|
} // namespace chrono
|
||||||
@ -40,6 +49,8 @@ struct _LIBCPP_AVAILABILITY_TZDB tzdb {
|
|||||||
|
|
||||||
_LIBCPP_END_NAMESPACE_STD
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
_LIBCPP_POP_MACROS
|
||||||
|
|
||||||
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
|
||||||
|
|
||||||
#endif // _LIBCPP___CHRONO_TZDB_H
|
#endif // _LIBCPP___CHRONO_TZDB_H
|
||||||
|
@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
# include <__availability>
|
# include <__availability>
|
||||||
# include <__chrono/tzdb.h>
|
# include <__chrono/tzdb.h>
|
||||||
|
# include <__config>
|
||||||
|
# include <__fwd/string.h>
|
||||||
# include <forward_list>
|
# include <forward_list>
|
||||||
# include <string_view>
|
|
||||||
|
|
||||||
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
# pragma GCC system_header
|
# pragma GCC system_header
|
||||||
@ -32,9 +33,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||||||
|
|
||||||
namespace chrono {
|
namespace chrono {
|
||||||
|
|
||||||
|
// TODO TZDB
|
||||||
|
// Libc++ recently switched to only export __ugly_names from the dylib.
|
||||||
|
// Since the library is still experimental the functions in this header
|
||||||
|
// should be adapted to this new style. The other tzdb headers should be
|
||||||
|
// evaluated too.
|
||||||
|
|
||||||
class _LIBCPP_AVAILABILITY_TZDB tzdb_list {
|
class _LIBCPP_AVAILABILITY_TZDB tzdb_list {
|
||||||
public:
|
public:
|
||||||
_LIBCPP_EXPORTED_FROM_ABI explicit tzdb_list(tzdb&& __tzdb);
|
class __impl; // public to allow construction in dylib
|
||||||
|
_LIBCPP_HIDE_FROM_ABI explicit tzdb_list(__impl* __p) : __impl_(__p) {
|
||||||
|
_LIBCPP_ASSERT_NON_NULL(__impl_ != nullptr, "initialized time_zone without a valid pimpl object");
|
||||||
|
}
|
||||||
_LIBCPP_EXPORTED_FROM_ABI ~tzdb_list();
|
_LIBCPP_EXPORTED_FROM_ABI ~tzdb_list();
|
||||||
|
|
||||||
tzdb_list(const tzdb_list&) = delete;
|
tzdb_list(const tzdb_list&) = delete;
|
||||||
@ -46,16 +56,15 @@ public:
|
|||||||
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI const_iterator erase_after(const_iterator __p);
|
_LIBCPP_EXPORTED_FROM_ABI const_iterator erase_after(const_iterator __p);
|
||||||
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI tzdb& __emplace_front(tzdb&& __tzdb);
|
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator begin() const noexcept;
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator begin() const noexcept;
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator end() const noexcept;
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator end() const noexcept;
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator cbegin() const noexcept;
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator cbegin() const noexcept;
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator cend() const noexcept;
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const_iterator cend() const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __impl& __implementation() { return *__impl_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class __impl;
|
|
||||||
__impl* __impl_;
|
__impl* __impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -686,6 +686,8 @@ constexpr hours make24(const hours& h, bool is_pm) noexcept;
|
|||||||
// [time.zone.db], time zone database
|
// [time.zone.db], time zone database
|
||||||
struct tzdb { // C++20
|
struct tzdb { // C++20
|
||||||
string version;
|
string version;
|
||||||
|
vector<time_zone> zones;
|
||||||
|
vector<time_zone_link> links;
|
||||||
};
|
};
|
||||||
|
|
||||||
class tzdb_list { // C++20
|
class tzdb_list { // C++20
|
||||||
@ -716,15 +718,34 @@ tzdb_list& get_tzdb_list();
|
|||||||
const tzdb& reload_tzdb(); // C++20
|
const tzdb& reload_tzdb(); // C++20
|
||||||
string remote_version(); // C++20
|
string remote_version(); // C++20
|
||||||
|
|
||||||
// 25.10.5, class time_zone // C++20
|
// 25.10.5, class time_zone // C++20
|
||||||
enum class choose {earliest, latest};
|
enum class choose {earliest, latest};
|
||||||
class time_zone;
|
class time_zone {
|
||||||
bool operator==(const time_zone& x, const time_zone& y) noexcept;
|
time_zone(time_zone&&) = default;
|
||||||
bool operator!=(const time_zone& x, const time_zone& y) noexcept;
|
time_zone& operator=(time_zone&&) = default;
|
||||||
bool operator<(const time_zone& x, const time_zone& y) noexcept;
|
|
||||||
bool operator>(const time_zone& x, const time_zone& y) noexcept;
|
// unspecified additional constructors
|
||||||
bool operator<=(const time_zone& x, const time_zone& y) noexcept;
|
|
||||||
bool operator>=(const time_zone& x, const time_zone& y) noexcept;
|
string_view name() const noexcept;
|
||||||
|
};
|
||||||
|
bool operator==(const time_zone& x, const time_zone& y) noexcept; // C++20
|
||||||
|
strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; // C++20
|
||||||
|
|
||||||
|
// [time.zone.link], class time_zone_link
|
||||||
|
class time_zone_link { // C++20
|
||||||
|
public:
|
||||||
|
time_zone_link(time_zone_link&&) = default;
|
||||||
|
time_zone_link& operator=(time_zone_link&&) = default;
|
||||||
|
|
||||||
|
// unspecified additional constructors
|
||||||
|
|
||||||
|
string_view name() const noexcept;
|
||||||
|
string_view target() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const time_zone_link& x, const time_zone_link& y); // C++20
|
||||||
|
strong_ordering operator<=>(const time_zone_link& x, const time_zone_link& y); // C++20
|
||||||
|
|
||||||
} // chrono
|
} // chrono
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
@ -842,6 +863,8 @@ constexpr chrono::year operator ""y(unsigned lo
|
|||||||
|
|
||||||
#if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
#if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
|
||||||
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||||
|
# include <__chrono/time_zone.h>
|
||||||
|
# include <__chrono/time_zone_link.h>
|
||||||
# include <__chrono/tzdb.h>
|
# include <__chrono/tzdb.h>
|
||||||
# include <__chrono/tzdb_list.h>
|
# include <__chrono/tzdb_list.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -288,6 +288,8 @@
|
|||||||
{ include: [ "<__chrono/steady_clock.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/steady_clock.h>", "private", "<chrono>", "public" ] },
|
||||||
{ include: [ "<__chrono/system_clock.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/system_clock.h>", "private", "<chrono>", "public" ] },
|
||||||
{ include: [ "<__chrono/time_point.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/time_point.h>", "private", "<chrono>", "public" ] },
|
||||||
|
{ include: [ "<__chrono/time_zone.h>", "private", "<chrono>", "public" ] },
|
||||||
|
{ include: [ "<__chrono/time_zone_link.h>", "private", "<chrono>", "public" ] },
|
||||||
{ include: [ "<__chrono/tzdb.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/tzdb.h>", "private", "<chrono>", "public" ] },
|
||||||
{ include: [ "<__chrono/tzdb_list.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/tzdb_list.h>", "private", "<chrono>", "public" ] },
|
||||||
{ include: [ "<__chrono/weekday.h>", "private", "<chrono>", "public" ] },
|
{ include: [ "<__chrono/weekday.h>", "private", "<chrono>", "public" ] },
|
||||||
|
@ -1156,6 +1156,12 @@ module std_private_chrono_steady_clock [system] {
|
|||||||
header "__chrono/steady_clock.h"
|
header "__chrono/steady_clock.h"
|
||||||
export std_private_chrono_time_point
|
export std_private_chrono_time_point
|
||||||
}
|
}
|
||||||
|
module std_private_chrono_time_zone [system] {
|
||||||
|
header "__chrono/time_zone.h"
|
||||||
|
}
|
||||||
|
module std_private_chrono_time_zone_link [system] {
|
||||||
|
header "__chrono/time_zone_link.h"
|
||||||
|
}
|
||||||
module std_private_chrono_system_clock [system] {
|
module std_private_chrono_system_clock [system] {
|
||||||
header "__chrono/system_clock.h"
|
header "__chrono/system_clock.h"
|
||||||
export std_private_chrono_time_point
|
export std_private_chrono_time_point
|
||||||
|
@ -221,7 +221,11 @@ export namespace std {
|
|||||||
|
|
||||||
// [time.zone.timezone], class time_zone
|
// [time.zone.timezone], class time_zone
|
||||||
using std::chrono::choose;
|
using std::chrono::choose;
|
||||||
|
# endif
|
||||||
|
# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
|
||||||
using std::chrono::time_zone;
|
using std::chrono::time_zone;
|
||||||
|
# endif
|
||||||
|
# if 0
|
||||||
|
|
||||||
// [time.zone.zonedtraits], class template zoned_traits
|
// [time.zone.zonedtraits], class template zoned_traits
|
||||||
using std::chrono::zoned_traits;
|
using std::chrono::zoned_traits;
|
||||||
@ -233,10 +237,14 @@ export namespace std {
|
|||||||
|
|
||||||
// [time.zone.leap], leap second support
|
// [time.zone.leap], leap second support
|
||||||
using std::chrono::leap_second;
|
using std::chrono::leap_second;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
|
||||||
// [time.zone.link], class time_zone_link
|
// [time.zone.link], class time_zone_link
|
||||||
using std::chrono::time_zone_link;
|
using std::chrono::time_zone_link;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if 0
|
||||||
// [time.format], formatting
|
// [time.format], formatting
|
||||||
using std::chrono::local_time_format;
|
using std::chrono::local_time_format;
|
||||||
# endif
|
# endif
|
||||||
|
@ -336,7 +336,13 @@ endif()
|
|||||||
|
|
||||||
if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
|
if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
|
||||||
list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
|
list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
|
||||||
tz.cpp
|
include/tzdb/time_zone_link_private.h
|
||||||
|
include/tzdb/time_zone_private.h
|
||||||
|
include/tzdb/types_private.h
|
||||||
|
include/tzdb/tzdb_list_private.h
|
||||||
|
include/tzdb/tzdb_private.h
|
||||||
|
time_zone.cpp
|
||||||
|
tzdb.cpp
|
||||||
tzdb_list.cpp
|
tzdb_list.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
27
libcxx/src/include/tzdb/time_zone_link_private.h
Normal file
27
libcxx/src/include/tzdb/time_zone_link_private.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
|
||||||
|
#define _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
struct time_zone_link::__constructor_tag {};
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
|
48
libcxx/src/include/tzdb/time_zone_private.h
Normal file
48
libcxx/src/include/tzdb/time_zone_private.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H
|
||||||
|
#define _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "types_private.h"
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
class time_zone::__impl {
|
||||||
|
public:
|
||||||
|
explicit _LIBCPP_HIDE_FROM_ABI __impl(string&& __name) : __name_(std::move(__name)) {}
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view __name() const noexcept { return __name_; }
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI vector<__tz::__continuation>& __continuations() { return __continuations_; }
|
||||||
|
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const vector<__tz::__continuation>& __continuations() const {
|
||||||
|
return __continuations_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
string __name_;
|
||||||
|
// Note the first line has a name + __continuation, the other lines
|
||||||
|
// are just __continuations. So there is always at least one item in
|
||||||
|
// the vector.
|
||||||
|
vector<__tz::__continuation> __continuations_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H
|
106
libcxx/src/include/tzdb/types_private.h
Normal file
106
libcxx/src/include/tzdb/types_private.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H
|
||||||
|
#define __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
// TODO TZDB
|
||||||
|
// The helper classes in this header have no constructor but are loaded with
|
||||||
|
// dedicated parse functions. In the original design this header was public and
|
||||||
|
// the parsing was done in the dylib. In that design having constructors would
|
||||||
|
// expand the ABI interface. Since this header is now in the dylib that design
|
||||||
|
// should be reconsidered. (For now the design is kept as is, in case this
|
||||||
|
// header needs to be public for unforseen reasons.)
|
||||||
|
|
||||||
|
namespace chrono::__tz {
|
||||||
|
|
||||||
|
// Sun>=8 first Sunday on or after the eighth
|
||||||
|
// Sun<=25 last Sunday on or before the 25th
|
||||||
|
struct __constrained_weekday {
|
||||||
|
/* year_month_day operator()(year __year, month __month);*/ // needed but not implemented
|
||||||
|
|
||||||
|
weekday __weekday;
|
||||||
|
enum __comparison_t { __le, __ge } __comparison;
|
||||||
|
day __day;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The on field has a few alternative presentations
|
||||||
|
// 5 the fifth of the month
|
||||||
|
// lastSun the last Sunday in the month
|
||||||
|
// lastMon the last Monday in the month
|
||||||
|
// Sun>=8 first Sunday on or after the eighth
|
||||||
|
// Sun<=25 last Sunday on or before the 25th
|
||||||
|
using __on = variant<day, weekday_last, __constrained_weekday>;
|
||||||
|
|
||||||
|
enum class __clock { __local, __standard, __universal };
|
||||||
|
|
||||||
|
struct __at {
|
||||||
|
seconds __time{0};
|
||||||
|
__tz::__clock __clock{__tz::__clock::__local};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __save {
|
||||||
|
seconds __time;
|
||||||
|
bool __is_dst;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The names of the fields match the fields of a Rule.
|
||||||
|
struct __rule {
|
||||||
|
year __from;
|
||||||
|
year __to;
|
||||||
|
month __in;
|
||||||
|
__tz::__on __on;
|
||||||
|
__tz::__at __at;
|
||||||
|
__tz::__save __save;
|
||||||
|
string __letters;
|
||||||
|
};
|
||||||
|
|
||||||
|
using __rules_storage_type = std::vector<std::pair<string, vector<__tz::__rule>>>; // TODO TZDB use flat_map;
|
||||||
|
|
||||||
|
struct __continuation {
|
||||||
|
// Non-owning link to the RULE entries.
|
||||||
|
__tz::__rules_storage_type* __rule_database_;
|
||||||
|
|
||||||
|
seconds __stdoff;
|
||||||
|
|
||||||
|
// The RULES is either a SAVE or a NAME.
|
||||||
|
// The size_t is used as cache. After loading the rules they are
|
||||||
|
// sorted and remain stable, then an index in the vector can be
|
||||||
|
// used.
|
||||||
|
// If this field contains - then standard time always
|
||||||
|
// applies. This is indicated by the monostate.
|
||||||
|
using __rules_t = variant<monostate, __tz::__save, string, size_t>;
|
||||||
|
|
||||||
|
__rules_t __rules;
|
||||||
|
|
||||||
|
string __format;
|
||||||
|
// TODO TZDB the until field can contain more than just a year.
|
||||||
|
// Parts of the UNTIL, the optional parts are default initialized
|
||||||
|
// optional<year> __until_;
|
||||||
|
year __year = chrono::year::min();
|
||||||
|
month __in{January};
|
||||||
|
__tz::__on __on{chrono::day{1}};
|
||||||
|
__tz::__at __at{chrono::seconds{0}, __tz::__clock::__local};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chrono::__tz
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H
|
104
libcxx/src/include/tzdb/tzdb_list_private.h
Normal file
104
libcxx/src/include/tzdb/tzdb_list_private.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H
|
||||||
|
#define _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H
|
||||||
|
|
||||||
|
#include <__mutex/unique_lock.h>
|
||||||
|
#include <forward_list>
|
||||||
|
|
||||||
|
// When threads are not available the locking is not required.
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
# include <shared_mutex>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "types_private.h"
|
||||||
|
#include "tzdb_private.h"
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Private API
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// The tzdb_list stores a list of "tzdb" entries.
|
||||||
|
//
|
||||||
|
// The public tzdb database does not store the RULE entries of the IANA
|
||||||
|
// database. These entries are considered an implementation detail. Since most
|
||||||
|
// of the tzdb_list interface is exposed as "a list of tzdb entries" it's not
|
||||||
|
// possible to use a helper struct that stores a tzdb and the RULE database.
|
||||||
|
// Instead this class stores these in parallel forward lists.
|
||||||
|
//
|
||||||
|
// Since the nodes of a forward_list are stable it's possible to store pointers
|
||||||
|
// and references to these nodes.
|
||||||
|
class tzdb_list::__impl {
|
||||||
|
public:
|
||||||
|
__impl() { __load_no_lock(); }
|
||||||
|
|
||||||
|
[[nodiscard]] const tzdb& __load() {
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
unique_lock __lock{__mutex_};
|
||||||
|
#endif
|
||||||
|
__load_no_lock();
|
||||||
|
return __tzdb_.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
using const_iterator = tzdb_list::const_iterator;
|
||||||
|
|
||||||
|
const tzdb& front() const noexcept {
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
shared_lock __lock{__mutex_};
|
||||||
|
#endif
|
||||||
|
return __tzdb_.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator erase_after(const_iterator __p) {
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
unique_lock __lock{__mutex_};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__rules_.erase_after(std::next(__rules_.cbegin(), std::distance(__tzdb_.cbegin(), __p)));
|
||||||
|
return __tzdb_.erase_after(__p);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const noexcept {
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
shared_lock __lock{__mutex_};
|
||||||
|
#endif
|
||||||
|
return __tzdb_.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() const noexcept {
|
||||||
|
// forward_list<T>::end does not access the list, so no need to take a lock.
|
||||||
|
return __tzdb_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const noexcept { return begin(); }
|
||||||
|
const_iterator cend() const noexcept { return end(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Loads the tzdbs
|
||||||
|
// pre: The caller ensures the locking, if needed, is done.
|
||||||
|
void __load_no_lock() { chrono::__init_tzdb(__tzdb_.emplace_front(), __rules_.emplace_front()); }
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||||
|
mutable shared_mutex __mutex_;
|
||||||
|
#endif
|
||||||
|
forward_list<tzdb> __tzdb_;
|
||||||
|
|
||||||
|
forward_list<__tz::__rules_storage_type> __rules_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H
|
28
libcxx/src/include/tzdb/tzdb_private.h
Normal file
28
libcxx/src/include/tzdb/tzdb_private.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H
|
||||||
|
#define _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "types_private.h"
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules);
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H
|
32
libcxx/src/time_zone.cpp
Normal file
32
libcxx/src/time_zone.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "include/tzdb/time_zone_private.h"
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI time_zone time_zone::__create(unique_ptr<time_zone::__impl>&& __p) {
|
||||||
|
_LIBCPP_ASSERT_NON_NULL(__p != nullptr, "initialized time_zone without a valid pimpl object");
|
||||||
|
time_zone result;
|
||||||
|
result.__impl_ = std::move(__p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_EXPORTED_FROM_ABI time_zone::~time_zone() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view time_zone::__name() const noexcept { return __impl_->__name(); }
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
@ -1,146 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// Contains a parser for the IANA time zone data files.
|
|
||||||
//
|
|
||||||
// These files can be found at https://data.iana.org/time-zones/ and are in the
|
|
||||||
// public domain. Information regarding the input can be found at
|
|
||||||
// https://data.iana.org/time-zones/tz-how-to.html and
|
|
||||||
// https://man7.org/linux/man-pages/man8/zic.8.html.
|
|
||||||
//
|
|
||||||
// As indicated at https://howardhinnant.github.io/date/tz.html#Installation
|
|
||||||
// For Windows another file seems to be required
|
|
||||||
// https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
|
|
||||||
// This file seems to contain the mapping of Windows time zone name to IANA
|
|
||||||
// time zone names.
|
|
||||||
//
|
|
||||||
// However this article mentions another way to do the mapping on Windows
|
|
||||||
// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255
|
|
||||||
// This requires Windows 10 Version 1903, which was released in May of 2019
|
|
||||||
// and considered end of life in December 2020
|
|
||||||
// https://learn.microsoft.com/en-us/lifecycle/announcements/windows-10-1903-end-of-servicing
|
|
||||||
//
|
|
||||||
// TODO TZDB Implement the Windows mapping in tzdb::current_zone
|
|
||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
||||||
|
|
||||||
namespace chrono {
|
|
||||||
|
|
||||||
// This function is weak so it can be overriden in the tests. The
|
|
||||||
// declaration is in the test header test/support/test_tzdb.h
|
|
||||||
_LIBCPP_WEAK string_view __libcpp_tzdb_directory() {
|
|
||||||
#if defined(__linux__)
|
|
||||||
return "/usr/share/zoneinfo/";
|
|
||||||
#else
|
|
||||||
# error "unknown path to the IANA Time Zone Database"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static bool __is_whitespace(int __c) { return __c == ' ' || __c == '\t'; }
|
|
||||||
|
|
||||||
static void __skip_optional_whitespace(istream& __input) {
|
|
||||||
while (chrono::__is_whitespace(__input.peek()))
|
|
||||||
__input.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __skip_mandatory_whitespace(istream& __input) {
|
|
||||||
if (!chrono::__is_whitespace(__input.get()))
|
|
||||||
std::__throw_runtime_error("corrupt tzdb: expected whitespace");
|
|
||||||
|
|
||||||
chrono::__skip_optional_whitespace(__input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __matches(istream& __input, char __expected) {
|
|
||||||
if (std::tolower(__input.get()) != __expected)
|
|
||||||
std::__throw_runtime_error((string("corrupt tzdb: expected character '") + __expected + '\'').c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __matches(istream& __input, string_view __expected) {
|
|
||||||
for (auto __c : __expected)
|
|
||||||
if (std::tolower(__input.get()) != __c)
|
|
||||||
std::__throw_runtime_error((string("corrupt tzdb: expected string '") + string(__expected) + '\'').c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static string __parse_string(istream& __input) {
|
|
||||||
string __result;
|
|
||||||
while (true) {
|
|
||||||
int __c = __input.get();
|
|
||||||
switch (__c) {
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
__input.unget();
|
|
||||||
[[fallthrough]];
|
|
||||||
case istream::traits_type::eof():
|
|
||||||
if (__result.empty())
|
|
||||||
std::__throw_runtime_error("corrupt tzdb: expected a string");
|
|
||||||
|
|
||||||
return __result;
|
|
||||||
|
|
||||||
default:
|
|
||||||
__result.push_back(__c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static string __parse_version(istream& __input) {
|
|
||||||
// The first line in tzdata.zi contains
|
|
||||||
// # version YYYYw
|
|
||||||
// The parser expects this pattern
|
|
||||||
// #\s*version\s*\(.*)
|
|
||||||
// This part is not documented.
|
|
||||||
chrono::__matches(__input, '#');
|
|
||||||
chrono::__skip_optional_whitespace(__input);
|
|
||||||
chrono::__matches(__input, "version");
|
|
||||||
chrono::__skip_mandatory_whitespace(__input);
|
|
||||||
return chrono::__parse_string(__input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static tzdb __make_tzdb() {
|
|
||||||
tzdb __result;
|
|
||||||
|
|
||||||
filesystem::path __root = chrono::__libcpp_tzdb_directory();
|
|
||||||
ifstream __tzdata{__root / "tzdata.zi"};
|
|
||||||
|
|
||||||
__result.version = chrono::__parse_version(__tzdata);
|
|
||||||
return __result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Public API
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI tzdb_list& get_tzdb_list() {
|
|
||||||
static tzdb_list __result{chrono::__make_tzdb()};
|
|
||||||
return __result;
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const tzdb& reload_tzdb() {
|
|
||||||
if (chrono::remote_version() == chrono::get_tzdb().version)
|
|
||||||
return chrono::get_tzdb();
|
|
||||||
|
|
||||||
return chrono::get_tzdb_list().__emplace_front(chrono::__make_tzdb());
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI string remote_version() {
|
|
||||||
filesystem::path __root = chrono::__libcpp_tzdb_directory();
|
|
||||||
ifstream __tzdata{__root / "tzdata.zi"};
|
|
||||||
return chrono::__parse_version(__tzdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chrono
|
|
||||||
|
|
||||||
_LIBCPP_END_NAMESPACE_STD
|
|
641
libcxx/src/tzdb.cpp
Normal file
641
libcxx/src/tzdb.cpp
Normal file
@ -0,0 +1,641 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "include/tzdb/time_zone_link_private.h"
|
||||||
|
#include "include/tzdb/time_zone_private.h"
|
||||||
|
#include "include/tzdb/types_private.h"
|
||||||
|
#include "include/tzdb/tzdb_list_private.h"
|
||||||
|
#include "include/tzdb/tzdb_private.h"
|
||||||
|
|
||||||
|
// Contains a parser for the IANA time zone data files.
|
||||||
|
//
|
||||||
|
// These files can be found at https://data.iana.org/time-zones/ and are in the
|
||||||
|
// public domain. Information regarding the input can be found at
|
||||||
|
// https://data.iana.org/time-zones/tz-how-to.html and
|
||||||
|
// https://man7.org/linux/man-pages/man8/zic.8.html.
|
||||||
|
//
|
||||||
|
// As indicated at https://howardhinnant.github.io/date/tz.html#Installation
|
||||||
|
// For Windows another file seems to be required
|
||||||
|
// https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
|
||||||
|
// This file seems to contain the mapping of Windows time zone name to IANA
|
||||||
|
// time zone names.
|
||||||
|
//
|
||||||
|
// However this article mentions another way to do the mapping on Windows
|
||||||
|
// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255
|
||||||
|
// This requires Windows 10 Version 1903, which was released in May of 2019
|
||||||
|
// and considered end of life in December 2020
|
||||||
|
// https://learn.microsoft.com/en-us/lifecycle/announcements/windows-10-1903-end-of-servicing
|
||||||
|
//
|
||||||
|
// TODO TZDB Implement the Windows mapping in tzdb::current_zone
|
||||||
|
|
||||||
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
namespace chrono {
|
||||||
|
|
||||||
|
// This function is weak so it can be overriden in the tests. The
|
||||||
|
// declaration is in the test header test/support/test_tzdb.h
|
||||||
|
_LIBCPP_WEAK string_view __libcpp_tzdb_directory() {
|
||||||
|
#if defined(__linux__)
|
||||||
|
return "/usr/share/zoneinfo/";
|
||||||
|
#else
|
||||||
|
# error "unknown path to the IANA Time Zone Database"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Details
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
[[nodiscard]] static bool __is_whitespace(int __c) { return __c == ' ' || __c == '\t'; }
|
||||||
|
|
||||||
|
static void __skip_optional_whitespace(istream& __input) {
|
||||||
|
while (chrono::__is_whitespace(__input.peek()))
|
||||||
|
__input.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __skip_mandatory_whitespace(istream& __input) {
|
||||||
|
if (!chrono::__is_whitespace(__input.get()))
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static bool __is_eol(int __c) { return __c == '\n' || __c == std::char_traits<char>::eof(); }
|
||||||
|
|
||||||
|
static void __skip_line(istream& __input) {
|
||||||
|
while (!chrono::__is_eol(__input.peek())) {
|
||||||
|
__input.get();
|
||||||
|
}
|
||||||
|
__input.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __skip(istream& __input, char __suffix) {
|
||||||
|
if (std::tolower(__input.peek()) == __suffix)
|
||||||
|
__input.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __skip(istream& __input, string_view __suffix) {
|
||||||
|
for (auto __c : __suffix)
|
||||||
|
if (std::tolower(__input.peek()) == __c)
|
||||||
|
__input.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __matches(istream& __input, char __expected) {
|
||||||
|
if (std::tolower(__input.get()) != __expected)
|
||||||
|
std::__throw_runtime_error((string("corrupt tzdb: expected character '") + __expected + '\'').c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __matches(istream& __input, string_view __expected) {
|
||||||
|
for (auto __c : __expected)
|
||||||
|
if (std::tolower(__input.get()) != __c)
|
||||||
|
std::__throw_runtime_error((string("corrupt tzdb: expected string '") + string(__expected) + '\'').c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static string __parse_string(istream& __input) {
|
||||||
|
string __result;
|
||||||
|
while (true) {
|
||||||
|
int __c = __input.get();
|
||||||
|
switch (__c) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\n':
|
||||||
|
__input.unget();
|
||||||
|
[[fallthrough]];
|
||||||
|
case istream::traits_type::eof():
|
||||||
|
if (__result.empty())
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: expected a string");
|
||||||
|
|
||||||
|
return __result;
|
||||||
|
|
||||||
|
default:
|
||||||
|
__result.push_back(__c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static int64_t __parse_integral(istream& __input, bool __leading_zero_allowed) {
|
||||||
|
int64_t __result = __input.get();
|
||||||
|
if (__leading_zero_allowed) {
|
||||||
|
if (__result < '0' || __result > '9')
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: expected a digit");
|
||||||
|
} else {
|
||||||
|
if (__result < '1' || __result > '9')
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: expected a non-zero digit");
|
||||||
|
}
|
||||||
|
__result -= '0';
|
||||||
|
while (true) {
|
||||||
|
if (__input.peek() < '0' || __input.peek() > '9')
|
||||||
|
return __result;
|
||||||
|
|
||||||
|
// In order to avoid possible overflows we limit the accepted range.
|
||||||
|
// Most values parsed are expected to be very small:
|
||||||
|
// - 8784 hours in a year
|
||||||
|
// - 31 days in a month
|
||||||
|
// - year no real maximum, these values are expected to be less than
|
||||||
|
// the range of the year type.
|
||||||
|
//
|
||||||
|
// However the leapseconds use a seconds after epoch value. Using an
|
||||||
|
// int would run into an overflow in 2038. By using a 64-bit value
|
||||||
|
// the range is large enough for the bilions of years. Limiting that
|
||||||
|
// range slightly to make the code easier is not an issue.
|
||||||
|
if (__result > (std::numeric_limits<int64_t>::max() / 16))
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: integral too large");
|
||||||
|
|
||||||
|
__result *= 10;
|
||||||
|
__result += __input.get() - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Calendar
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
[[nodiscard]] static day __parse_day(istream& __input) {
|
||||||
|
unsigned __result = chrono::__parse_integral(__input, false);
|
||||||
|
if (__result > 31)
|
||||||
|
std::__throw_runtime_error("corrupt tzdb day: value too large");
|
||||||
|
return day{__result};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static weekday __parse_weekday(istream& __input) {
|
||||||
|
// TZDB allows the shortest unique name.
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'f':
|
||||||
|
chrono::__skip(__input, "riday");
|
||||||
|
return Friday;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
chrono::__skip(__input, "onday");
|
||||||
|
return Monday;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'a':
|
||||||
|
chrono::__skip(__input, "turday");
|
||||||
|
return Saturday;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
chrono::__skip(__input, "nday");
|
||||||
|
return Sunday;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'h':
|
||||||
|
chrono::__skip(__input, "ursday");
|
||||||
|
return Thursday;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
chrono::__skip(__input, "esday");
|
||||||
|
return Tuesday;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
chrono::__skip(__input, "ednesday");
|
||||||
|
return Wednesday;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::__throw_runtime_error("corrupt tzdb weekday: invalid name");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static month __parse_month(istream& __input) {
|
||||||
|
// TZDB allows the shortest unique name.
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'a':
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'p':
|
||||||
|
chrono::__skip(__input, "ril");
|
||||||
|
return April;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
chrono::__skip(__input, "gust");
|
||||||
|
return August;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
chrono::__skip(__input, "ecember");
|
||||||
|
return December;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
chrono::__skip(__input, "ebruary");
|
||||||
|
return February;
|
||||||
|
|
||||||
|
case 'j':
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'a':
|
||||||
|
chrono::__skip(__input, "nuary");
|
||||||
|
return January;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'n':
|
||||||
|
chrono::__skip(__input, 'e');
|
||||||
|
return June;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
chrono::__skip(__input, 'y');
|
||||||
|
return July;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
if (std::tolower(__input.get()) == 'a')
|
||||||
|
switch (std::tolower(__input.get())) {
|
||||||
|
case 'y':
|
||||||
|
return May;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
chrono::__skip(__input, "ch");
|
||||||
|
return March;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
chrono::__skip(__input, "ovember");
|
||||||
|
return November;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
chrono::__skip(__input, "ctober");
|
||||||
|
return October;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
chrono::__skip(__input, "eptember");
|
||||||
|
return September;
|
||||||
|
}
|
||||||
|
std::__throw_runtime_error("corrupt tzdb month: invalid name");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static year __parse_year_value(istream& __input) {
|
||||||
|
bool __negative = __input.peek() == '-';
|
||||||
|
if (__negative) [[unlikely]]
|
||||||
|
__input.get();
|
||||||
|
|
||||||
|
int64_t __result = __parse_integral(__input, true);
|
||||||
|
if (__result > static_cast<int>(year::max())) {
|
||||||
|
if (__negative)
|
||||||
|
std::__throw_runtime_error("corrupt tzdb year: year is less than the minimum");
|
||||||
|
|
||||||
|
std::__throw_runtime_error("corrupt tzdb year: year is greater than the maximum");
|
||||||
|
}
|
||||||
|
|
||||||
|
return year{static_cast<int>(__negative ? -__result : __result)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static year __parse_year(istream& __input) {
|
||||||
|
if (std::tolower(__input.peek()) != 'm') [[likely]]
|
||||||
|
return chrono::__parse_year_value(__input);
|
||||||
|
|
||||||
|
__input.get();
|
||||||
|
switch (std::tolower(__input.peek())) {
|
||||||
|
case 'i':
|
||||||
|
__input.get();
|
||||||
|
chrono::__skip(__input, 'n');
|
||||||
|
[[fallthrough]];
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
// The m is minimum, even when that is ambiguous.
|
||||||
|
return year::min();
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
__input.get();
|
||||||
|
chrono::__skip(__input, 'x');
|
||||||
|
return year::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::__throw_runtime_error("corrupt tzdb year: expected 'min' or 'max'");
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// TZDB fields
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
[[nodiscard]] static year __parse_to(istream& __input, year __only) {
|
||||||
|
if (std::tolower(__input.peek()) != 'o')
|
||||||
|
return chrono::__parse_year(__input);
|
||||||
|
|
||||||
|
__input.get();
|
||||||
|
chrono::__skip(__input, "nly");
|
||||||
|
return __only;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__constrained_weekday::__comparison_t __parse_comparison(istream& __input) {
|
||||||
|
switch (__input.get()) {
|
||||||
|
case '>':
|
||||||
|
chrono::__matches(__input, '=');
|
||||||
|
return __tz::__constrained_weekday::__ge;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
chrono::__matches(__input, '=');
|
||||||
|
return __tz::__constrained_weekday::__le;
|
||||||
|
}
|
||||||
|
std::__throw_runtime_error("corrupt tzdb on: expected '>=' or '<='");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__on __parse_on(istream& __input) {
|
||||||
|
if (std::isdigit(__input.peek()))
|
||||||
|
return chrono::__parse_day(__input);
|
||||||
|
|
||||||
|
if (std::tolower(__input.peek()) == 'l') {
|
||||||
|
chrono::__matches(__input, "last");
|
||||||
|
return weekday_last(chrono::__parse_weekday(__input));
|
||||||
|
}
|
||||||
|
|
||||||
|
return __tz::__constrained_weekday{
|
||||||
|
chrono::__parse_weekday(__input), chrono::__parse_comparison(__input), chrono::__parse_day(__input)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static seconds __parse_duration(istream& __input) {
|
||||||
|
seconds __result{0};
|
||||||
|
int __c = __input.peek();
|
||||||
|
bool __negative = __c == '-';
|
||||||
|
if (__negative) {
|
||||||
|
__input.get();
|
||||||
|
// Negative is either a negative value or a single -.
|
||||||
|
// The latter means 0 and the parsing is complete.
|
||||||
|
if (!std::isdigit(__input.peek()))
|
||||||
|
return __result;
|
||||||
|
}
|
||||||
|
|
||||||
|
__result += hours(__parse_integral(__input, true));
|
||||||
|
if (__input.peek() != ':')
|
||||||
|
return __negative ? -__result : __result;
|
||||||
|
|
||||||
|
__input.get();
|
||||||
|
__result += minutes(__parse_integral(__input, true));
|
||||||
|
if (__input.peek() != ':')
|
||||||
|
return __negative ? -__result : __result;
|
||||||
|
|
||||||
|
__input.get();
|
||||||
|
__result += seconds(__parse_integral(__input, true));
|
||||||
|
if (__input.peek() != '.')
|
||||||
|
return __negative ? -__result : __result;
|
||||||
|
|
||||||
|
__input.get();
|
||||||
|
(void)__parse_integral(__input, true); // Truncate the digits.
|
||||||
|
|
||||||
|
return __negative ? -__result : __result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__clock __parse_clock(istream& __input) {
|
||||||
|
switch (__input.get()) { // case sensitive
|
||||||
|
case 'w':
|
||||||
|
return __tz::__clock::__local;
|
||||||
|
case 's':
|
||||||
|
return __tz::__clock::__standard;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
case 'g':
|
||||||
|
case 'z':
|
||||||
|
return __tz::__clock::__universal;
|
||||||
|
}
|
||||||
|
|
||||||
|
__input.unget();
|
||||||
|
return __tz::__clock::__local;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static bool __parse_dst(istream& __input, seconds __offset) {
|
||||||
|
switch (__input.get()) { // case sensitive
|
||||||
|
case 's':
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__input.unget();
|
||||||
|
return __offset != 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__at __parse_at(istream& __input) {
|
||||||
|
return {__parse_duration(__input), __parse_clock(__input)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__save __parse_save(istream& __input) {
|
||||||
|
seconds __time = chrono::__parse_duration(__input);
|
||||||
|
return {__time, chrono::__parse_dst(__input, __time)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static string __parse_letters(istream& __input) {
|
||||||
|
string __result = __parse_string(__input);
|
||||||
|
// Canonicalize "-" to "" since they are equivalent in the specification.
|
||||||
|
return __result != "-" ? __result : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__continuation::__rules_t __parse_rules(istream& __input) {
|
||||||
|
int __c = __input.peek();
|
||||||
|
// A single - is not a SAVE but a special case.
|
||||||
|
if (__c == '-') {
|
||||||
|
__input.get();
|
||||||
|
if (chrono::__is_whitespace(__input.peek()))
|
||||||
|
return monostate{};
|
||||||
|
__input.unget();
|
||||||
|
return chrono::__parse_save(__input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::isdigit(__c) || __c == '+')
|
||||||
|
return chrono::__parse_save(__input);
|
||||||
|
|
||||||
|
return chrono::__parse_string(__input);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static __tz::__continuation __parse_continuation(__tz::__rules_storage_type& __rules, istream& __input) {
|
||||||
|
__tz::__continuation __result;
|
||||||
|
|
||||||
|
__result.__rule_database_ = std::addressof(__rules);
|
||||||
|
|
||||||
|
// Note STDOFF is specified as
|
||||||
|
// This field has the same format as the AT and SAVE fields of rule lines;
|
||||||
|
// These fields have different suffix letters, these letters seem
|
||||||
|
// not to be used so do not allow any of them.
|
||||||
|
|
||||||
|
__result.__stdoff = chrono::__parse_duration(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__result.__rules = chrono::__parse_rules(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__result.__format = chrono::__parse_string(__input);
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
|
||||||
|
if (chrono::__is_eol(__input.peek()))
|
||||||
|
return __result;
|
||||||
|
__result.__year = chrono::__parse_year(__input);
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
|
||||||
|
if (chrono::__is_eol(__input.peek()))
|
||||||
|
return __result;
|
||||||
|
__result.__in = chrono::__parse_month(__input);
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
|
||||||
|
if (chrono::__is_eol(__input.peek()))
|
||||||
|
return __result;
|
||||||
|
__result.__on = chrono::__parse_on(__input);
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
|
||||||
|
if (chrono::__is_eol(__input.peek()))
|
||||||
|
return __result;
|
||||||
|
__result.__at = __parse_at(__input);
|
||||||
|
|
||||||
|
return __result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Time Zone Database entries
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static string __parse_version(istream& __input) {
|
||||||
|
// The first line in tzdata.zi contains
|
||||||
|
// # version YYYYw
|
||||||
|
// The parser expects this pattern
|
||||||
|
// #\s*version\s*\(.*)
|
||||||
|
// This part is not documented.
|
||||||
|
chrono::__matches(__input, '#');
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
chrono::__matches(__input, "version");
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
return chrono::__parse_string(__input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __parse_rule(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) {
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
string __name = chrono::__parse_string(__input);
|
||||||
|
|
||||||
|
if (__rules.empty() || __rules.back().first != __name)
|
||||||
|
__rules.emplace_back(__name, vector<__tz::__rule>{});
|
||||||
|
|
||||||
|
__tz::__rule& __rule = __rules.back().second.emplace_back();
|
||||||
|
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__from = chrono::__parse_year(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__to = chrono::__parse_to(__input, __rule.__from);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
chrono::__matches(__input, '-');
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__in = chrono::__parse_month(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__on = chrono::__parse_on(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__at = __parse_at(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__save = __parse_save(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
__rule.__letters = chrono::__parse_letters(__input);
|
||||||
|
chrono::__skip_line(__input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __parse_zone(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) {
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
auto __p = std::make_unique<time_zone::__impl>(chrono::__parse_string(__input));
|
||||||
|
vector<__tz::__continuation>& __continuations = __p->__continuations();
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
|
||||||
|
do {
|
||||||
|
// The first line must be valid, continuations are optional.
|
||||||
|
__continuations.emplace_back(__parse_continuation(__rules, __input));
|
||||||
|
chrono::__skip_line(__input);
|
||||||
|
chrono::__skip_optional_whitespace(__input);
|
||||||
|
} while (std::isdigit(__input.peek()) || __input.peek() == '-');
|
||||||
|
|
||||||
|
__tzdb.zones.emplace_back(time_zone::__create(std::move(__p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __parse_link(tzdb& __tzdb, istream& __input) {
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
string __target = chrono::__parse_string(__input);
|
||||||
|
chrono::__skip_mandatory_whitespace(__input);
|
||||||
|
string __name = chrono::__parse_string(__input);
|
||||||
|
chrono::__skip_line(__input);
|
||||||
|
|
||||||
|
__tzdb.links.emplace_back(time_zone_link::__constructor_tag{}, std::move(__name), std::move(__target));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istream& __input) {
|
||||||
|
while (true) {
|
||||||
|
int __c = std::tolower(__input.get());
|
||||||
|
|
||||||
|
switch (__c) {
|
||||||
|
case istream::traits_type::eof():
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
chrono::__skip_line(__input);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
chrono::__skip(__input, "ule");
|
||||||
|
chrono::__parse_rule(__db, __rules, __input);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'z':
|
||||||
|
chrono::__skip(__input, "one");
|
||||||
|
chrono::__parse_zone(__db, __rules, __input);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
chrono::__skip(__input, "ink");
|
||||||
|
chrono::__parse_link(__db, __input);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::__throw_runtime_error("corrupt tzdb: unexpected input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
|
||||||
|
filesystem::path __root = chrono::__libcpp_tzdb_directory();
|
||||||
|
ifstream __tzdata{__root / "tzdata.zi"};
|
||||||
|
|
||||||
|
__tzdb.version = chrono::__parse_version(__tzdata);
|
||||||
|
chrono::__parse_tzdata(__tzdb, __rules, __tzdata);
|
||||||
|
std::ranges::sort(__tzdb.zones);
|
||||||
|
std::ranges::sort(__tzdb.links);
|
||||||
|
std::ranges::sort(__rules, {}, [](const auto& p) { return p.first; });
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Public API
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI tzdb_list& get_tzdb_list() {
|
||||||
|
static tzdb_list __result{new tzdb_list::__impl()};
|
||||||
|
return __result;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const tzdb& reload_tzdb() {
|
||||||
|
if (chrono::remote_version() == chrono::get_tzdb().version)
|
||||||
|
return chrono::get_tzdb();
|
||||||
|
|
||||||
|
return chrono::get_tzdb_list().__implementation().__load();
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI string remote_version() {
|
||||||
|
filesystem::path __root = chrono::__libcpp_tzdb_directory();
|
||||||
|
ifstream __tzdata{__root / "tzdata.zi"};
|
||||||
|
return chrono::__parse_version(__tzdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chrono
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
@ -10,76 +10,12 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include <__mutex/unique_lock.h>
|
#include "include/tzdb/tzdb_list_private.h"
|
||||||
#include <forward_list>
|
|
||||||
|
|
||||||
// When threads are not available the locking is not required.
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
# include <shared_mutex>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
namespace chrono {
|
namespace chrono {
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Private API
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
class tzdb_list::__impl {
|
|
||||||
public:
|
|
||||||
explicit __impl(tzdb&& __tzdb) { __tzdb_.push_front(std::move(__tzdb)); }
|
|
||||||
|
|
||||||
using const_iterator = tzdb_list::const_iterator;
|
|
||||||
|
|
||||||
const tzdb& front() const noexcept {
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
shared_lock __lock{__mutex_};
|
|
||||||
#endif
|
|
||||||
return __tzdb_.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator erase_after(const_iterator __p) {
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
unique_lock __lock{__mutex_};
|
|
||||||
#endif
|
|
||||||
return __tzdb_.erase_after(__p);
|
|
||||||
}
|
|
||||||
|
|
||||||
tzdb& __emplace_front(tzdb&& __tzdb) {
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
unique_lock __lock{__mutex_};
|
|
||||||
#endif
|
|
||||||
return __tzdb_.emplace_front(std::move(__tzdb));
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator begin() const noexcept {
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
shared_lock __lock{__mutex_};
|
|
||||||
#endif
|
|
||||||
return __tzdb_.begin();
|
|
||||||
}
|
|
||||||
const_iterator end() const noexcept {
|
|
||||||
// forward_list<T>::end does not access the list, so no need to take a lock.
|
|
||||||
return __tzdb_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator cbegin() const noexcept { return begin(); }
|
|
||||||
const_iterator cend() const noexcept { return end(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
|
||||||
mutable shared_mutex __mutex_;
|
|
||||||
#endif
|
|
||||||
forward_list<tzdb> __tzdb_;
|
|
||||||
};
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Public API
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI tzdb_list::tzdb_list(tzdb&& __tzdb) : __impl_{new __impl(std::move(__tzdb))} {}
|
|
||||||
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI tzdb_list::~tzdb_list() { delete __impl_; }
|
_LIBCPP_EXPORTED_FROM_ABI tzdb_list::~tzdb_list() { delete __impl_; }
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const tzdb& tzdb_list::front() const noexcept {
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const tzdb& tzdb_list::front() const noexcept {
|
||||||
@ -90,10 +26,6 @@ _LIBCPP_EXPORTED_FROM_ABI tzdb_list::const_iterator tzdb_list::erase_after(const
|
|||||||
return __impl_->erase_after(__p);
|
return __impl_->erase_after(__p);
|
||||||
}
|
}
|
||||||
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI tzdb& tzdb_list::__emplace_front(tzdb&& __tzdb) {
|
|
||||||
return __impl_->__emplace_front(std::move(__tzdb));
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI tzdb_list::const_iterator tzdb_list::begin() const noexcept {
|
_LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI tzdb_list::const_iterator tzdb_list::begin() const noexcept {
|
||||||
return __impl_->begin();
|
return __impl_->begin();
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
|
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
// These types have "private" constructors.
|
||||||
|
extern std::chrono::time_zone tz;
|
||||||
|
extern std::chrono::time_zone_link link;
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
|
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
|
||||||
list.front();
|
list.front();
|
||||||
@ -34,4 +38,17 @@ void test() {
|
|||||||
std::chrono::get_tzdb_list();
|
std::chrono::get_tzdb_list();
|
||||||
std::chrono::get_tzdb();
|
std::chrono::get_tzdb();
|
||||||
std::chrono::remote_version();
|
std::chrono::remote_version();
|
||||||
|
|
||||||
|
{
|
||||||
|
tz.name();
|
||||||
|
operator==(tz, tz);
|
||||||
|
operator<=>(tz, tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
link.name();
|
||||||
|
link.target();
|
||||||
|
operator==(link, link);
|
||||||
|
operator<=>(link, link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
|
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
// These types have "private" constructors.
|
||||||
|
extern std::chrono::time_zone tz;
|
||||||
|
extern std::chrono::time_zone_link link;
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
|
std::chrono::tzdb_list& list = std::chrono::get_tzdb_list();
|
||||||
list.front(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
list.front(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
@ -32,4 +36,19 @@ void test() {
|
|||||||
crno::get_tzdb_list(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
crno::get_tzdb_list(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
crno::get_tzdb(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
crno::get_tzdb(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
crno::remote_version(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
crno::remote_version(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
|
||||||
|
{
|
||||||
|
tz.name(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
operator==(tz, tz); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
operator<=>(tz, tz); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
link.name(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
link.target(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
operator==(link, link);
|
||||||
|
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||||
|
operator<=>(link, link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
102
libcxx/test/libcxx/time/time.zone/time.zone.db/links.pass.cpp
Normal file
102
libcxx/test/libcxx/time/time.zone/time.zone.db/links.pass.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// Tests the IANA database rules links and operations.
|
||||||
|
// This is not part of the public tzdb interface.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "assert_macros.h"
|
||||||
|
#include "concat_macros.h"
|
||||||
|
#include "filesystem_test_helper.h"
|
||||||
|
#include "test_tzdb.h"
|
||||||
|
|
||||||
|
scoped_test_env env;
|
||||||
|
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||||
|
const std::filesystem::path file = env.create_file("zoneinfo/tzdata.zi");
|
||||||
|
|
||||||
|
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||||
|
static std::string result = dir.string();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(std::string_view input) {
|
||||||
|
static int version = 0;
|
||||||
|
|
||||||
|
std::ofstream f{file};
|
||||||
|
f << "# version " << version++ << '\n';
|
||||||
|
f.write(input.data(), input.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::chrono::tzdb& parse(std::string_view input) {
|
||||||
|
write(input);
|
||||||
|
return std::chrono::reload_tzdb();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_exception(std::string_view input, [[maybe_unused]] std::string_view what) {
|
||||||
|
write(input);
|
||||||
|
|
||||||
|
TEST_VALIDATE_EXCEPTION(
|
||||||
|
std::runtime_error,
|
||||||
|
[&]([[maybe_unused]] const std::runtime_error& e) {
|
||||||
|
TEST_LIBCPP_REQUIRE(
|
||||||
|
e.what() == what,
|
||||||
|
TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||||
|
},
|
||||||
|
TEST_IGNORE_NODISCARD std::chrono::reload_tzdb());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_invalid() {
|
||||||
|
test_exception("L", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("L ", "corrupt tzdb: expected a string");
|
||||||
|
|
||||||
|
test_exception("L n", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("L n ", "corrupt tzdb: expected a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_link() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
L z d
|
||||||
|
l b a
|
||||||
|
lInK b b
|
||||||
|
)");
|
||||||
|
assert(result.links.size() == 3);
|
||||||
|
|
||||||
|
assert(result.links[0].name() == "a");
|
||||||
|
assert(result.links[0].target() == "b");
|
||||||
|
|
||||||
|
assert(result.links[1].name() == "b");
|
||||||
|
assert(result.links[1].target() == "b");
|
||||||
|
|
||||||
|
assert(result.links[2].name() == "d");
|
||||||
|
assert(result.links[2].target() == "z");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
test_invalid();
|
||||||
|
test_link();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
565
libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
Normal file
565
libcxx/test/libcxx/time/time.zone/time.zone.db/rules.pass.cpp
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// Tests the IANA database rules parsing and operations.
|
||||||
|
// This is not part of the public tzdb interface.
|
||||||
|
// The test uses private implementation headers.
|
||||||
|
// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../../src/include
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "assert_macros.h"
|
||||||
|
#include "concat_macros.h"
|
||||||
|
#include "filesystem_test_helper.h"
|
||||||
|
#include "test_tzdb.h"
|
||||||
|
|
||||||
|
// headers in the dylib
|
||||||
|
#include "tzdb/types_private.h"
|
||||||
|
#include "tzdb/tzdb_private.h"
|
||||||
|
|
||||||
|
scoped_test_env env;
|
||||||
|
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||||
|
const std::filesystem::path file = env.create_file("zoneinfo/tzdata.zi");
|
||||||
|
|
||||||
|
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||||
|
static std::string result = dir.string();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write(std::string_view input) {
|
||||||
|
static int version = 0;
|
||||||
|
|
||||||
|
std::ofstream f{file};
|
||||||
|
f << "# version " << version++ << '\n';
|
||||||
|
f.write(input.data(), input.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parse_result {
|
||||||
|
explicit parse_result(std::string_view input) {
|
||||||
|
write(input);
|
||||||
|
std::chrono::tzdb tzdb; // result not needed for the tests.
|
||||||
|
std::chrono::__init_tzdb(tzdb, rules);
|
||||||
|
}
|
||||||
|
std::chrono::__tz::__rules_storage_type rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_exception(std::string_view input, [[maybe_unused]] std::string_view what) {
|
||||||
|
write(input);
|
||||||
|
|
||||||
|
TEST_VALIDATE_EXCEPTION(
|
||||||
|
std::runtime_error,
|
||||||
|
[&]([[maybe_unused]] const std::runtime_error& e) {
|
||||||
|
TEST_LIBCPP_REQUIRE(
|
||||||
|
e.what() == what,
|
||||||
|
TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||||
|
},
|
||||||
|
TEST_IGNORE_NODISCARD std::chrono::reload_tzdb());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_invalid() {
|
||||||
|
test_exception("R", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R ", "corrupt tzdb: expected a string");
|
||||||
|
|
||||||
|
test_exception("R r", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r x", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("R r +", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("R r mx", "corrupt tzdb year: expected 'min' or 'max'");
|
||||||
|
test_exception("R r -32768", "corrupt tzdb year: year is less than the minimum");
|
||||||
|
test_exception("R r 32768", "corrupt tzdb year: year is greater than the maximum");
|
||||||
|
|
||||||
|
test_exception("R r mix", "corrupt tzdb: expected whitespace");
|
||||||
|
test_exception("R r 0", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 x", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("R r 0 +", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("R r 0 mx", "corrupt tzdb year: expected 'min' or 'max'");
|
||||||
|
|
||||||
|
test_exception("R r 0 mix", "corrupt tzdb: expected whitespace");
|
||||||
|
test_exception("R r 0 1", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 X", "corrupt tzdb: expected character '-'");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 -", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - j", "corrupt tzdb month: invalid name");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja +", "corrupt tzdb weekday: invalid name");
|
||||||
|
test_exception("R r 0 1 - Ja 32", "corrupt tzdb day: value too large");
|
||||||
|
test_exception("R r 0 1 - Ja l", "corrupt tzdb: expected string 'last'");
|
||||||
|
test_exception("R r 0 1 - Ja last", "corrupt tzdb weekday: invalid name");
|
||||||
|
test_exception("R r 0 1 - Ja lastS", "corrupt tzdb weekday: invalid name");
|
||||||
|
test_exception("R r 0 1 - Ja S", "corrupt tzdb weekday: invalid name");
|
||||||
|
test_exception("R r 0 1 - Ja Su", "corrupt tzdb on: expected '>=' or '<='");
|
||||||
|
test_exception("R r 0 1 - Ja Su>", "corrupt tzdb: expected character '='");
|
||||||
|
test_exception("R r 0 1 - Ja Su<", "corrupt tzdb: expected character '='");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=+", "corrupt tzdb: expected a non-zero digit");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=0", "corrupt tzdb: expected a non-zero digit");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=32", "corrupt tzdb day: value too large");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 ", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 +", "corrupt tzdb: expected a digit");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1", "corrupt tzdb: expected whitespace");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1a", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1w 2", "corrupt tzdb: expected whitespace");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1w 2a", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1w 2s", "corrupt tzdb: expected whitespace");
|
||||||
|
test_exception("R r 0 1 - Ja Su>=31 1w 2s ", "corrupt tzdb: expected a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_name() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
R z 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
rULE z 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
RuLe z 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 2);
|
||||||
|
assert(result.rules[0].first == "a");
|
||||||
|
assert(result.rules[0].second.size() == 2);
|
||||||
|
assert(result.rules[1].first == "z");
|
||||||
|
assert(result.rules[1].second.size() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_from() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# min abbreviations
|
||||||
|
R a M 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a mI 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a mIN 1 - Ja Su>=31 1w 2s -
|
||||||
|
|
||||||
|
# max abbrviations
|
||||||
|
R a MA 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a mAx 1 - Ja Su>=31 1w 2s -
|
||||||
|
|
||||||
|
R a -1000 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a -100 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0000 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 100 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 1000 1 - Ja Su>=31 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 10);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[0].__from == std::chrono::year::min());
|
||||||
|
assert(result.rules[0].second[1].__from == std::chrono::year::min());
|
||||||
|
assert(result.rules[0].second[2].__from == std::chrono::year::min());
|
||||||
|
|
||||||
|
assert(result.rules[0].second[3].__from == std::chrono::year::max());
|
||||||
|
assert(result.rules[0].second[4].__from == std::chrono::year::max());
|
||||||
|
|
||||||
|
assert(result.rules[0].second[5].__from == std::chrono::year(-1000));
|
||||||
|
assert(result.rules[0].second[6].__from == std::chrono::year(-100));
|
||||||
|
assert(result.rules[0].second[7].__from == std::chrono::year(0));
|
||||||
|
assert(result.rules[0].second[8].__from == std::chrono::year(100));
|
||||||
|
assert(result.rules[0].second[9].__from == std::chrono::year(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_to() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# min abbreviations
|
||||||
|
R a 0 m - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 mi - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 min - Ja Su>=31 1w 2s -
|
||||||
|
|
||||||
|
# max abbrviations
|
||||||
|
R a 0 ma - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 max - Ja Su>=31 1w 2s -
|
||||||
|
|
||||||
|
R a 0 -1000 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 -100 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 0000 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 100 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 1000 - Ja Su>=31 1w 2s -
|
||||||
|
|
||||||
|
# only abbreviations
|
||||||
|
R a m O - Ja Su>=31 1w 2s -
|
||||||
|
R a ma oN - Ja Su>=31 1w 2s -
|
||||||
|
R a -100 onL - Ja Su>=31 1w 2s -
|
||||||
|
R a 100 oNlY - Ja Su>=31 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 14);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[0].__to == std::chrono::year::min());
|
||||||
|
assert(result.rules[0].second[1].__to == std::chrono::year::min());
|
||||||
|
assert(result.rules[0].second[2].__to == std::chrono::year::min());
|
||||||
|
|
||||||
|
assert(result.rules[0].second[3].__to == std::chrono::year::max());
|
||||||
|
assert(result.rules[0].second[4].__to == std::chrono::year::max());
|
||||||
|
|
||||||
|
assert(result.rules[0].second[5].__to == std::chrono::year(-1000));
|
||||||
|
assert(result.rules[0].second[6].__to == std::chrono::year(-100));
|
||||||
|
assert(result.rules[0].second[7].__to == std::chrono::year(0));
|
||||||
|
assert(result.rules[0].second[8].__to == std::chrono::year(100));
|
||||||
|
assert(result.rules[0].second[9].__to == std::chrono::year(1000));
|
||||||
|
|
||||||
|
assert(result.rules[0].second[10].__to == std::chrono::year::min());
|
||||||
|
assert(result.rules[0].second[11].__to == std::chrono::year::max());
|
||||||
|
assert(result.rules[0].second[12].__to == std::chrono::year(-100));
|
||||||
|
assert(result.rules[0].second[13].__to == std::chrono::year(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_in() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# All tests in alphabetic order to validate shortest unique abbreviation
|
||||||
|
|
||||||
|
# Shortest abbreviation valid
|
||||||
|
R s 0 1 - ap Su>=31 1w 2s -
|
||||||
|
R s 0 1 - au Su>=31 1w 2s -
|
||||||
|
R s 0 1 - d Su>=31 1w 2s -
|
||||||
|
R s 0 1 - f Su>=31 1w 2s -
|
||||||
|
R s 0 1 - ja Su>=31 1w 2s -
|
||||||
|
R s 0 1 - jul Su>=31 1w 2s -
|
||||||
|
R s 0 1 - jun Su>=31 1w 2s -
|
||||||
|
R s 0 1 - May Su>=31 1w 2s -
|
||||||
|
R s 0 1 - mar Su>=31 1w 2s -
|
||||||
|
R s 0 1 - n Su>=31 1w 2s -
|
||||||
|
R s 0 1 - o Su>=31 1w 2s -
|
||||||
|
R s 0 1 - s Su>=31 1w 2s -
|
||||||
|
|
||||||
|
# 3 letter abbreviation
|
||||||
|
R a 0 1 - APR Su>=31 1w 2s -
|
||||||
|
R a 0 1 - AUG Su>=31 1w 2s -
|
||||||
|
R a 0 1 - DEC Su>=31 1w 2s -
|
||||||
|
R a 0 1 - FEB Su>=31 1w 2s -
|
||||||
|
R a 0 1 - JAN Su>=31 1w 2s -
|
||||||
|
R a 0 1 - JUL Su>=31 1w 2s -
|
||||||
|
R a 0 1 - JUN Su>=31 1w 2s -
|
||||||
|
R a 0 1 - MAY Su>=31 1w 2s -
|
||||||
|
R a 0 1 - MAR Su>=31 1w 2s -
|
||||||
|
R a 0 1 - NOV Su>=31 1w 2s -
|
||||||
|
R a 0 1 - OCT Su>=31 1w 2s -
|
||||||
|
R a 0 1 - SEP Su>=31 1w 2s -
|
||||||
|
|
||||||
|
# Full names
|
||||||
|
R f 0 1 - ApRiL Su>=31 1w 2s -
|
||||||
|
R f 0 1 - AuGuSt Su>=31 1w 2s -
|
||||||
|
R f 0 1 - DeCeMber Su>=31 1w 2s -
|
||||||
|
R f 0 1 - FeBrUary Su>=31 1w 2s -
|
||||||
|
R f 0 1 - JaNuAry Su>=31 1w 2s -
|
||||||
|
R f 0 1 - JuLy Su>=31 1w 2s -
|
||||||
|
R f 0 1 - JuNe Su>=31 1w 2s -
|
||||||
|
R f 0 1 - MaY Su>=31 1w 2s -
|
||||||
|
R f 0 1 - MaRch Su>=31 1w 2s -
|
||||||
|
R f 0 1 - NoVemBeR Su>=31 1w 2s -
|
||||||
|
R f 0 1 - OcTobEr Su>=31 1w 2s -
|
||||||
|
R f 0 1 - SePteMbEr Su>=31 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 3);
|
||||||
|
for (std::size_t i = 0; i < result.rules.size(); ++i) {
|
||||||
|
assert(result.rules[i].second.size() == 12);
|
||||||
|
|
||||||
|
assert(result.rules[i].second[0].__in == std::chrono::April);
|
||||||
|
assert(result.rules[i].second[1].__in == std::chrono::August);
|
||||||
|
assert(result.rules[i].second[2].__in == std::chrono::December);
|
||||||
|
assert(result.rules[i].second[3].__in == std::chrono::February);
|
||||||
|
assert(result.rules[i].second[4].__in == std::chrono::January);
|
||||||
|
assert(result.rules[i].second[5].__in == std::chrono::July);
|
||||||
|
assert(result.rules[i].second[6].__in == std::chrono::June);
|
||||||
|
assert(result.rules[i].second[7].__in == std::chrono::May);
|
||||||
|
assert(result.rules[i].second[8].__in == std::chrono::March);
|
||||||
|
assert(result.rules[i].second[9].__in == std::chrono::November);
|
||||||
|
assert(result.rules[i].second[10].__in == std::chrono::October);
|
||||||
|
assert(result.rules[i].second[11].__in == std::chrono::September);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_on_day() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# The parser does not validate the day as valid day of month
|
||||||
|
R a 0 1 - Fe 1 1w 2s -
|
||||||
|
R a 0 1 - Fe 10 1w 2s -
|
||||||
|
R a 0 1 - Fe 20 1w 2s -
|
||||||
|
R a 0 1 - Fe 30 1w 2s -
|
||||||
|
R a 0 1 - Fe 31 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 5);
|
||||||
|
assert(std::get<std::chrono::day>(result.rules[0].second[0].__on) == std::chrono::day(1));
|
||||||
|
assert(std::get<std::chrono::day>(result.rules[0].second[1].__on) == std::chrono::day(10));
|
||||||
|
assert(std::get<std::chrono::day>(result.rules[0].second[2].__on) == std::chrono::day(20));
|
||||||
|
assert(std::get<std::chrono::day>(result.rules[0].second[3].__on) == std::chrono::day(30));
|
||||||
|
assert(std::get<std::chrono::day>(result.rules[0].second[4].__on) == std::chrono::day(31));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_on_last() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# All tests in alphabetic order to validate shortest unique abbreviation
|
||||||
|
|
||||||
|
# Shortest abbreviation valid
|
||||||
|
R s 0 1 - Ja lastF 1w 2s -
|
||||||
|
R s 0 1 - Ja lastM 1w 2s -
|
||||||
|
R s 0 1 - Ja lastSa 1w 2s -
|
||||||
|
R s 0 1 - Ja lastSu 1w 2s -
|
||||||
|
R s 0 1 - Ja lastTh 1w 2s -
|
||||||
|
R s 0 1 - Ja lastTu 1w 2s -
|
||||||
|
R s 0 1 - Ja lastW 1w 2s -
|
||||||
|
|
||||||
|
# 3 letter abbreviation
|
||||||
|
R a 0 1 - Ja lastFri 1w 2s -
|
||||||
|
R a 0 1 - Ja lastMon 1w 2s -
|
||||||
|
R a 0 1 - Ja lastSat 1w 2s -
|
||||||
|
R a 0 1 - Ja lastSun 1w 2s -
|
||||||
|
R a 0 1 - Ja lastThu 1w 2s -
|
||||||
|
R a 0 1 - Ja lastTue 1w 2s -
|
||||||
|
R a 0 1 - Ja lastWed 1w 2s -
|
||||||
|
|
||||||
|
# Full names
|
||||||
|
R f 0 1 - Ja lastFriday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastMonday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastSaturday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastSunday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastThursday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastTuesday 1w 2s -
|
||||||
|
R f 0 1 - Ja lastWednesday 1w 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 3);
|
||||||
|
for (std::size_t i = 0; i < result.rules.size(); ++i) {
|
||||||
|
assert(result.rules[i].second.size() == 7);
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[0].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Friday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[1].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Monday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[2].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Saturday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[3].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Sunday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[4].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Thursday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[5].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Tuesday));
|
||||||
|
assert(std::get<std::chrono::weekday_last>(result.rules[i].second[6].__on) ==
|
||||||
|
std::chrono::weekday_last(std::chrono::Wednesday));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_on_constrain() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# Shortest abbreviation valid
|
||||||
|
R s 0 1 - Ja F>=1 1w 2s -
|
||||||
|
R s 0 1 - Ja M<=1 1w 2s -
|
||||||
|
R s 0 1 - Ja Sa>=31 1w 2s -
|
||||||
|
R s 0 1 - Ja Su<=31 1w 2s -
|
||||||
|
R s 0 1 - Ja Th>=10 1w 2s -
|
||||||
|
R s 0 1 - Ja Tu<=20 1w 2s -
|
||||||
|
R s 0 1 - Ja W>=30 1w 2s -
|
||||||
|
|
||||||
|
# 3 letter abbreviation
|
||||||
|
R a 0 1 - Ja Fri>=1 1w 2s -
|
||||||
|
R a 0 1 - Ja Mon<=1 1w 2s -
|
||||||
|
R a 0 1 - Ja Sat>=31 1w 2s -
|
||||||
|
R a 0 1 - Ja Sun<=31 1w 2s -
|
||||||
|
R a 0 1 - Ja Thu>=10 1w 2s -
|
||||||
|
R a 0 1 - Ja Tue<=20 1w 2s -
|
||||||
|
R a 0 1 - Ja Wed>=30 1w 2s -
|
||||||
|
|
||||||
|
# Full names
|
||||||
|
R f 0 1 - Ja Friday>=1 1w 2s -
|
||||||
|
R f 0 1 - Ja Monday<=1 1w 2s -
|
||||||
|
R f 0 1 - Ja Saturday>=31 1w 2s -
|
||||||
|
R f 0 1 - Ja Sunday<=31 1w 2s -
|
||||||
|
R f 0 1 - Ja Thursday>=10 1w 2s -
|
||||||
|
R f 0 1 - Ja Tuesday<=20 1w 2s -
|
||||||
|
R f 0 1 - Ja Wednesday>=30 1w 2s -
|
||||||
|
|
||||||
|
)"};
|
||||||
|
|
||||||
|
std::chrono::__tz::__constrained_weekday r;
|
||||||
|
assert(result.rules.size() == 3);
|
||||||
|
for (std::size_t i = 0; i < result.rules.size(); ++i) {
|
||||||
|
assert(result.rules[i].second.size() == 7);
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[0].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Friday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(1));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[1].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Monday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
|
||||||
|
assert(r.__day == std::chrono::day(1));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[2].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Saturday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(31));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[3].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Sunday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
|
||||||
|
assert(r.__day == std::chrono::day(31));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[4].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Thursday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(10));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[5].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Tuesday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
|
||||||
|
assert(r.__day == std::chrono::day(20));
|
||||||
|
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(result.rules[i].second[6].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Wednesday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(30));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_on() {
|
||||||
|
test_on_day();
|
||||||
|
test_on_last();
|
||||||
|
test_on_constrain();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_at() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
# Based on the examples in the man page.
|
||||||
|
# Note the input is not expected to have fractional seconds, they are truncated.
|
||||||
|
R a 0 1 - Ja Su>=31 2w 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 2:00s 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 01:28:14u 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 00:19:32.10g 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 12:00z 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 15:00 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 24:00 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 260:00 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 -2:30 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 - 2s -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 10);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[0].__at.__time == std::chrono::hours(2));
|
||||||
|
assert(result.rules[0].second[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[1].__at.__time == std::chrono::hours(2));
|
||||||
|
assert(result.rules[0].second[1].__at.__clock == std::chrono::__tz::__clock::__standard);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[2].__at.__time ==
|
||||||
|
std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
|
||||||
|
assert(result.rules[0].second[2].__at.__clock == std::chrono::__tz::__clock::__universal);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[3].__at.__time == std::chrono::minutes(19) + std::chrono::seconds(32));
|
||||||
|
assert(result.rules[0].second[3].__at.__clock == std::chrono::__tz::__clock::__universal);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[4].__at.__time == std::chrono::hours(12));
|
||||||
|
assert(result.rules[0].second[4].__at.__clock == std::chrono::__tz::__clock::__universal);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[5].__at.__time == std::chrono::hours(15));
|
||||||
|
assert(result.rules[0].second[5].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[6].__at.__time == std::chrono::hours(24));
|
||||||
|
assert(result.rules[0].second[6].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[7].__at.__time == std::chrono::hours(260));
|
||||||
|
assert(result.rules[0].second[7].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[8].__at.__time == -(std::chrono::hours(2) + std::chrono::minutes(30)));
|
||||||
|
assert(result.rules[0].second[8].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[9].__at.__time == std::chrono::hours(0)); // The man page expresses it in hours
|
||||||
|
assert(result.rules[0].second[9].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_save() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2d -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2:00s -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 0 -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 0:00:01 -
|
||||||
|
R a 0 1 - Ja Su>=31 1w -0:00:01 -
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 5);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[0].__save.__time == std::chrono::hours(2));
|
||||||
|
assert(result.rules[0].second[0].__save.__is_dst == true);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[1].__save.__time == std::chrono::hours(2));
|
||||||
|
assert(result.rules[0].second[1].__save.__is_dst == false);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[2].__save.__time == std::chrono::hours(0));
|
||||||
|
assert(result.rules[0].second[2].__save.__is_dst == false);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[3].__save.__time == std::chrono::seconds(1));
|
||||||
|
assert(result.rules[0].second[3].__save.__is_dst == true);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[4].__save.__time == -std::chrono::seconds(1));
|
||||||
|
assert(result.rules[0].second[4].__save.__is_dst == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_letter() {
|
||||||
|
parse_result result{
|
||||||
|
R"(
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2s -
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2s a
|
||||||
|
R a 0 1 - Ja Su>=31 1w 2s abc
|
||||||
|
)"};
|
||||||
|
|
||||||
|
assert(result.rules.size() == 1);
|
||||||
|
assert(result.rules[0].second.size() == 3);
|
||||||
|
|
||||||
|
assert(result.rules[0].second[0].__letters == "");
|
||||||
|
assert(result.rules[0].second[1].__letters == "a");
|
||||||
|
assert(result.rules[0].second[2].__letters == "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
test_invalid();
|
||||||
|
test_name();
|
||||||
|
test_from();
|
||||||
|
test_to();
|
||||||
|
test_in();
|
||||||
|
test_on();
|
||||||
|
test_at();
|
||||||
|
test_save();
|
||||||
|
test_letter();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
380
libcxx/test/libcxx/time/time.zone/time.zone.db/zones.pass.cpp
Normal file
380
libcxx/test/libcxx/time/time.zone/time.zone.db/zones.pass.cpp
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// Tests the IANA database zones parsing and operations.
|
||||||
|
// This is not part of the public tzdb interface.
|
||||||
|
// The test uses private implementation headers.
|
||||||
|
// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../../src/include
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "assert_macros.h"
|
||||||
|
#include "concat_macros.h"
|
||||||
|
#include "filesystem_test_helper.h"
|
||||||
|
#include "test_tzdb.h"
|
||||||
|
|
||||||
|
// headers in the dylib
|
||||||
|
#include "tzdb/types_private.h"
|
||||||
|
#include "tzdb/tzdb_private.h"
|
||||||
|
#include "tzdb/time_zone_private.h"
|
||||||
|
|
||||||
|
scoped_test_env env;
|
||||||
|
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||||
|
const std::filesystem::path file = env.create_file("zoneinfo/tzdata.zi");
|
||||||
|
|
||||||
|
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||||
|
static std::string result = dir.string();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write(std::string_view input) {
|
||||||
|
static int version = 0;
|
||||||
|
|
||||||
|
std::ofstream f{file};
|
||||||
|
f << "# version " << version++ << '\n';
|
||||||
|
f.write(input.data(), input.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::chrono::tzdb& parse(std::string_view input) {
|
||||||
|
write(input);
|
||||||
|
return std::chrono::reload_tzdb();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::vector<std::chrono::__tz::__continuation>& continuations(const std::chrono::time_zone& time_zone) {
|
||||||
|
return time_zone.__implementation().__continuations();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_exception(std::string_view input, [[maybe_unused]] std::string_view what) {
|
||||||
|
write(input);
|
||||||
|
|
||||||
|
TEST_VALIDATE_EXCEPTION(
|
||||||
|
std::runtime_error,
|
||||||
|
[&]([[maybe_unused]] const std::runtime_error& e) {
|
||||||
|
TEST_LIBCPP_REQUIRE(
|
||||||
|
e.what() == what,
|
||||||
|
TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||||
|
},
|
||||||
|
TEST_IGNORE_NODISCARD std::chrono::reload_tzdb());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_invalid() {
|
||||||
|
test_exception("Z", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("Z ", "corrupt tzdb: expected a string");
|
||||||
|
|
||||||
|
test_exception("Z n", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("Z n ", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("Z n x", "corrupt tzdb: expected a digit");
|
||||||
|
test_exception("Z n +", "corrupt tzdb: expected a digit");
|
||||||
|
|
||||||
|
test_exception("Z n 0", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("Z n 0 ", "corrupt tzdb: expected a string");
|
||||||
|
|
||||||
|
test_exception("Z n 0 r", "corrupt tzdb: expected whitespace");
|
||||||
|
|
||||||
|
test_exception("Z n 0 r ", "corrupt tzdb: expected a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_name() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
Z n 0 r f
|
||||||
|
)");
|
||||||
|
assert(result.zones.size() == 1);
|
||||||
|
assert(result.zones[0].name() == "n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stdoff() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
# Based on the examples in the man page.
|
||||||
|
# Note the input is not expected to have fractional seconds, they are truncated.
|
||||||
|
Zo na 2 r f
|
||||||
|
Zon nb 2:00 r f
|
||||||
|
Zone nc 01:28:14 r f
|
||||||
|
zONE nd 00:19:32.10 r f
|
||||||
|
zoNe ne 12:00 r f
|
||||||
|
Z nf 15:00 r f
|
||||||
|
Z ng 24:00 r f
|
||||||
|
Z nh 260:00 r f
|
||||||
|
Z ni -2:30 r f
|
||||||
|
Z nj - r f
|
||||||
|
)");
|
||||||
|
|
||||||
|
assert(result.zones.size() == 10);
|
||||||
|
for (std::size_t i = 0; i < result.zones.size(); ++i)
|
||||||
|
assert(continuations(result.zones[0]).size() == 1);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[0].__stdoff == std::chrono::hours(2));
|
||||||
|
assert(continuations(result.zones[1])[0].__stdoff == std::chrono::hours(2));
|
||||||
|
assert(continuations(result.zones[2])[0].__stdoff ==
|
||||||
|
std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
|
||||||
|
assert(continuations(result.zones[3])[0].__stdoff == std::chrono::minutes(19) + std::chrono::seconds(32));
|
||||||
|
assert(continuations(result.zones[4])[0].__stdoff == std::chrono::hours(12));
|
||||||
|
assert(continuations(result.zones[5])[0].__stdoff == std::chrono::hours(15));
|
||||||
|
assert(continuations(result.zones[6])[0].__stdoff == std::chrono::hours(24));
|
||||||
|
assert(continuations(result.zones[7])[0].__stdoff == std::chrono::hours(260));
|
||||||
|
assert(continuations(result.zones[8])[0].__stdoff == -(std::chrono::hours(2) + std::chrono::minutes(30)));
|
||||||
|
assert(continuations(result.zones[9])[0].__stdoff == std::chrono::hours(0)); // The man page expresses it in hours
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_rules() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
Z na 0 - f
|
||||||
|
Z nb 0 r f
|
||||||
|
Z nc 0 2d f
|
||||||
|
Z nd 0 2:00s f
|
||||||
|
Z ne 0 0 f
|
||||||
|
Z nf 0 0:00:01 f
|
||||||
|
Z ng 0 -0:00:01 f
|
||||||
|
)");
|
||||||
|
|
||||||
|
assert(result.zones.size() == 7);
|
||||||
|
for (std::size_t i = 0; i < result.zones.size(); ++i)
|
||||||
|
assert(continuations(result.zones[0]).size() == 1);
|
||||||
|
|
||||||
|
assert(std::holds_alternative<std::monostate>(continuations(result.zones[0])[0].__rules));
|
||||||
|
assert(std::get<std::string>(continuations(result.zones[1])[0].__rules) == "r");
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[2])[0].__rules).__time ==
|
||||||
|
std::chrono::hours(2));
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[2])[0].__rules).__is_dst == true);
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[3])[0].__rules).__time ==
|
||||||
|
std::chrono::hours(2));
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[3])[0].__rules).__is_dst == false);
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[4])[0].__rules).__time ==
|
||||||
|
std::chrono::hours(0));
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[4])[0].__rules).__is_dst == false);
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[5])[0].__rules).__time ==
|
||||||
|
std::chrono::seconds(1));
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[5])[0].__rules).__is_dst == true);
|
||||||
|
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[6])[0].__rules).__time ==
|
||||||
|
-std::chrono::seconds(1));
|
||||||
|
assert(std::get<std::chrono::__tz::__save>(continuations(result.zones[6])[0].__rules).__is_dst == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_format() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
Z n 0 r f
|
||||||
|
)");
|
||||||
|
assert(result.zones.size() == 1);
|
||||||
|
assert(continuations(result.zones[0]).size() == 1);
|
||||||
|
assert(continuations(result.zones[0])[0].__format == "f");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_until() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
Z na 0 r f
|
||||||
|
Z nb 0 r f 1000
|
||||||
|
Z nc 0 r f -1000 N
|
||||||
|
Z nd 0 r f ma S 31
|
||||||
|
Z ne 0 r f 0 jA LASTw
|
||||||
|
Z nf 0 r f -42 jUN m<=1
|
||||||
|
Z ng 0 r f 42 jul Su>=12
|
||||||
|
Z nh 0 r f 42 JUl 1 2w
|
||||||
|
Z ni 0 r f 42 July 1 01:28:14u
|
||||||
|
Z nj 0 r f 42 Jul 1 -
|
||||||
|
)");
|
||||||
|
assert(result.zones.size() == 10);
|
||||||
|
for (std::size_t i = 0; i < result.zones.size(); ++i)
|
||||||
|
assert(continuations(result.zones[0]).size() == 1);
|
||||||
|
|
||||||
|
std::chrono::__tz::__constrained_weekday r;
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[0].__year == std::chrono::year::min());
|
||||||
|
assert(continuations(result.zones[0])[0].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[1])[0].__year == std::chrono::year(1000));
|
||||||
|
assert(continuations(result.zones[1])[0].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[1])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[1])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[1])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[2])[0].__year == std::chrono::year(-1000));
|
||||||
|
assert(continuations(result.zones[2])[0].__in == std::chrono::November);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[2])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[2])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[2])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[3])[0].__year == std::chrono::year::max());
|
||||||
|
assert(continuations(result.zones[3])[0].__in == std::chrono::September);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[3])[0].__on) == std::chrono::day(31));
|
||||||
|
assert(continuations(result.zones[3])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[3])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[4])[0].__year == std::chrono::year(0));
|
||||||
|
assert(continuations(result.zones[4])[0].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::weekday_last>(continuations(result.zones[4])[0].__on) ==
|
||||||
|
std::chrono::weekday_last{std::chrono::Wednesday});
|
||||||
|
assert(continuations(result.zones[4])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[4])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[5])[0].__year == std::chrono::year(-42));
|
||||||
|
assert(continuations(result.zones[5])[0].__in == std::chrono::June);
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[5])[0].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Monday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
|
||||||
|
assert(r.__day == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[5])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[5])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[6])[0].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[6])[0].__in == std::chrono::July);
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[6])[0].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Sunday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(12));
|
||||||
|
assert(continuations(result.zones[6])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[6])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[7])[0].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[7])[0].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[7])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[7])[0].__at.__time == std::chrono::hours(2));
|
||||||
|
assert(continuations(result.zones[7])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[8])[0].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[8])[0].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[8])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[8])[0].__at.__time ==
|
||||||
|
std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
|
||||||
|
assert(continuations(result.zones[8])[0].__at.__clock == std::chrono::__tz::__clock::__universal);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[9])[0].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[9])[0].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[9])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[9])[0].__at.__time == std::chrono::hours(0)); // The man page expresses it in hours
|
||||||
|
assert(continuations(result.zones[9])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_continuation() {
|
||||||
|
const std::chrono::tzdb& result = parse(
|
||||||
|
R"(
|
||||||
|
Z na 0 r f
|
||||||
|
0 r f 1000
|
||||||
|
0 r f -1000 N
|
||||||
|
0 r f ma S 31
|
||||||
|
0 r f 0 Ja lastW
|
||||||
|
0 r f -42 Jun M<=1
|
||||||
|
0 r f 42 Jul Su>=12
|
||||||
|
0 r f 42 Jul 1 2w
|
||||||
|
0 r f 42 Jul 1 01:28:14u
|
||||||
|
0 r f 42 Jul 1 -
|
||||||
|
)");
|
||||||
|
|
||||||
|
assert(result.zones.size() == 1);
|
||||||
|
assert(continuations(result.zones[0]).size() == 10);
|
||||||
|
|
||||||
|
std::chrono::__tz::__constrained_weekday r;
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[0].__year == std::chrono::year::min());
|
||||||
|
assert(continuations(result.zones[0])[0].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[0].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[0].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[0].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[1].__year == std::chrono::year(1000));
|
||||||
|
assert(continuations(result.zones[0])[1].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[1].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[1].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[1].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[2].__year == std::chrono::year(-1000));
|
||||||
|
assert(continuations(result.zones[0])[2].__in == std::chrono::November);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[2].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[2].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[2].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[3].__year == std::chrono::year::max());
|
||||||
|
assert(continuations(result.zones[0])[3].__in == std::chrono::September);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[3].__on) == std::chrono::day(31));
|
||||||
|
assert(continuations(result.zones[0])[3].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[3].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[4].__year == std::chrono::year(0));
|
||||||
|
assert(continuations(result.zones[0])[4].__in == std::chrono::January);
|
||||||
|
assert(std::get<std::chrono::weekday_last>(continuations(result.zones[0])[4].__on) ==
|
||||||
|
std::chrono::weekday_last{std::chrono::Wednesday});
|
||||||
|
assert(continuations(result.zones[0])[4].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[4].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[5].__year == std::chrono::year(-42));
|
||||||
|
assert(continuations(result.zones[0])[5].__in == std::chrono::June);
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[0])[5].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Monday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__le);
|
||||||
|
assert(r.__day == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[5].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[5].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[6].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[0])[6].__in == std::chrono::July);
|
||||||
|
r = std::get<std::chrono::__tz::__constrained_weekday>(continuations(result.zones[0])[6].__on);
|
||||||
|
assert(r.__weekday == std::chrono::Sunday);
|
||||||
|
assert(r.__comparison == std::chrono::__tz::__constrained_weekday::__ge);
|
||||||
|
assert(r.__day == std::chrono::day(12));
|
||||||
|
assert(continuations(result.zones[0])[6].__at.__time == std::chrono::seconds(0));
|
||||||
|
assert(continuations(result.zones[0])[6].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[7].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[0])[7].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[7].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[7].__at.__time == std::chrono::hours(2));
|
||||||
|
assert(continuations(result.zones[0])[7].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[8].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[0])[8].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[8].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[8].__at.__time ==
|
||||||
|
std::chrono::hours(1) + std::chrono::minutes(28) + std::chrono::seconds(14));
|
||||||
|
assert(continuations(result.zones[0])[8].__at.__clock == std::chrono::__tz::__clock::__universal);
|
||||||
|
|
||||||
|
assert(continuations(result.zones[0])[9].__year == std::chrono::year(42));
|
||||||
|
assert(continuations(result.zones[0])[9].__in == std::chrono::July);
|
||||||
|
assert(std::get<std::chrono::day>(continuations(result.zones[0])[9].__on) == std::chrono::day(1));
|
||||||
|
assert(continuations(result.zones[0])[9].__at.__time == std::chrono::hours(0)); // The man page expresses it in hours
|
||||||
|
assert(continuations(result.zones[0])[9].__at.__clock == std::chrono::__tz::__clock::__local);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
test_invalid();
|
||||||
|
test_name();
|
||||||
|
test_stdoff();
|
||||||
|
test_rules();
|
||||||
|
test_format();
|
||||||
|
test_until();
|
||||||
|
|
||||||
|
test_continuation();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -127,6 +127,7 @@ chrono string
|
|||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
chrono type_traits
|
chrono type_traits
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
@ -834,13 +835,17 @@ system_error type_traits
|
|||||||
system_error version
|
system_error version
|
||||||
thread array
|
thread array
|
||||||
thread atomic
|
thread atomic
|
||||||
|
thread cctype
|
||||||
thread cerrno
|
thread cerrno
|
||||||
thread chrono
|
thread chrono
|
||||||
|
thread clocale
|
||||||
thread compare
|
thread compare
|
||||||
thread cstddef
|
thread cstddef
|
||||||
thread cstdint
|
thread cstdint
|
||||||
|
thread cstdlib
|
||||||
thread cstring
|
thread cstring
|
||||||
thread ctime
|
thread ctime
|
||||||
|
thread cwchar
|
||||||
thread functional
|
thread functional
|
||||||
thread iosfwd
|
thread iosfwd
|
||||||
thread limits
|
thread limits
|
||||||
|
|
@ -127,6 +127,7 @@ chrono string
|
|||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
chrono type_traits
|
chrono type_traits
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -127,6 +127,7 @@ chrono string
|
|||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
chrono type_traits
|
chrono type_traits
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -127,6 +127,7 @@ chrono string
|
|||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
chrono type_traits
|
chrono type_traits
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -133,6 +133,7 @@ chrono string
|
|||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
chrono type_traits
|
chrono type_traits
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -87,6 +87,7 @@ chrono stdexcept
|
|||||||
chrono string
|
chrono string
|
||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -87,6 +87,7 @@ chrono stdexcept
|
|||||||
chrono string
|
chrono string
|
||||||
chrono string_view
|
chrono string_view
|
||||||
chrono tuple
|
chrono tuple
|
||||||
|
chrono vector
|
||||||
chrono version
|
chrono version
|
||||||
cinttypes cstdint
|
cinttypes cstdint
|
||||||
cmath limits
|
cmath limits
|
||||||
|
|
@ -12,16 +12,16 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
|
||||||
// const tzdb& get_tzdb();
|
// const tzdb& get_tzdb();
|
||||||
|
|
||||||
#include <chrono>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
|
|
||||||
@ -30,5 +30,15 @@ int main(int, const char**) {
|
|||||||
|
|
||||||
assert(!db.version.empty());
|
assert(!db.version.empty());
|
||||||
|
|
||||||
|
LIBCPP_ASSERT(!db.__rules.empty());
|
||||||
|
|
||||||
|
assert(!db.zones.empty());
|
||||||
|
assert(std::ranges::is_sorted(db.zones));
|
||||||
|
assert(std::ranges::adjacent_find(db.zones) == db.zones.end()); // is unique?
|
||||||
|
|
||||||
|
assert(!db.links.empty());
|
||||||
|
assert(std::ranges::is_sorted(db.links));
|
||||||
|
assert(std::ranges::adjacent_find(db.links) == db.links.end()); // is unique?
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// XFAIL: libcpp-has-no-incomplete-tzdb
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
// XFAIL: availability-tzdb-missing
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
// TODO TZDB Enable tests
|
// TODO TZDB (#81654) Enable tests
|
||||||
// UNSUPPORTED: c++20, c++23, c++26
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
// <chrono>
|
// <chrono>
|
||||||
|
@ -37,7 +37,11 @@ int main(int, const char**) {
|
|||||||
tzdb.version = "version";
|
tzdb.version = "version";
|
||||||
assert(tzdb.version == "version");
|
assert(tzdb.version == "version");
|
||||||
|
|
||||||
// TODO TZDB add the other data members
|
[[maybe_unused]] std::vector<std::chrono::time_zone>& zones = tzdb.zones;
|
||||||
|
|
||||||
|
[[maybe_unused]] std::vector<std::chrono::time_zone_link>& links = tzdb.links;
|
||||||
|
|
||||||
|
// TODO TZDB add the leap data member
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// TODO TZDB (#81654) Enable tests
|
||||||
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// class time_zone_link;
|
||||||
|
|
||||||
|
// string_view name() const noexcept;
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
|
||||||
|
assert(tzdb.links.size() > 1);
|
||||||
|
|
||||||
|
std::same_as<std::string_view> auto name = tzdb.links[0].name();
|
||||||
|
static_assert(noexcept(tzdb.links[0].name()));
|
||||||
|
assert(name != tzdb.links[1].name());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// TODO TZDB (#81654) Enable tests
|
||||||
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// class time_zone_link;
|
||||||
|
|
||||||
|
// string_view target() const noexcept;
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
|
||||||
|
assert(tzdb.links.size() > 1);
|
||||||
|
|
||||||
|
[[maybe_unused]] std::same_as<std::string_view> auto _ = tzdb.links[0].target();
|
||||||
|
static_assert(noexcept(tzdb.links[0].target()));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// TODO TZDB (#81654) Enable tests
|
||||||
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// bool operator==(const time_zone_link& x, const time_zone_link& y) noexcept;
|
||||||
|
// strong_ordering operator<=>(const time_zone_link& x, const time_zone_link& y) noexcept;
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_comparisons.h"
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
|
||||||
|
assert(tzdb.links.size() > 2);
|
||||||
|
|
||||||
|
AssertOrderAreNoexcept<std::chrono::time_zone_link>();
|
||||||
|
AssertOrderReturn<std::strong_ordering, std::chrono::time_zone_link>();
|
||||||
|
|
||||||
|
assert(testOrder(tzdb.links[0], tzdb.links[1], std::strong_ordering::less));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// class time_zone_link
|
||||||
|
// {
|
||||||
|
// time_zone_link(time_zone_link&&) = default;
|
||||||
|
// time_zone_link& operator=(time_zone_link&&) = default;
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <concepts>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
// It's impossible to actually obtain a non-const reference to a
|
||||||
|
// time_zone_link, and as a result the move constructor can never be exercised
|
||||||
|
// in runtime code. We still check the property pedantically.
|
||||||
|
LIBCPP_STATIC_ASSERT(!std::copy_constructible<std::chrono::time_zone_link>);
|
||||||
|
LIBCPP_STATIC_ASSERT(!std::is_copy_assignable_v<std::chrono::time_zone_link>);
|
||||||
|
static_assert(std::move_constructible<std::chrono::time_zone_link>);
|
||||||
|
static_assert(std::is_move_assignable_v<std::chrono::time_zone_link>);
|
@ -0,0 +1,38 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// TODO TZDB (#81654) Enable tests
|
||||||
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// class time_zone;
|
||||||
|
|
||||||
|
// string_view name() const noexcept;
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
|
||||||
|
assert(tzdb.zones.size() > 1);
|
||||||
|
|
||||||
|
[[maybe_unused]] std::same_as<std::string_view> auto _ = tzdb.zones[0].name();
|
||||||
|
static_assert(noexcept(tzdb.zones[0].name()));
|
||||||
|
assert(tzdb.zones[0].name() != tzdb.zones[1].name());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// TODO TZDB (#81654) Enable tests
|
||||||
|
// UNSUPPORTED: c++20, c++23, c++26
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// bool operator==(const time_zone& x, const time_zone& y) noexcept;
|
||||||
|
// strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_comparisons.h"
|
||||||
|
|
||||||
|
int main(int, const char**) {
|
||||||
|
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
|
||||||
|
assert(tzdb.zones.size() > 2);
|
||||||
|
|
||||||
|
AssertOrderAreNoexcept<std::chrono::time_zone>();
|
||||||
|
AssertOrderReturn<std::strong_ordering, std::chrono::time_zone>();
|
||||||
|
|
||||||
|
assert(testOrder(tzdb.zones[0], tzdb.zones[1], std::strong_ordering::less));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||||
|
|
||||||
|
// XFAIL: libcpp-has-no-incomplete-tzdb
|
||||||
|
// XFAIL: availability-tzdb-missing
|
||||||
|
|
||||||
|
// <chrono>
|
||||||
|
|
||||||
|
// class time_zone
|
||||||
|
// {
|
||||||
|
// time_zone(time_zone&&) = default;
|
||||||
|
// time_zone& operator=(time_zone&&) = default;
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <concepts>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
|
// It's impossible to actually obtain a non-const reference to a time_zone, and
|
||||||
|
// as a result the move constructor can never be exercised in runtime code. We
|
||||||
|
// still check the property pedantically.
|
||||||
|
LIBCPP_STATIC_ASSERT(!std::copy_constructible<std::chrono::time_zone>);
|
||||||
|
LIBCPP_STATIC_ASSERT(!std::is_copy_assignable_v<std::chrono::time_zone>);
|
||||||
|
static_assert(std::move_constructible<std::chrono::time_zone>);
|
||||||
|
static_assert(std::is_move_assignable_v<std::chrono::time_zone>);
|
Loading…
x
Reference in New Issue
Block a user