libstdc++: Implement C++20 time zone support in <chrono>
This is the largest missing piece of C++20 support. Only the cxx11 ABI is supported, due to the use of std::string in the API for time zones. For the old gcc4 ABI, utc_clock and leap seconds are supported, but only using a hardcoded list of leap seconds, no up-to-date tzdb::leap_seconds information is available, and no time zones or zoned_time conversions. The implementation currently depends on a tzdata.zi file being provided by the OS or the user. The expected location is /usr/share/zoneinfo but that can be changed using --with-libstdcxx-zoneinfo-dir=PATH. On targets that support it there is also a weak symbol that users can override in their own program (which also helps with testing): extern "C++" const char* __gnu_cxx::zoneinfo_dir_override(); If no file is found, a fallback tzdb object will be created which only contains the "Etc/UTC" and "Etc/GMT" time zones. A leapseconds file is also expected in the same directory, but if that isn't present then a hardcoded list of leapseconds is used, which is correct at least as far as 2023-06-28 (and it currently looks like no leap second will be inserted for a few years). The tzdata.zi and leapseconds files from https://www.iana.org/time-zones are in the public domain, so shipping copies of them with GCC would be an option. However, the tzdata.zi file will rapidly become outdated, so users should really provide it themselves (or convince their OS vendor to do so). It would also be possible to implement an alternative parser for the compiled tzdata files (one per time zone) under /usr/share/zoneinfo. Those files are present on more operating systems, but do not contain all the information present in tzdata.zi. Specifically, the "links" are not present, so that e.g. "UTC" and "Universal" are distinct time zones, rather than both being links to the canonical "Etc/UTC" zone. For some platforms those files are hard links to the same file, but there's no indication which zone is the canonical name and which is a link. Other platforms just store them in different inodes anyway. I do not plan to add such an alternative parser for the compiled files. That would need to be contributed by maintainers or users of targets that require it, if making tzdata.zi available is not an option. The library ABI would not need to change for a new tzdb implementation, because everything in tzdb_list, tzdb and time_zone is implemented as a pimpl (except for the shared_ptr links between nodes, described below). That means the new exported symbols added by this commit should be stable even if the implementation is completely rewritten. The information from tzdata.zi is parsed and stored in data structures that closely model the info in the file. This is a space-efficient representation that uses less memory that storing every transition for every time zone. It also avoids spending time expanding that information into time zone transitions that might never be needed by the program. When a conversion to/from a local time to UTC is requested the information will be processed to determine the time zone transitions close to the time being converted. There is a bug in some time zone transitions. When generating a sys_info object immediately after one that was previously generated, we need to find the previous rule that was in effect and note its offset and letters. This is so that the start time and abbreviation of the new sys_info will be correct. This only affects time zones that use a format like "C%sT" where the LETTERS replacing %s are non-empty for standard time, e.g. "Asia/Shanghai" which uses "CST" for standard time and "CDT" for daylight time. The tzdb_list structure maintains a linked list of tzdb nodes using shared_ptr links. This allows the iterators into the list to share ownership with the list itself. This offers a non-portable solution to a lifetime issue in the API. Because tzdb objects can be erased from the list using tzdb_list::erase_after, separate modules/libraries in a large program cannot guarantee that any const tzdb& or const time_zone* remains valid indefinitely. Holding onto a tzdb_list::const_iterator will extend the tzdb object's lifetime, even if it's erased from the list. An alternative design would be for the list iterator to hold a weak_ptr. This would allow users to test whether the tzdb still exists when the iterator is dereferenced, which is better than just having a dangling raw pointer. That doesn't actually extend the tzdb's lifetime though, and every use of it would need to be preceded by checking the weak_ptr. Using shared_ptr adds a little bit of overhead but allows users to solve the lifetime issue if they rely on the libstdc++-specific iterator property. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_ZONEINFO_DIR): New macro. * config.h.in: Regenerate. * config/abi/pre/gnu.ver: Export new symbols. * configure: Regenerate. * configure.ac (GLIBCXX_ZONEINFO_DIR): Use new macro. * include/std/chrono (utc_clock::from_sys): Correct handling of leap seconds. (nonexistent_local_time::_M_make_what_str): Define. (ambiguous_local_time::_M_make_what_str): Define. (__throw_bad_local_time): Define new function. (time_zone, tzdb_list, tzdb): Implement all members. (remote_version, zoned_time, get_leap_second_info): Define. * include/std/version: Add comment for __cpp_lib_chrono. * src/c++20/Makefile.am: Add new file. * src/c++20/Makefile.in: Regenerate. * src/c++20/tzdb.cc: New file. * testsuite/lib/libstdc++.exp: Define effective target tzdb. * testsuite/std/time/clock/file/members.cc: Check file_time alias and file_clock::now() member. * testsuite/std/time/clock/gps/1.cc: Likewise for gps_clock. * testsuite/std/time/clock/tai/1.cc: Likewise for tai_clock. * testsuite/std/time/syn_c++20.cc: Uncomment everything except parse. * testsuite/std/time/clock/utc/leap_second_info.cc: New test. * testsuite/std/time/exceptions.cc: New test. * testsuite/std/time/time_zone/get_info_local.cc: New test. * testsuite/std/time/time_zone/get_info_sys.cc: New test. * testsuite/std/time/time_zone/requirements.cc: New test. * testsuite/std/time/tzdb/1.cc: New test. * testsuite/std/time/tzdb/leap_seconds.cc: New test. * testsuite/std/time/tzdb_list/1.cc: New test. * testsuite/std/time/tzdb_list/requirements.cc: New test. * testsuite/std/time/zoned_time/1.cc: New test. * testsuite/std/time/zoned_time/custom.cc: New test. * testsuite/std/time/zoned_time/deduction.cc: New test. * testsuite/std/time/zoned_time/req_neg.cc: New test. * testsuite/std/time/zoned_time/requirements.cc: New test. * testsuite/std/time/zoned_traits.cc: New test.
This commit is contained in:
parent
907c84cb1d
commit
9fc61d45fa
30 changed files with 3884 additions and 186 deletions
|
@ -5140,6 +5140,33 @@ AC_DEFUN([GLIBCXX_EMERGENCY_EH_ALLOC], [
|
|||
AC_SUBST(EH_POOL_FLAGS)
|
||||
])
|
||||
|
||||
dnl
|
||||
dnl Allow the location of tzdata files to be configured.
|
||||
dnl
|
||||
dnl --with-libstdcxx-zoneinfo-dir=PATH will set the directory to PATH.
|
||||
dnl
|
||||
dnl Defines:
|
||||
dnl _GLIBCXX_ZONEINFO_DIR if std::chrono::tzdb should use a non-default
|
||||
dnl directory for the tzdata.zi and leapseconds files.
|
||||
dnl
|
||||
AC_DEFUN([GLIBCXX_ZONEINFO_DIR], [
|
||||
AC_ARG_WITH([libstdcxx-zoneinfo-dir],
|
||||
AC_HELP_STRING([--with-libstdcxx-zoneinfo-dir],
|
||||
[the directory to search for tzdata files]),
|
||||
[zoneinfo_dir="${withval}"
|
||||
AC_DEFINE(_GLIBCXX_ZONEINFO_DIR, "${withval}",
|
||||
[Define if a non-default location should be used for tzdata files.])
|
||||
],
|
||||
[
|
||||
case "$host" in
|
||||
# *-*-aix*) zoneinfo_dir="/usr/share/lib/zoneinfo" ;;
|
||||
*) zoneinfo_dir="/usr/share/zoneinfo" ;;
|
||||
esac
|
||||
])
|
||||
|
||||
AC_MSG_NOTICE([zoneinfo data directory: ${zoneinfo_dir}])
|
||||
])
|
||||
|
||||
# Macros from the top-level gcc directory.
|
||||
m4_include([../config/gc++filt.m4])
|
||||
m4_include([../config/tls.m4])
|
||||
|
|
|
@ -1037,6 +1037,9 @@
|
|||
/* Defined if as can handle rdseed. */
|
||||
#undef _GLIBCXX_X86_RDSEED
|
||||
|
||||
/* Define if a non-default location should be used for tzdata files. */
|
||||
#undef _GLIBCXX_ZONEINFO_DIR
|
||||
|
||||
/* Define to 1 if mutex_timedlock is available. */
|
||||
#undef _GTHREAD_USE_MUTEX_TIMEDLOCK
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ GLIBCXX_3.4 {
|
|||
std::a[a-c]*;
|
||||
std::ad[a-n]*;
|
||||
std::ad[p-z]*;
|
||||
std::a[e-z]*;
|
||||
std::a[e-s]*;
|
||||
std::a[u-z]*;
|
||||
# std::ba[a-r]*;
|
||||
std::basic_[a-e]*;
|
||||
std::basic_f[a-h]*;
|
||||
|
@ -2485,6 +2486,23 @@ GLIBCXX_3.4.31 {
|
|||
|
||||
_ZSt15__try_use_facet*;
|
||||
|
||||
_ZNSt6chrono11reload_tzdbEv;
|
||||
_ZNSt6chrono8get_tzdbEv;
|
||||
_ZNSt6chrono13get_tzdb_listEv;
|
||||
_ZNSt6chrono14remote_version*;
|
||||
_ZNSt6chrono12current_zoneEv;
|
||||
_ZNSt6chrono11locate_zoneESt17basic_string_viewIcSt11char_traitsIcEE;
|
||||
_ZNKSt6chrono9time_zone15_M_get_sys_info*;
|
||||
_ZNKSt6chrono9time_zone17_M_get_local_info*;
|
||||
_ZNKSt6chrono4tzdb12current_zoneEv;
|
||||
_ZNKSt6chrono4tzdb11locate_zoneESt17basic_string_viewIcSt11char_traitsIcEE;
|
||||
_ZNKSt6chrono9tzdb_list5beginEv;
|
||||
_ZNKSt6chrono9tzdb_list5frontEv;
|
||||
_ZNSt6chrono9tzdb_list11erase_afterENS0_14const_iteratorE;
|
||||
_ZNKSt6chrono9tzdb_list14const_iteratordeEv;
|
||||
_ZNSt6chrono9tzdb_list14const_iteratorppEv;
|
||||
_ZNSt6chrono9tzdb_list14const_iteratorppEi;
|
||||
|
||||
} GLIBCXX_3.4.30;
|
||||
|
||||
# Symbols in the support library (libsupc++) have their own tag.
|
||||
|
|
43
libstdc++-v3/configure
vendored
43
libstdc++-v3/configure
vendored
|
@ -961,6 +961,7 @@ enable_libstdcxx_filesystem_ts
|
|||
enable_libstdcxx_backtrace
|
||||
enable_libstdcxx_static_eh_pool
|
||||
with_libstdcxx_eh_pool_obj_count
|
||||
with_libstdcxx_zoneinfo_dir
|
||||
enable_cet
|
||||
with_gxx_include_dir
|
||||
enable_version_specific_runtime_libs
|
||||
|
@ -1704,6 +1705,8 @@ Optional Packages:
|
|||
--with-libstdcxx-eh-pool-obj-count
|
||||
the number of exceptions that can be allocated from
|
||||
the pool if malloc fails
|
||||
--with-libstdcxx-zoneinfo-dir
|
||||
the directory to search for tzdata files
|
||||
--with-gxx-include-dir=DIR
|
||||
installation directory for include files
|
||||
--with-toolexeclibdir=DIR
|
||||
|
@ -12182,7 +12185,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 12185 "configure"
|
||||
#line 12188 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -12288,7 +12291,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 12291 "configure"
|
||||
#line 12294 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -16012,7 +16015,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; }
|
|||
# Fake what AC_TRY_COMPILE does.
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16015 "configure"
|
||||
#line 16018 "configure"
|
||||
int main()
|
||||
{
|
||||
typedef bool atomic_type;
|
||||
|
@ -16047,7 +16050,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; }
|
|||
rm -f conftest*
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16050 "configure"
|
||||
#line 16053 "configure"
|
||||
int main()
|
||||
{
|
||||
typedef short atomic_type;
|
||||
|
@ -16082,7 +16085,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; }
|
|||
rm -f conftest*
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16085 "configure"
|
||||
#line 16088 "configure"
|
||||
int main()
|
||||
{
|
||||
// NB: _Atomic_word not necessarily int.
|
||||
|
@ -16118,7 +16121,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; }
|
|||
rm -f conftest*
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16121 "configure"
|
||||
#line 16124 "configure"
|
||||
int main()
|
||||
{
|
||||
typedef long long atomic_type;
|
||||
|
@ -16274,7 +16277,7 @@ $as_echo "mutex" >&6; }
|
|||
# unnecessary for this test.
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16277 "configure"
|
||||
#line 16280 "configure"
|
||||
int main()
|
||||
{
|
||||
_Decimal32 d1;
|
||||
|
@ -16316,7 +16319,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
|||
# unnecessary for this test.
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 16319 "configure"
|
||||
#line 16322 "configure"
|
||||
template<typename T1, typename T2>
|
||||
struct same
|
||||
{ typedef T2 type; };
|
||||
|
@ -71511,6 +71514,30 @@ fi
|
|||
|
||||
|
||||
|
||||
# For src/c++20/tzdb.cc defaults.
|
||||
|
||||
|
||||
# Check whether --with-libstdcxx-zoneinfo-dir was given.
|
||||
if test "${with_libstdcxx_zoneinfo_dir+set}" = set; then :
|
||||
withval=$with_libstdcxx_zoneinfo_dir; zoneinfo_dir="${withval}"
|
||||
|
||||
$as_echo "#define _GLIBCXX_ZONEINFO_DIR \"\${withval}\"" >>confdefs.h
|
||||
|
||||
|
||||
else
|
||||
|
||||
case "$host" in
|
||||
# *-*-aix*) zoneinfo_dir="/usr/share/lib/zoneinfo" ;;
|
||||
*) zoneinfo_dir="/usr/share/zoneinfo" ;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: zoneinfo data directory: ${zoneinfo_dir}" >&5
|
||||
$as_echo "$as_me: zoneinfo data directory: ${zoneinfo_dir}" >&6;}
|
||||
|
||||
|
||||
# Define documentation rules conditionally.
|
||||
|
||||
# See if makeinfo has been installed and is modern enough
|
||||
|
|
|
@ -535,6 +535,9 @@ GLIBCXX_CHECK_EXCEPTION_PTR_SYMVER
|
|||
# For libsupc++/eh_alloc.cc defaults.
|
||||
GLIBCXX_EMERGENCY_EH_ALLOC
|
||||
|
||||
# For src/c++20/tzdb.cc defaults.
|
||||
GLIBCXX_ZONEINFO_DIR
|
||||
|
||||
# Define documentation rules conditionally.
|
||||
|
||||
# See if makeinfo has been installed and is modern enough
|
||||
|
|
|
@ -46,11 +46,17 @@
|
|||
# include <string>
|
||||
# include <vector>
|
||||
# include <bits/charconv.h> // __to_chars_len, __to_chars_10_impl
|
||||
# include <bits/stl_algo.h> // upper_bound TODO: move leap_second_info to .so
|
||||
# include <bits/stl_algo.h> // upper_bound
|
||||
# include <bits/shared_ptr.h>
|
||||
# include <bits/unique_ptr.h>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// TODO formatting and parsing
|
||||
// # undef __cpp_lib_chrono
|
||||
// # define __cpp_lib_chrono 201907L
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
@ -140,7 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{
|
||||
using _CDur = common_type_t<_Duration, seconds>;
|
||||
const auto __li = chrono::get_leap_second_info(__t);
|
||||
sys_time<_CDur> __s{__t.time_since_epoch() - seconds{__li.elapsed}};
|
||||
sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed};
|
||||
if (__li.is_leap_second)
|
||||
__s = chrono::floor<seconds>(__s) + seconds{1} - _CDur{1};
|
||||
return __s;
|
||||
|
@ -149,13 +155,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template<typename _Duration>
|
||||
[[nodiscard]]
|
||||
static utc_time<common_type_t<_Duration, seconds>>
|
||||
from_sys(const sys_time<_Duration>& __t)
|
||||
{
|
||||
using _CDur = common_type_t<_Duration, seconds>;
|
||||
utc_time<_Duration> __u(__t.time_since_epoch());
|
||||
const auto __li = chrono::get_leap_second_info(__u);
|
||||
return utc_time<_CDur>{__u} + seconds{__li.elapsed};
|
||||
}
|
||||
from_sys(const sys_time<_Duration>& __t);
|
||||
};
|
||||
|
||||
/** A clock that measures International Atomic Time.
|
||||
|
@ -2056,7 +2056,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
- chrono::weekday{sys_days{_M_y / _M_m / 1}}
|
||||
+ days((_M_wdi.index()-1)*7 + 1));
|
||||
__glibcxx_assert(__d.count() >= 1);
|
||||
return __d.count() <= unsigned{(_M_y / _M_m / last).day()};
|
||||
return (unsigned)__d.count() <= (unsigned)(_M_y / _M_m / last).day();
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
|
@ -2500,8 +2500,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
}
|
||||
|
||||
#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
|
||||
// C++20 [time.zones] Time zones
|
||||
|
||||
struct tzdb;
|
||||
|
||||
struct sys_info
|
||||
{
|
||||
sys_seconds begin;
|
||||
|
@ -2532,9 +2535,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ __glibcxx_assert(__i.result == local_info::nonexistent); }
|
||||
|
||||
private:
|
||||
template<typename _Duration> // TODO
|
||||
template<typename _Duration>
|
||||
static string
|
||||
_S_make_what_str(const local_time<_Duration>&, const local_info&);
|
||||
_S_make_what_str(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
{
|
||||
#if 1
|
||||
return "local time is non-existent";
|
||||
#else
|
||||
std::ostringstream __os;
|
||||
__os << __tp << " is in a gap between\n"
|
||||
<< local_seconds(__i.first.end.time_since_epoch())
|
||||
+ __i.first.offset << ' ' << __i.first.abbrev << " and\n"
|
||||
<< local_seconds(__i.second.begin.time_since_epoch())
|
||||
+ __i.second.offset << ' ' << __i.second.abbrev
|
||||
<< " which are both equivalent to\n"
|
||||
<< __i.first.end << " UTC";
|
||||
return std::move(__os).str();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class ambiguous_local_time : public runtime_error
|
||||
|
@ -2542,16 +2561,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
public:
|
||||
template<typename _Duration>
|
||||
ambiguous_local_time(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
const local_info& __i)
|
||||
: runtime_error(_S_make_what_str(__tp, __i))
|
||||
{ __glibcxx_assert(__i.result == local_info::nonexistent); }
|
||||
{ __glibcxx_assert(__i.result == local_info::ambiguous); }
|
||||
|
||||
private:
|
||||
template<typename _Duration> // TODO
|
||||
template<typename _Duration>
|
||||
static string
|
||||
_S_make_what_str(const local_time<_Duration>&, const local_info&);
|
||||
_S_make_what_str(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
{
|
||||
#if 1
|
||||
return "local time is ambiguous";
|
||||
#else
|
||||
std::ostringstream __os;
|
||||
__os << __tp << " is ambiguous. It could be\n"
|
||||
<< __tp << ' ' << __i.first.abbrev << " == "
|
||||
<< __tp - __i.first.offset << " UTC or\n"
|
||||
<< __tp << ' ' << __i.second.abbrev << " == "
|
||||
<< __tp - __i.second.offset << " UTC";
|
||||
return std::move(__os).str();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Duration>
|
||||
[[noreturn]] void
|
||||
__throw_bad_local_time(const local_time<_Duration>& __tp,
|
||||
const local_info& __i)
|
||||
{
|
||||
#if __cpp_exceptions
|
||||
if (__i.result == local_info::nonexistent)
|
||||
throw nonexistent_local_time(__tp, __i);
|
||||
throw ambiguous_local_time(__tp, __i);
|
||||
#else
|
||||
__builtin_abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
enum class choose { earliest, latest };
|
||||
|
||||
class time_zone
|
||||
|
@ -2560,46 +2607,188 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
time_zone(time_zone&&) = default;
|
||||
time_zone& operator=(time_zone&&) = default;
|
||||
|
||||
~time_zone();
|
||||
|
||||
[[nodiscard]]
|
||||
string_view name() const noexcept { return _M_name; }
|
||||
|
||||
template<typename _Duration>
|
||||
sys_info
|
||||
get_info(const sys_time<_Duration>& __st) const;
|
||||
get_info(const sys_time<_Duration>& __st) const
|
||||
{ return _M_get_sys_info(chrono::floor<seconds>(__st)); }
|
||||
|
||||
template<typename _Duration>
|
||||
local_info
|
||||
get_info(const local_time<_Duration>& __tp) const;
|
||||
get_info(const local_time<_Duration>& __tp) const
|
||||
{ return _M_get_local_info(chrono::floor<seconds>(__tp)); }
|
||||
|
||||
template<typename _Duration>
|
||||
sys_time<common_type_t<_Duration, seconds>>
|
||||
to_sys(const local_time<_Duration>& __tp) const;
|
||||
to_sys(const local_time<_Duration>& __tp) const
|
||||
{
|
||||
local_info __info = get_info(__tp);
|
||||
|
||||
if (__info.result != local_info::unique)
|
||||
__throw_bad_local_time(__tp, __info);
|
||||
|
||||
return sys_time<_Duration>(__tp.time_since_epoch())
|
||||
- __info.first.offset;
|
||||
}
|
||||
|
||||
template<typename _Duration>
|
||||
sys_time<common_type_t<_Duration, seconds>>
|
||||
to_sys(const local_time<_Duration>& __tp, choose __z) const;
|
||||
to_sys(const local_time<_Duration>& __tp, choose __z) const
|
||||
{
|
||||
local_info __info = get_info(__tp);
|
||||
|
||||
if (__info.result == local_info::nonexistent)
|
||||
return __info.first.end; // Last second of the previous sys_info.
|
||||
|
||||
sys_time<_Duration> __st(__tp.time_since_epoch());
|
||||
|
||||
if (__info.result == local_info::ambiguous && __z == choose::latest)
|
||||
return __st - __info.second.offset; // Time in the later sys_info.
|
||||
// else if __z == earliest, use __info.first.offset as below:
|
||||
|
||||
return __st - __info.first.offset;
|
||||
}
|
||||
|
||||
template<typename _Duration>
|
||||
local_time<common_type_t<_Duration, seconds>>
|
||||
to_local(const sys_time<_Duration>& __tp) const;
|
||||
to_local(const sys_time<_Duration>& __tp) const
|
||||
{
|
||||
auto __d = (__tp + get_info(__tp).offset).time_since_epoch();
|
||||
return local_time<common_type_t<_Duration, seconds>>(__d);
|
||||
}
|
||||
|
||||
friend bool
|
||||
[[nodiscard]] friend bool
|
||||
operator==(const time_zone& __x, const time_zone& __y) noexcept
|
||||
{ return __x.name() == __y.name(); }
|
||||
{ return __x._M_name == __y._M_name; }
|
||||
|
||||
friend strong_ordering
|
||||
[[nodiscard]] friend strong_ordering
|
||||
operator<=>(const time_zone& __x, const time_zone& __y) noexcept
|
||||
{ return __x.name() <=> __y.name(); }
|
||||
{ return __x._M_name <=> __y._M_name; }
|
||||
|
||||
private:
|
||||
string _M_name;
|
||||
sys_info _M_get_sys_info(sys_seconds) const;
|
||||
local_info _M_get_local_info(local_seconds) const;
|
||||
|
||||
friend const tzdb& reload_tzdb();
|
||||
friend struct tzdb;
|
||||
friend class tzdb_list;
|
||||
|
||||
struct _Impl;
|
||||
|
||||
explicit time_zone(unique_ptr<_Impl> __p);
|
||||
string _M_name;
|
||||
unique_ptr<_Impl> _M_impl;
|
||||
};
|
||||
|
||||
struct tzdb;
|
||||
const time_zone* locate_zone(string_view __tz_name);
|
||||
const time_zone* current_zone();
|
||||
|
||||
/** The list of `chrono::tzdb` objects
|
||||
*
|
||||
* A single object of this type is constructed by the C++ runtime,
|
||||
* and can be accessed by calling `chrono::get_tzdb_list()`.
|
||||
*
|
||||
* The front of the list is the current `tzdb` object and can be accessed
|
||||
* via `chrono::get_tzdb_list().front()` or `chrono::get_tzdb()` or
|
||||
* `*chrono::get_tzdb_list().begin()`.
|
||||
*
|
||||
* The `chrono::reload_tzdb()` function will check for a newer version
|
||||
* and if found, insert it at the front of the list.
|
||||
*
|
||||
* @since C++20
|
||||
*/
|
||||
class tzdb_list
|
||||
{
|
||||
struct _Node;
|
||||
|
||||
public:
|
||||
tzdb_list(const tzdb_list&) = delete;
|
||||
tzdb_list& operator=(const tzdb_list&) = delete;
|
||||
|
||||
/** An iterator into the `tzdb_list`
|
||||
*
|
||||
* As a extension, in libstdc++ each `tzdb` is reference-counted
|
||||
* and the `const_iterator` type shares ownership of the object it
|
||||
* refers to. This ensures that a `tzdb` erased from the list will
|
||||
* not be destroyed while there is an iterator that refers to it.
|
||||
*/
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
using value_type = tzdb;
|
||||
using reference = const tzdb&;
|
||||
using pointer = const tzdb*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = forward_iterator_tag;
|
||||
|
||||
constexpr const_iterator() = default;
|
||||
const_iterator(const const_iterator&) = default;
|
||||
const_iterator(const_iterator&&) = default;
|
||||
const_iterator& operator=(const const_iterator&) = default;
|
||||
const_iterator& operator=(const_iterator&&) = default;
|
||||
|
||||
reference operator*() const noexcept;
|
||||
pointer operator->() const noexcept { return &**this; }
|
||||
const_iterator& operator++();
|
||||
const_iterator operator++(int);
|
||||
|
||||
bool operator==(const const_iterator&) const noexcept = default;
|
||||
|
||||
private:
|
||||
explicit const_iterator(const shared_ptr<_Node>&) noexcept;
|
||||
|
||||
friend class tzdb_list;
|
||||
|
||||
shared_ptr<_Node> _M_node;
|
||||
void* _M_reserved = nullptr;
|
||||
};
|
||||
|
||||
/** Access the current `tzdb` at the front of the list.
|
||||
*
|
||||
* This returns a reference to the same object as `chrono::get_tzdb()`.
|
||||
*
|
||||
* @returns A reference to the current tzdb object.
|
||||
* @since C++20
|
||||
*/
|
||||
const tzdb& front() const noexcept;
|
||||
|
||||
/** Remove the tzdb object _after_ the one the iterator refers to.
|
||||
*
|
||||
* Calling this function concurently with any of `front()`, `begin()`,
|
||||
* or `end()` does not cause a data race, but in general this function
|
||||
* is not thread-safe. The behaviour may be undefined if erasing an
|
||||
* element from the list while another thread is calling the same
|
||||
* function, or incrementing an iterator into the list, or accessing
|
||||
* the element being erased (unless it is accessed through an iterator).
|
||||
*
|
||||
* @param __p A dereferenceable iterator.
|
||||
* @returns An iterator the element after the one that was erased
|
||||
* (or `end()` if there is no such element).
|
||||
* @since C++20
|
||||
*/
|
||||
const_iterator erase_after(const_iterator __p);
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept { return {}; }
|
||||
const_iterator cbegin() const noexcept { return begin(); }
|
||||
const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
private:
|
||||
constexpr explicit tzdb_list(nullptr_t);
|
||||
|
||||
friend tzdb_list& get_tzdb_list();
|
||||
friend const tzdb& get_tzdb();
|
||||
friend const tzdb& reload_tzdb();
|
||||
friend struct tzdb;
|
||||
friend class leap_second;
|
||||
friend struct time_zone::_Impl;
|
||||
friend class time_zone_link;
|
||||
};
|
||||
|
||||
class time_zone_link
|
||||
{
|
||||
public:
|
||||
|
@ -2619,7 +2808,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
private:
|
||||
friend const tzdb& reload_tzdb();
|
||||
// TODO unspecified additional constructors
|
||||
friend class tzdb_list::_Node;
|
||||
|
||||
explicit time_zone_link(nullptr_t) { }
|
||||
|
||||
string _M_name;
|
||||
string _M_target;
|
||||
};
|
||||
|
@ -2720,10 +2912,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
private:
|
||||
explicit leap_second(seconds::rep __s) : _M_s(__s) { }
|
||||
|
||||
friend class tzdb_list::_Node;
|
||||
|
||||
friend const tzdb& reload_tzdb();
|
||||
template<typename _Dur>
|
||||
|
||||
template<typename _Duration>
|
||||
friend leap_second_info
|
||||
get_leap_second_info(const utc_time<_Dur>&);
|
||||
get_leap_second_info(const utc_time<_Duration>&);
|
||||
|
||||
seconds _M_s; // == date().time_since_epoch() * value().count()
|
||||
};
|
||||
|
@ -2745,9 +2940,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct tzdb
|
||||
{
|
||||
string version;
|
||||
vector<time_zone> zones;
|
||||
vector<time_zone_link> links;
|
||||
vector<leap_second> leap_seconds;
|
||||
_GLIBCXX_STD_C::vector<time_zone> zones;
|
||||
_GLIBCXX_STD_C::vector<time_zone_link> links;
|
||||
_GLIBCXX_STD_C::vector<leap_second> leap_seconds;
|
||||
|
||||
const time_zone*
|
||||
locate_zone(string_view __tz_name) const;
|
||||
|
@ -2757,146 +2952,353 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
private:
|
||||
friend const tzdb& reload_tzdb();
|
||||
|
||||
struct _Rule;
|
||||
vector<_Rule> _M_rules;
|
||||
friend class time_zone;
|
||||
friend class tzdb_list::_Node;
|
||||
};
|
||||
|
||||
class tzdb_list
|
||||
{
|
||||
struct _Node;
|
||||
public:
|
||||
tzdb_list(const tzdb_list&) = delete;
|
||||
tzdb_list& operator=(const tzdb_list&) = delete;
|
||||
tzdb_list& get_tzdb_list();
|
||||
const tzdb& get_tzdb();
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
using value_type = tzdb;
|
||||
using reference = const tzdb&;
|
||||
using pointer = const tzdb*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = forward_iterator_tag;
|
||||
|
||||
constexpr const_iterator() = default;
|
||||
const_iterator(const const_iterator&) = default;
|
||||
const_iterator(const_iterator&&) = default;
|
||||
const_iterator& operator=(const const_iterator&) = default;
|
||||
const_iterator& operator=(const_iterator&&) = default;
|
||||
|
||||
reference operator*() const noexcept;
|
||||
pointer operator->() const noexcept { return &**this; }
|
||||
const_iterator& operator++();
|
||||
const_iterator operator++(int);
|
||||
|
||||
bool operator==(const const_iterator&) const noexcept = default;
|
||||
|
||||
private:
|
||||
explicit const_iterator(const shared_ptr<_Node>&) noexcept;
|
||||
|
||||
shared_ptr<_Node> _M_node;
|
||||
void* _M_reserved = nullptr;
|
||||
};
|
||||
|
||||
// TODO const tzdb& front() const noexcept;
|
||||
|
||||
const_iterator erase_after(const_iterator);
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept { return {}; }
|
||||
const_iterator cbegin() const noexcept { return begin(); }
|
||||
const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
private:
|
||||
constexpr explicit tzdb_list(nullptr_t);
|
||||
|
||||
friend const tzdb_list& get_tzdb_list();
|
||||
friend const tzdb& get_tzdb();
|
||||
friend const tzdb& reload_tzdb();
|
||||
|
||||
static _Node* _S_head;
|
||||
static shared_ptr<_Node> _S_head_owner;
|
||||
};
|
||||
|
||||
// TODO
|
||||
// const tzdb_list& get_tzdb_list();
|
||||
// const tzdb& get_tzdb();
|
||||
|
||||
// const tzdb& reload_tzdb();
|
||||
// string remove_version();
|
||||
const tzdb& reload_tzdb();
|
||||
string remote_version();
|
||||
|
||||
template<typename _Duration, typename _TimeZonePtr = const time_zone*>
|
||||
class zoned_time; // TODO
|
||||
class zoned_time
|
||||
{
|
||||
static_assert(__is_duration_v<_Duration>);
|
||||
|
||||
using zoned_seconds = zoned_time<seconds>;
|
||||
using _Traits = zoned_traits<_TimeZonePtr>;
|
||||
|
||||
// Every constructor that accepts a string_view as its first parameter
|
||||
// does not participate in class template argument deduction.
|
||||
using string_view = type_identity_t<std::string_view>;
|
||||
|
||||
public:
|
||||
using duration = common_type_t<_Duration, seconds>;
|
||||
|
||||
zoned_time() requires requires { _Traits::default_zone(); }
|
||||
{ }
|
||||
|
||||
zoned_time(const zoned_time&) = default;
|
||||
zoned_time& operator=(const zoned_time&) = default;
|
||||
|
||||
zoned_time(const sys_time<_Duration>& __st)
|
||||
requires requires { _Traits::default_zone(); }
|
||||
: _M_tp(__st)
|
||||
{ }
|
||||
|
||||
explicit
|
||||
zoned_time(_TimeZonePtr __z) : _M_zone(std::move(__z)) { }
|
||||
|
||||
explicit
|
||||
zoned_time(string_view __name)
|
||||
requires requires {
|
||||
_TimeZonePtr{_Traits::locate_zone(std::string_view{})};
|
||||
}
|
||||
: _M_zone(_Traits::locate_zone(__name))
|
||||
{ }
|
||||
|
||||
template<typename _Duration2>
|
||||
zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& __zt)
|
||||
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
|
||||
: _M_zone(__zt._M_zone), _M_tp(__zt._M_tp)
|
||||
{ }
|
||||
|
||||
zoned_time(_TimeZonePtr __z, const sys_time<_Duration>& __st)
|
||||
: _M_zone(std::move(__z)), _M_tp(__st)
|
||||
{ }
|
||||
|
||||
zoned_time(string_view __name, const sys_time<_Duration>& __st)
|
||||
: zoned_time(_Traits::locate_zone(__name), __st)
|
||||
{ }
|
||||
|
||||
zoned_time(_TimeZonePtr __z, const local_time<_Duration>& __tp)
|
||||
requires requires {
|
||||
{ __z->to_sys(__tp) } -> convertible_to<sys_time<_Duration>>;
|
||||
}
|
||||
: _M_zone(std::move(__z)), _M_tp(_M_zone->to_sys(__tp))
|
||||
{ }
|
||||
|
||||
zoned_time(string_view __name, const local_time<_Duration>& __tp)
|
||||
requires requires (_TimeZonePtr __z) {
|
||||
{ _Traits::locate_zone(__name) } -> convertible_to<_TimeZonePtr>;
|
||||
{ __z->to_sys(__tp) } -> convertible_to<sys_time<_Duration>>;
|
||||
}
|
||||
: zoned_time(_Traits::locate_zone(__name), __tp)
|
||||
{ }
|
||||
|
||||
zoned_time(_TimeZonePtr __z, const local_time<_Duration>& __tp,
|
||||
choose __c)
|
||||
requires requires {
|
||||
{ __z->to_sys(__tp, __c) } -> convertible_to<sys_time<_Duration>>;
|
||||
}
|
||||
: _M_zone(std::move(__z)), _M_tp(_M_zone->to_sys(__tp, __c))
|
||||
{ }
|
||||
|
||||
zoned_time(string_view __name, const local_time<_Duration>& __tp,
|
||||
choose __c)
|
||||
requires requires (_TimeZonePtr __z) {
|
||||
{ _Traits::locate_zone(__name) } -> convertible_to<_TimeZonePtr>;
|
||||
{ __z->to_sys(__tp, __c) } -> convertible_to<sys_time<_Duration>>;
|
||||
}
|
||||
: _M_zone(_Traits::locate_zone(__name)),
|
||||
_M_tp(_M_zone->to_sys(__tp, __c))
|
||||
{ }
|
||||
|
||||
template<typename _Duration2, typename _TimeZonePtr2>
|
||||
zoned_time(_TimeZonePtr __z,
|
||||
const zoned_time<_Duration2, _TimeZonePtr2>& __zt)
|
||||
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
|
||||
: _M_zone(__z), _M_tp(__zt._M_tp)
|
||||
{ }
|
||||
|
||||
template<typename _Duration2, typename _TimeZonePtr2>
|
||||
zoned_time(_TimeZonePtr __z,
|
||||
const zoned_time<_Duration2, _TimeZonePtr2>& __zt,
|
||||
choose __c)
|
||||
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
|
||||
: _M_zone(__z), _M_tp(__zt._M_tp)
|
||||
{ }
|
||||
|
||||
template<typename _Duration2, typename _TimeZonePtr2>
|
||||
zoned_time(string_view __name,
|
||||
const zoned_time<_Duration2, _TimeZonePtr2>& __zt)
|
||||
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
|
||||
&& requires {
|
||||
{ _Traits::locate_zone(__name) } -> convertible_to<_TimeZonePtr>;
|
||||
}
|
||||
: _M_zone(_Traits::locate_zone(__name)), _M_tp(__zt._M_tp)
|
||||
{ }
|
||||
|
||||
template<typename _Duration2, typename _TimeZonePtr2>
|
||||
zoned_time(string_view __name,
|
||||
const zoned_time<_Duration2, _TimeZonePtr2>& __zt,
|
||||
choose __c)
|
||||
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
|
||||
&& requires {
|
||||
{ _Traits::locate_zone(__name) } -> convertible_to<_TimeZonePtr>;
|
||||
}
|
||||
: _M_zone(_Traits::locate_zone(__name)), _M_tp(__zt._M_tp)
|
||||
{ }
|
||||
|
||||
zoned_time&
|
||||
operator=(const sys_time<_Duration>& __st)
|
||||
{
|
||||
_M_tp = __st;
|
||||
return *this;
|
||||
}
|
||||
|
||||
zoned_time&
|
||||
operator=(const local_time<_Duration>& __lt)
|
||||
{
|
||||
_M_tp = _M_zone->to_sys(__lt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
operator sys_time<duration>() const { return _M_tp; }
|
||||
|
||||
[[nodiscard]]
|
||||
explicit operator local_time<duration>() const
|
||||
{ return get_local_time(); }
|
||||
|
||||
[[nodiscard]]
|
||||
_TimeZonePtr
|
||||
get_time_zone() const
|
||||
{ return _M_zone; }
|
||||
|
||||
[[nodiscard]]
|
||||
local_time<duration>
|
||||
get_local_time() const
|
||||
{ return _M_zone->to_local(_M_tp); }
|
||||
|
||||
[[nodiscard]]
|
||||
sys_time<duration>
|
||||
get_sys_time() const
|
||||
{ return _M_tp; }
|
||||
|
||||
[[nodiscard]]
|
||||
sys_info
|
||||
get_info() const
|
||||
{ return _M_zone->get_info(_M_tp); }
|
||||
|
||||
[[nodiscard]] friend bool
|
||||
operator==(const zoned_time&, const zoned_time&) = default;
|
||||
|
||||
private:
|
||||
_TimeZonePtr _M_zone{ _Traits::default_zone() };
|
||||
sys_time<duration> _M_tp{};
|
||||
|
||||
template<typename _Duration2, typename _TimeZonePtr2>
|
||||
friend class zoned_time;
|
||||
};
|
||||
|
||||
zoned_time() -> zoned_time<seconds>;
|
||||
|
||||
template<typename _Duration>
|
||||
leap_second_info
|
||||
zoned_time(sys_time<_Duration>)
|
||||
-> zoned_time<common_type_t<_Duration, seconds>>;
|
||||
|
||||
/// @cond undocumented
|
||||
template<typename _TimeZonePtrOrName>
|
||||
using __time_zone_representation
|
||||
= __conditional_t<is_convertible_v<_TimeZonePtrOrName, string_view>,
|
||||
const time_zone*,
|
||||
remove_cvref_t<_TimeZonePtrOrName>>;
|
||||
/// @endcond
|
||||
|
||||
template<typename _TimeZonePtrOrName>
|
||||
zoned_time(_TimeZonePtrOrName&&)
|
||||
-> zoned_time<seconds, __time_zone_representation<_TimeZonePtrOrName>>;
|
||||
|
||||
template<typename _TimeZonePtrOrName, typename _Duration>
|
||||
zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>)
|
||||
-> zoned_time<common_type_t<_Duration, seconds>,
|
||||
__time_zone_representation<_TimeZonePtrOrName>>;
|
||||
|
||||
template<typename _TimeZonePtrOrName, typename _Duration>
|
||||
zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>,
|
||||
choose = choose::earliest)
|
||||
-> zoned_time<common_type_t<_Duration, seconds>,
|
||||
__time_zone_representation<_TimeZonePtrOrName>>;
|
||||
|
||||
template<typename _Duration, typename _TimeZonePtrOrName,
|
||||
typename _TimeZonePtr2>
|
||||
zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, _TimeZonePtr2>,
|
||||
choose = choose::earliest)
|
||||
-> zoned_time<common_type_t<_Duration, seconds>,
|
||||
__time_zone_representation<_TimeZonePtrOrName>>;
|
||||
|
||||
template<typename _Dur1, typename _TZPtr1, typename _Dur2, typename _TZPtr2>
|
||||
[[nodiscard]]
|
||||
inline bool
|
||||
operator==(const zoned_time<_Dur1, _TZPtr1>& __x,
|
||||
const zoned_time<_Dur2, _TZPtr2>& __y)
|
||||
{
|
||||
return __x.get_time_zone() == __y.get_time_zone()
|
||||
&& __x.get_sys_time() == __y.get_sys_time();
|
||||
}
|
||||
|
||||
using zoned_seconds = zoned_time<seconds>;
|
||||
#endif // _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
inline leap_second_info
|
||||
__get_leap_second_info(sys_seconds __ss, bool __is_utc)
|
||||
{
|
||||
if (__ss < sys_seconds{}) [[unlikely]]
|
||||
return {};
|
||||
|
||||
const seconds::rep __leaps[] {
|
||||
78796800, // 1 Jul 1972
|
||||
94694400, // 1 Jan 1973
|
||||
126230400, // 1 Jan 1974
|
||||
157766400, // 1 Jan 1975
|
||||
189302400, // 1 Jan 1976
|
||||
220924800, // 1 Jan 1977
|
||||
252460800, // 1 Jan 1978
|
||||
283996800, // 1 Jan 1979
|
||||
315532800, // 1 Jan 1980
|
||||
362793600, // 1 Jul 1981
|
||||
394329600, // 1 Jul 1982
|
||||
425865600, // 1 Jul 1983
|
||||
489024000, // 1 Jul 1985
|
||||
567993600, // 1 Jan 1988
|
||||
631152000, // 1 Jan 1990
|
||||
662688000, // 1 Jan 1991
|
||||
709948800, // 1 Jul 1992
|
||||
741484800, // 1 Jul 1993
|
||||
773020800, // 1 Jul 1994
|
||||
820454400, // 1 Jan 1996
|
||||
867715200, // 1 Jul 1997
|
||||
915148800, // 1 Jan 1999
|
||||
1136073600, // 1 Jan 2006
|
||||
1230768000, // 1 Jan 2009
|
||||
1341100800, // 1 Jul 2012
|
||||
1435708800, // 1 Jul 2015
|
||||
1483228800, // 1 Jan 2017
|
||||
};
|
||||
// The list above is known to be valid until (at least) this date
|
||||
// and only contains positive leap seconds.
|
||||
const sys_seconds __expires(1687910400s); // 2023-06-28 00:00:00 UTC
|
||||
|
||||
#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
|
||||
if (__ss > __expires)
|
||||
{
|
||||
// Use updated leap_seconds from tzdb.
|
||||
size_t __n = std::size(__leaps);
|
||||
|
||||
auto __db = get_tzdb_list().begin();
|
||||
auto __first = __db->leap_seconds.begin() + __n;
|
||||
auto __last = __db->leap_seconds.end();
|
||||
auto __pos = std::upper_bound(__first, __last, __ss);
|
||||
seconds __elapsed(__n);
|
||||
for (auto __i = __first; __i != __pos; ++__i)
|
||||
__elapsed += __i->value();
|
||||
|
||||
if (__is_utc)
|
||||
{
|
||||
// Convert utc_time to sys_time:
|
||||
__ss -= __elapsed;
|
||||
// See if that sys_time is before (or during) previous leap sec:
|
||||
if (__pos != __first && __ss < __pos[-1])
|
||||
{
|
||||
if ((__ss + 1s) >= __pos[-1])
|
||||
return {true, __elapsed};
|
||||
__elapsed -= __pos[-1].value();
|
||||
}
|
||||
}
|
||||
return {false, __elapsed};
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
seconds::rep __s = __ss.time_since_epoch().count();
|
||||
const seconds::rep* __first = std::begin(__leaps);
|
||||
const seconds::rep* __last = std::end(__leaps);
|
||||
|
||||
// Don't bother searching the list if we're after the last one.
|
||||
if (__s > (__last[-1] + (__last - __first) + 1))
|
||||
return { false, seconds(__last - __first) };
|
||||
|
||||
auto __pos = std::upper_bound(__first, __last, __s);
|
||||
seconds __elapsed{__pos - __first};
|
||||
if (__is_utc)
|
||||
{
|
||||
// Convert utc_time to sys_time:
|
||||
__s -= __elapsed.count();
|
||||
// See if that sys_time is before (or during) previous leap sec:
|
||||
if (__pos != __first && __s < __pos[-1])
|
||||
{
|
||||
if ((__s + 1) >= __pos[-1])
|
||||
return {true, __elapsed};
|
||||
--__elapsed;
|
||||
}
|
||||
}
|
||||
return {false, __elapsed};
|
||||
}
|
||||
}
|
||||
} // namespace __detail
|
||||
|
||||
template<typename _Duration>
|
||||
[[nodiscard]]
|
||||
inline leap_second_info
|
||||
get_leap_second_info(const utc_time<_Duration>& __ut)
|
||||
{
|
||||
if constexpr (is_same_v<_Duration, seconds>)
|
||||
{
|
||||
const seconds::rep __leaps[] {
|
||||
78796800, // 1 Jul 1972
|
||||
94694400, // 1 Jan 1973
|
||||
126230400, // 1 Jan 1974
|
||||
157766400, // 1 Jan 1975
|
||||
189302400, // 1 Jan 1976
|
||||
220924800, // 1 Jan 1977
|
||||
252460800, // 1 Jan 1978
|
||||
283996800, // 1 Jan 1979
|
||||
315532800, // 1 Jan 1980
|
||||
362793600, // 1 Jul 1981
|
||||
394329600, // 1 Jul 1982
|
||||
425865600, // 1 Jul 1983
|
||||
489024000, // 1 Jul 1985
|
||||
567993600, // 1 Jan 1988
|
||||
631152000, // 1 Jan 1990
|
||||
662688000, // 1 Jan 1991
|
||||
709948800, // 1 Jul 1992
|
||||
741484800, // 1 Jul 1993
|
||||
773020800, // 1 Jul 1994
|
||||
820454400, // 1 Jan 1996
|
||||
867715200, // 1 Jul 1997
|
||||
915148800, // 1 Jan 1999
|
||||
1136073600, // 1 Jan 2006
|
||||
1230768000, // 1 Jan 2009
|
||||
1341100800, // 1 Jul 2012
|
||||
1435708800, // 1 Jul 2015
|
||||
1483228800, // 1 Jan 2017
|
||||
};
|
||||
// The list above is known to be valid until 2023-06-28 00:00:00 UTC
|
||||
const seconds::rep __expires = 1687910400;
|
||||
const seconds::rep __s = __ut.time_since_epoch().count();
|
||||
auto __s = chrono::duration_cast<seconds>(__ut.time_since_epoch());
|
||||
return __detail::__get_leap_second_info(sys_seconds(__s), true);
|
||||
}
|
||||
|
||||
const seconds::rep* __first = std::begin(__leaps);
|
||||
const seconds::rep* __last = std::end(__leaps);
|
||||
|
||||
if (__s > __expires)
|
||||
{
|
||||
// TODO: use updated leap_seconds from tzdb
|
||||
#if 0
|
||||
auto __db = get_tzdb_list().begin();
|
||||
__first = __db->leap_seconds.data();
|
||||
__last = __first + __db->leap_seconds.size();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Don't bother searching the list if we're after the last one.
|
||||
if (__s > __last[-1])
|
||||
return { false, seconds(__last - __first) };
|
||||
|
||||
auto __pos = std::upper_bound(__first, __last, __s);
|
||||
return {
|
||||
__pos != begin(__leaps) && __pos[-1] == __s,
|
||||
seconds{__pos - __first}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto __s = chrono::time_point_cast<seconds>(__ut);
|
||||
return chrono::get_leap_second_info(__s);
|
||||
}
|
||||
template<typename _Duration>
|
||||
[[nodiscard]]
|
||||
inline utc_time<common_type_t<_Duration, seconds>>
|
||||
utc_clock::from_sys(const sys_time<_Duration>& __t)
|
||||
{
|
||||
using _CDur = common_type_t<_Duration, seconds>;
|
||||
auto __s = chrono::time_point_cast<seconds>(__t);
|
||||
const auto __li = __detail::__get_leap_second_info(__s, false);
|
||||
return utc_time<_CDur>{__t.time_since_epoch()} + __li.elapsed;
|
||||
}
|
||||
|
||||
/// @} group chrono
|
||||
|
|
|
@ -251,6 +251,8 @@
|
|||
# define __cpp_lib_barrier 201907L
|
||||
# endif
|
||||
#endif
|
||||
// #undef __cpp_lib_chrono
|
||||
// #define __cpp_lib_chrono 201907L
|
||||
// FIXME: #define __cpp_lib_execution 201902L
|
||||
#define __cpp_lib_constexpr_algorithms 201806L
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
|
|
|
@ -36,7 +36,7 @@ else
|
|||
inst_sources =
|
||||
endif
|
||||
|
||||
sources =
|
||||
sources = tzdb.cc
|
||||
|
||||
vpath % $(top_srcdir)/src/c++20
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ CONFIG_CLEAN_FILES =
|
|||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libc__20convenience_la_LIBADD =
|
||||
am__objects_1 =
|
||||
am__objects_1 = tzdb.lo
|
||||
@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = sstream-inst.lo
|
||||
am_libc__20convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2)
|
||||
libc__20convenience_la_OBJECTS = $(am_libc__20convenience_la_OBJECTS)
|
||||
|
@ -431,7 +431,7 @@ headers =
|
|||
@ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = \
|
||||
@ENABLE_EXTERN_TEMPLATE_TRUE@ sstream-inst.cc
|
||||
|
||||
sources =
|
||||
sources = tzdb.cc
|
||||
libc__20convenience_la_SOURCES = $(sources) $(inst_sources)
|
||||
|
||||
# AM_CXXFLAGS needs to be in each subdirectory so that it can be
|
||||
|
|
1806
libstdc++-v3/src/c++20/tzdb.cc
Normal file
1806
libstdc++-v3/src/c++20/tzdb.cc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1397,6 +1397,20 @@ proc check_effective_target_hosted { } {
|
|||
}]
|
||||
}
|
||||
|
||||
# Return 1 if std::chrono::tzdb is supported.
|
||||
proc check_effective_target_tzdb { } {
|
||||
if {![check_effective_target_cxx11_abi]} {
|
||||
return 0
|
||||
}
|
||||
return [check_v3_target_prop_cached et_tzdb {
|
||||
set cond "defined _GLIBCXX_ZONEINFO_DIR"
|
||||
if {[v3_check_preprocessor_condition tzdb $cond]} {
|
||||
return 1
|
||||
}
|
||||
return [file exists /usr/share/zoneinfo/tzdata.zi]
|
||||
}]
|
||||
}
|
||||
|
||||
set additional_prunes ""
|
||||
|
||||
if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \
|
||||
|
|
|
@ -32,8 +32,19 @@ test01()
|
|||
VERIFY( d2 == d1 );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
file_time<file_clock::duration> t = file_clock::now();
|
||||
file_time<seconds> s = floor<seconds>(t);
|
||||
VERIFY( t - s < 1s );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
||||
|
|
|
@ -31,8 +31,26 @@ test02()
|
|||
VERIFY( clock_cast<gps_clock>(clock_cast<utc_clock>(t)) == t );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
gps_time<gps_clock::duration> gps1 = gps_clock::now();
|
||||
utc_time<utc_clock::duration> utc = utc_clock::now();
|
||||
gps_time<gps_clock::duration> gps2 = gps_clock::now();
|
||||
|
||||
auto delta = gps2 - gps1;
|
||||
VERIFY( (utc - clock_cast<utc_clock>(gps1)) <= delta );
|
||||
VERIFY( (clock_cast<utc_clock>(gps2) - utc) <= delta );
|
||||
|
||||
gps_seconds s = time_point_cast<seconds>(gps1);
|
||||
VERIFY( gps1 - s < 1s );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
}
|
||||
|
|
|
@ -34,8 +34,26 @@ test02()
|
|||
VERIFY( clock_cast<tai_clock>(clock_cast<utc_clock>(t)) == t );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
tai_time<tai_clock::duration> tai1 = tai_clock::now();
|
||||
utc_time<utc_clock::duration> utc = utc_clock::now();
|
||||
tai_time<tai_clock::duration> tai2 = tai_clock::now();
|
||||
|
||||
auto delta = tai2 - tai1;
|
||||
VERIFY( (utc - clock_cast<utc_clock>(tai1)) <= delta );
|
||||
VERIFY( (clock_cast<utc_clock>(tai2) - utc) <= delta );
|
||||
|
||||
tai_seconds s = time_point_cast<seconds>(tai1);
|
||||
VERIFY( tai1 - s < 1s );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-additional-options "-DHAVE_TZDB" { target tzdb } }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void
|
||||
test_before()
|
||||
{
|
||||
// No leaps seconds defined before the epoch.
|
||||
auto s = std::chrono::utc_seconds(-1s);
|
||||
auto lsi = get_leap_second_info(s);
|
||||
VERIFY( lsi.is_leap_second == false );
|
||||
VERIFY( lsi.elapsed == 0s );
|
||||
|
||||
auto ms = std::chrono::utc_time<std::chrono::milliseconds>(s - 5500ms);
|
||||
lsi = get_leap_second_info(ms);
|
||||
VERIFY( lsi.is_leap_second == false );
|
||||
VERIFY( lsi.elapsed == 0s );
|
||||
}
|
||||
|
||||
void
|
||||
test_after()
|
||||
{
|
||||
#ifdef HAVE_TZDB
|
||||
const auto& leaps = std::chrono::get_tzdb().leap_seconds;
|
||||
std::chrono::seconds sum(0);
|
||||
for (auto leap : leaps)
|
||||
sum += leap.value();
|
||||
|
||||
// After the last defined leap second.
|
||||
auto last = leaps.back().date().time_since_epoch();
|
||||
auto ut = std::chrono::utc_time<std::chrono::milliseconds>(last + 72h + 10ms);
|
||||
auto lsi = get_leap_second_info(ut);
|
||||
VERIFY( lsi.is_leap_second == false );
|
||||
VERIFY( lsi.elapsed == sum );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
test_between()
|
||||
{
|
||||
std::chrono::sys_days st(1995y/9/4);
|
||||
auto ut = std::chrono::clock_cast<std::chrono::utc_clock>(st);
|
||||
auto lsi = get_leap_second_info(ut);
|
||||
VERIFY( lsi.is_leap_second == false );
|
||||
VERIFY( lsi.elapsed == 19s );
|
||||
}
|
||||
|
||||
void
|
||||
test_during()
|
||||
{
|
||||
#ifdef HAVE_TZDB
|
||||
// Verify that leap_second_info::is_leap_second is true for each leap second.
|
||||
const auto& leaps = std::chrono::get_tzdb().leap_seconds;
|
||||
for (const auto& leap : leaps)
|
||||
{
|
||||
// N.B. this assumes all leap seconds are positive:
|
||||
std::chrono::seconds elapsed(&leap - &leaps.front());
|
||||
std::chrono::utc_seconds ut(leap.date().time_since_epoch() + elapsed);
|
||||
auto lsi = get_leap_second_info(ut);
|
||||
VERIFY( lsi.is_leap_second == true );
|
||||
VERIFY( lsi.elapsed == elapsed + 1s );
|
||||
lsi = get_leap_second_info(ut + 999ms);
|
||||
VERIFY( lsi.is_leap_second == true );
|
||||
VERIFY( lsi.elapsed == elapsed + 1s );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_before();
|
||||
test_after();
|
||||
test_between();
|
||||
test_during();
|
||||
}
|
49
libstdc++-v3/testsuite/std/time/exceptions.cc
Normal file
49
libstdc++-v3/testsuite/std/time/exceptions.cc
Normal file
|
@ -0,0 +1,49 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target tzdb }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_nonexistent()
|
||||
{
|
||||
std::string expected
|
||||
= "2016-03-13 02:30:00 is in a gap between\n"
|
||||
"2016-03-13 02:00:00 EST and\n"
|
||||
"2016-03-13 03:00:00 EDT which are both equivalent to\n"
|
||||
"2016-03-13 07:00:00 UTC";
|
||||
|
||||
using namespace std::chrono;
|
||||
try {
|
||||
auto zt = zoned_time{"America/New_York",
|
||||
local_days{Sunday[2]/March/2016} + 2h + 30min};
|
||||
VERIFY(false);
|
||||
} catch (const nonexistent_local_time& e) {
|
||||
// VERIFY( e.what() == expected );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_ambiguous()
|
||||
{
|
||||
std::string expected
|
||||
= "2016-11-06 01:30:00 is ambiguous. It could be\n"
|
||||
"2016-11-06 01:30:00 EDT == 2016-11-06 05:30:00 UTC or\n"
|
||||
"2016-11-06 01:30:00 EST == 2016-11-06 06:30:00 UTC";
|
||||
|
||||
using namespace std::chrono;
|
||||
try {
|
||||
auto zt = zoned_time{"America/New_York",
|
||||
local_days{Sunday[1]/November/2016} + 1h + 30min};
|
||||
VERIFY(false);
|
||||
} catch (const ambiguous_local_time& e) {
|
||||
// VERIFY( e.what() == expected );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_nonexistent();
|
||||
test_ambiguous();
|
||||
}
|
|
@ -43,8 +43,6 @@ namespace __gnu_test
|
|||
using std::chrono::sys_seconds;
|
||||
using std::chrono::sys_days;
|
||||
|
||||
// FIXME
|
||||
#if 0
|
||||
using std::chrono::utc_clock;
|
||||
using std::chrono::utc_time;
|
||||
using std::chrono::utc_seconds;
|
||||
|
@ -59,7 +57,6 @@ namespace __gnu_test
|
|||
using std::chrono::gps_clock;
|
||||
using std::chrono::gps_time;
|
||||
using std::chrono::gps_seconds;
|
||||
#endif
|
||||
|
||||
using std::chrono::file_clock;
|
||||
using std::chrono::file_time;
|
||||
|
@ -69,13 +66,10 @@ namespace __gnu_test
|
|||
using std::chrono::local_seconds;
|
||||
using std::chrono::local_days;
|
||||
|
||||
// FIXME
|
||||
#if 0
|
||||
using std::chrono::clock_time_conversion;
|
||||
using std::chrono::clock_cast;
|
||||
|
||||
using std::chrono::last_spec;
|
||||
#endif
|
||||
|
||||
using std::chrono::day;
|
||||
using std::chrono::month;
|
||||
|
@ -101,8 +95,7 @@ namespace __gnu_test
|
|||
using std::chrono::make12;
|
||||
using std::chrono::make24;
|
||||
|
||||
// FIXME
|
||||
#if 0
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
using std::chrono::tzdb;
|
||||
using std::chrono::tzdb_list;
|
||||
using std::chrono::get_tzdb;
|
||||
|
@ -129,12 +122,14 @@ namespace __gnu_test
|
|||
using std::chrono::leap_second;
|
||||
|
||||
using std::chrono::time_zone_link;
|
||||
|
||||
using std::chrono::local_time_format;
|
||||
|
||||
using std::chrono::parse;
|
||||
#endif
|
||||
|
||||
// FIXME
|
||||
// using std::chrono::local_time_format;
|
||||
|
||||
// FIXME
|
||||
// using std::chrono::parse;
|
||||
|
||||
using std::chrono::last;
|
||||
using std::chrono::Sunday;
|
||||
using std::chrono::Monday;
|
||||
|
|
222
libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
Normal file
222
libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
Normal file
|
@ -0,0 +1,222 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target tzdb }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
struct empty_tag { } empty;
|
||||
|
||||
bool operator==(const sys_info& info, empty_tag)
|
||||
{
|
||||
return info.begin == sys_seconds() && info.end == info.begin
|
||||
&& info.offset == 0s && info.save == 0min && info.abbrev.empty();
|
||||
}
|
||||
|
||||
void
|
||||
test_utc()
|
||||
{
|
||||
auto tz = locate_zone("UTC");
|
||||
auto now = time_point_cast<seconds>(system_clock::now());
|
||||
local_info info = tz->get_info(local_seconds(now.time_since_epoch()));
|
||||
VERIFY( info.result == local_info::unique );
|
||||
VERIFY( info.first.begin < now );
|
||||
VERIFY( info.first.end > now );
|
||||
VERIFY( info.first.offset == 0h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "UTC" );
|
||||
VERIFY( info.second == empty );
|
||||
}
|
||||
|
||||
auto dst_start = March/Sunday[last];
|
||||
auto dst_end = October/Sunday[last];
|
||||
|
||||
void
|
||||
test_unique()
|
||||
{
|
||||
auto tz = locate_zone("Europe/London");
|
||||
local_days feb1(sys_days(2022y/February/1).time_since_epoch());
|
||||
local_info info;
|
||||
|
||||
info = tz->get_info(feb1);
|
||||
VERIFY( info.result == local_info::unique );
|
||||
VERIFY( info.first.begin == sys_days(2021y/dst_end) + 1h );
|
||||
VERIFY( info.first.end == sys_days(2022y/dst_start) + 1h );
|
||||
VERIFY( info.first.offset == 0h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "GMT" );
|
||||
VERIFY( info.second == empty );
|
||||
|
||||
info = tz->get_info(feb1 + months(4));
|
||||
VERIFY( info.result == local_info::unique );
|
||||
VERIFY( info.first.begin == sys_days(2022y/dst_start) + 1h );
|
||||
VERIFY( info.first.end == sys_days(2022y/dst_end) + 1h );
|
||||
VERIFY( info.first.offset == 1h );
|
||||
VERIFY( info.first.save == 1h );
|
||||
VERIFY( info.first.abbrev == "BST" );
|
||||
VERIFY( info.second == empty );
|
||||
}
|
||||
|
||||
void
|
||||
test_nonexistent()
|
||||
{
|
||||
auto tz = locate_zone("Europe/Helsinki");
|
||||
sys_time<hours> change = sys_days(2022y/dst_start) + 1h;
|
||||
local_seconds nonesuch(change.time_since_epoch() + 2h + 30min);
|
||||
local_info info;
|
||||
|
||||
info = tz->get_info(nonesuch);
|
||||
VERIFY( info.result == local_info::nonexistent );
|
||||
VERIFY( info.first.end == change );
|
||||
VERIFY( info.first.offset == 2h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "EET" );
|
||||
VERIFY( info.second.begin == info.first.end );
|
||||
VERIFY( info.second.offset == 3h );
|
||||
VERIFY( info.second.save == 1h );
|
||||
VERIFY( info.second.abbrev == "EEST" );
|
||||
|
||||
tz = locate_zone("America/New_York");
|
||||
nonesuch = local_days(Sunday[2]/March/2016) + 2h + 30min;
|
||||
info = tz->get_info(nonesuch);
|
||||
VERIFY( info.result == local_info::nonexistent );
|
||||
VERIFY( info.first.end == sys_days(Sunday[2]/March/2016) + 5h + 2h );
|
||||
VERIFY( info.first.offset == -5h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "EST" );
|
||||
VERIFY( info.second.begin == info.first.end );
|
||||
VERIFY( info.second.offset == -4h );
|
||||
VERIFY( info.second.save == 1h );
|
||||
VERIFY( info.second.abbrev == "EDT" );
|
||||
}
|
||||
|
||||
void
|
||||
test_ambiguous()
|
||||
{
|
||||
auto tz = locate_zone("Europe/Helsinki");
|
||||
sys_time<hours> change = sys_days(2022y/dst_end) + 1h;
|
||||
local_seconds twix(change.time_since_epoch() + 2h + 30min);
|
||||
local_info info;
|
||||
|
||||
info = tz->get_info(twix);
|
||||
VERIFY( info.result == local_info::ambiguous );
|
||||
VERIFY( info.first.end == change );
|
||||
VERIFY( info.first.offset == 3h );
|
||||
VERIFY( info.first.save == 1h );
|
||||
VERIFY( info.first.abbrev == "EEST" );
|
||||
VERIFY( info.second.begin == info.first.end );
|
||||
VERIFY( info.second.offset == 2h );
|
||||
VERIFY( info.second.save == 0h );
|
||||
VERIFY( info.second.abbrev == "EET" );
|
||||
|
||||
tz = locate_zone("America/New_York");
|
||||
twix = local_days(Sunday[2]/March/2016) + 2h + 30min;
|
||||
info = tz->get_info(twix);
|
||||
VERIFY( info.result == local_info::nonexistent );
|
||||
VERIFY( info.first.end == sys_days(Sunday[2]/March/2016) + 5h + 2h );
|
||||
VERIFY( info.first.offset == -5h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "EST" );
|
||||
VERIFY( info.second.begin == info.first.end );
|
||||
VERIFY( info.second.offset == -4h );
|
||||
VERIFY( info.second.save == 1h );
|
||||
VERIFY( info.second.abbrev == "EDT" );
|
||||
}
|
||||
|
||||
void
|
||||
test_egypt()
|
||||
{
|
||||
local_days d(2010y/May/1);
|
||||
auto tz = locate_zone("Egypt");
|
||||
local_info info = tz->get_info(d);
|
||||
VERIFY( info.result == local_info::unique );
|
||||
VERIFY( info.first.begin == sys_days(2010y/April/29) + 22h );
|
||||
VERIFY( info.first.offset == 3h );
|
||||
VERIFY( info.first.save == 1h );
|
||||
VERIFY( info.first.abbrev == "EEST" );
|
||||
|
||||
info = tz->get_info(d - 24h);
|
||||
VERIFY( info.result == local_info::nonexistent );
|
||||
VERIFY( info.first.begin == sys_days(2009y/August/20) + 21h );
|
||||
VERIFY( info.first.offset == 2h );
|
||||
VERIFY( info.first.save == 0h );
|
||||
VERIFY( info.first.abbrev == "EET" );
|
||||
VERIFY( info.second.begin == sys_days(2010y/April/29) + 22h );
|
||||
VERIFY( info.second.offset == 3h );
|
||||
VERIFY( info.second.save == 1h );
|
||||
VERIFY( info.second.abbrev == "EEST" );
|
||||
|
||||
#if 0
|
||||
std::ostringstream out;
|
||||
local_seconds lt(local_days(2001y/January/1));
|
||||
const local_days end(2021y/January/1);
|
||||
|
||||
while (lt < end)
|
||||
{
|
||||
local_info i = tz->get_info(lt);
|
||||
|
||||
out << '\n' << i;
|
||||
|
||||
auto next = i.first.end;
|
||||
if (i.result != local_info::unique)
|
||||
next = i.second.begin + 24h;
|
||||
lt = zoned_time(tz, next).get_local_time();
|
||||
}
|
||||
out << '\n';
|
||||
|
||||
std::string expected = R"(
|
||||
[[2000-09-28 21:00:00,2001-04-26 22:00:00,02:00:00,0min,EET]]
|
||||
[[2001-04-26 22:00:00,2001-09-27 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2001-04-26 22:00:00,2001-09-27 21:00:00,03:00:00,60min,EEST] and [2001-09-27 21:00:00,2002-04-25 22:00:00,02:00:00,0min,EET]]
|
||||
[[2001-09-27 21:00:00,2002-04-25 22:00:00,02:00:00,0min,EET]]
|
||||
[[2002-04-25 22:00:00,2002-09-26 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2002-04-25 22:00:00,2002-09-26 21:00:00,03:00:00,60min,EEST] and [2002-09-26 21:00:00,2003-04-24 22:00:00,02:00:00,0min,EET]]
|
||||
[[2002-09-26 21:00:00,2003-04-24 22:00:00,02:00:00,0min,EET]]
|
||||
[[2003-04-24 22:00:00,2003-09-25 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2003-04-24 22:00:00,2003-09-25 21:00:00,03:00:00,60min,EEST] and [2003-09-25 21:00:00,2004-04-29 22:00:00,02:00:00,0min,EET]]
|
||||
[[2003-09-25 21:00:00,2004-04-29 22:00:00,02:00:00,0min,EET]]
|
||||
[[2004-04-29 22:00:00,2004-09-30 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2004-04-29 22:00:00,2004-09-30 21:00:00,03:00:00,60min,EEST] and [2004-09-30 21:00:00,2005-04-28 22:00:00,02:00:00,0min,EET]]
|
||||
[[2004-09-30 21:00:00,2005-04-28 22:00:00,02:00:00,0min,EET]]
|
||||
[[2005-04-28 22:00:00,2005-09-29 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2005-04-28 22:00:00,2005-09-29 21:00:00,03:00:00,60min,EEST] and [2005-09-29 21:00:00,2006-04-27 22:00:00,02:00:00,0min,EET]]
|
||||
[[2005-09-29 21:00:00,2006-04-27 22:00:00,02:00:00,0min,EET]]
|
||||
[[2006-04-27 22:00:00,2006-09-21 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2006-04-27 22:00:00,2006-09-21 21:00:00,03:00:00,60min,EEST] and [2006-09-21 21:00:00,2007-04-26 22:00:00,02:00:00,0min,EET]]
|
||||
[[2006-09-21 21:00:00,2007-04-26 22:00:00,02:00:00,0min,EET]]
|
||||
[[2007-04-26 22:00:00,2007-09-06 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2007-04-26 22:00:00,2007-09-06 21:00:00,03:00:00,60min,EEST] and [2007-09-06 21:00:00,2008-04-24 22:00:00,02:00:00,0min,EET]]
|
||||
[[2007-09-06 21:00:00,2008-04-24 22:00:00,02:00:00,0min,EET]]
|
||||
[[2008-04-24 22:00:00,2008-08-28 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2008-04-24 22:00:00,2008-08-28 21:00:00,03:00:00,60min,EEST] and [2008-08-28 21:00:00,2009-04-23 22:00:00,02:00:00,0min,EET]]
|
||||
[[2008-08-28 21:00:00,2009-04-23 22:00:00,02:00:00,0min,EET]]
|
||||
[[2009-04-23 22:00:00,2009-08-20 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2009-04-23 22:00:00,2009-08-20 21:00:00,03:00:00,60min,EEST] and [2009-08-20 21:00:00,2010-04-29 22:00:00,02:00:00,0min,EET]]
|
||||
[[2009-08-20 21:00:00,2010-04-29 22:00:00,02:00:00,0min,EET]]
|
||||
[[2010-04-29 22:00:00,2010-08-10 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2010-04-29 22:00:00,2010-08-10 21:00:00,03:00:00,60min,EEST] and [2010-08-10 21:00:00,2010-09-09 22:00:00,02:00:00,0min,EET]]
|
||||
[[2010-08-10 21:00:00,2010-09-09 22:00:00,02:00:00,0min,EET]]
|
||||
[[2010-09-09 22:00:00,2010-09-30 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2010-09-09 22:00:00,2010-09-30 21:00:00,03:00:00,60min,EEST] and [2010-09-30 21:00:00,2014-05-15 22:00:00,02:00:00,0min,EET]]
|
||||
[[2010-09-30 21:00:00,2014-05-15 22:00:00,02:00:00,0min,EET]]
|
||||
[[2014-05-15 22:00:00,2014-06-26 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2014-05-15 22:00:00,2014-06-26 21:00:00,03:00:00,60min,EEST] and [2014-06-26 21:00:00,2014-07-31 22:00:00,02:00:00,0min,EET]]
|
||||
[[2014-06-26 21:00:00,2014-07-31 22:00:00,02:00:00,0min,EET]]
|
||||
[[2014-07-31 22:00:00,2014-09-25 21:00:00,03:00:00,60min,EEST]]
|
||||
[ambiguous local time between [2014-07-31 22:00:00,2014-09-25 21:00:00,03:00:00,60min,EEST] and [2014-09-25 21:00:00,32767-12-31 00:00:00,02:00:00,0min,EET]]
|
||||
[[2014-09-25 21:00:00,32767-12-31 00:00:00,02:00:00,0min,EET]]
|
||||
)";
|
||||
VERIFY( out.str() == expected );
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_utc();
|
||||
test_unique();
|
||||
test_nonexistent();
|
||||
test_ambiguous();
|
||||
test_egypt();
|
||||
}
|
219
libstdc++-v3/testsuite/std/time/time_zone/get_info_sys.cc
Normal file
219
libstdc++-v3/testsuite/std/time/time_zone/get_info_sys.cc
Normal file
|
@ -0,0 +1,219 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target tzdb }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_zurich()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
const time_zone* const tz = locate_zone("Europe/Zurich");
|
||||
|
||||
{
|
||||
sys_days d = 1853y/July/16;
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == (34min + 8s) );
|
||||
VERIFY( info.abbrev == "LMT" );
|
||||
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
info = tz->get_info(d + 1s);
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
info = tz->get_info(d + 0.001s);
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1894y/June/1;
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1941y/May/Monday[1];
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST daylight savings time starts at 1am local time (UTC+1).
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1941y/October/Monday[1];
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CET standard time starts at 2am local time (UTC+2).
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1942y/May/Monday[1];
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST daylight savings time starts at 1am local time (UTC+1).
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1942y/October/Monday[1];
|
||||
|
||||
auto info = tz->get_info(d - 1s);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CET standard time starts at 2am local time (UTC+2).
|
||||
info = tz->get_info(d);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1943y/May/Monday[1];
|
||||
|
||||
// No daylight savings from 1943 until 1981.
|
||||
auto info = tz->get_info(d);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
info = tz->get_info(d + days(60));
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
info = tz->get_info(d + years(10));
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
info = tz->get_info(sys_days(1979y/June/3));
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
// Switzerland uses EU rules from 1981
|
||||
sys_days d = 1981y/March/Sunday[last];
|
||||
|
||||
auto info = tz->get_info(d);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
info = tz->get_info(d + 59min + 59s);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST begins at 1am UTC
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1981y/September/Sunday[last];
|
||||
|
||||
auto info = tz->get_info(d + 59min + 59s);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CEST ends at 1am UTC
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1994y/September/Sunday[last];
|
||||
|
||||
auto info = tz->get_info(d + 59min + 59s);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CEST ends at 1am UTC
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
d = 1995y/September/Sunday[last];
|
||||
info = tz->get_info(d + 59min + 59s);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CEST ends at 1am UTC
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
d = 1996y/September/Sunday[last];
|
||||
// CEST ends in October since 1996
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
d = 1996y/October/Sunday[last];
|
||||
// CEST ends at 1am UTC
|
||||
info = tz->get_info(d + 1h);
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_iterate()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto tz = locate_zone("Europe/Zurich");
|
||||
sys_seconds start(sys_days(1850y/January/1));
|
||||
const sys_seconds finish(sys_days(1982y/January/1));
|
||||
long count = 0;
|
||||
do
|
||||
{
|
||||
VERIFY(++count < 100); // Fail if we get stuck in a loop.
|
||||
auto info = tz->get_info(start);
|
||||
start = info.end;
|
||||
} while (start < finish);
|
||||
|
||||
VERIFY(count == 10); // Would be 9 if identical adjacent sys_info get merged.
|
||||
}
|
||||
|
||||
void
|
||||
test_shanghai()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto tz = locate_zone("Asia/Shanghai");
|
||||
sys_info info = tz->get_info(sys_days(1949y/January/1));
|
||||
VERIFY( info.abbrev == "CST" );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_zurich();
|
||||
test_iterate();
|
||||
test_shanghai();
|
||||
}
|
25
libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
Normal file
25
libstdc++-v3/testsuite/std/time/time_zone/requirements.cc
Normal file
|
@ -0,0 +1,25 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using std::chrono::time_zone;
|
||||
|
||||
static_assert( std::is_move_constructible_v<time_zone> );
|
||||
static_assert( std::is_move_assignable_v<time_zone> );
|
||||
|
||||
static_assert( ! std::is_default_constructible_v<time_zone> );
|
||||
static_assert( ! std::is_copy_constructible_v<time_zone> );
|
||||
static_assert( ! std::is_copy_assignable_v<time_zone> );
|
||||
|
||||
extern const time_zone* tz;
|
||||
|
||||
static_assert( std::is_same_v<decltype(tz->name()), std::string_view> );
|
||||
static_assert( noexcept(tz->name()) );
|
||||
|
||||
static_assert( std::is_same_v<decltype(*tz == *tz), bool> );
|
||||
static_assert( noexcept(*tz == *tz) );
|
||||
|
||||
static_assert( std::is_same_v<decltype(*tz <=> *tz), std::strong_ordering> );
|
||||
static_assert( noexcept(*tz <=> *tz) );
|
56
libstdc++-v3/testsuite/std/time/tzdb/1.cc
Normal file
56
libstdc++-v3/testsuite/std/time/tzdb/1.cc
Normal file
|
@ -0,0 +1,56 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
// { dg-additional-options "-DHAVE_TZDB" { target tzdb } }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
void
|
||||
test_version()
|
||||
{
|
||||
const tzdb& db = get_tzdb();
|
||||
VERIFY( &db == &get_tzdb_list().front() );
|
||||
|
||||
#ifdef HAVE_TZDB
|
||||
VERIFY( db.version == remote_version() );
|
||||
const tzdb& reloaded = reload_tzdb();
|
||||
if (reloaded.version == db.version)
|
||||
VERIFY( &reloaded == &db );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
test_current()
|
||||
{
|
||||
#ifdef HAVE_TZDB
|
||||
const tzdb& db = get_tzdb();
|
||||
const time_zone* tz = db.current_zone();
|
||||
VERIFY( tz == std::chrono::current_zone() );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
test_locate()
|
||||
{
|
||||
const tzdb& db = get_tzdb();
|
||||
const time_zone* tz = db.locate_zone("GMT");
|
||||
VERIFY( tz != nullptr );
|
||||
VERIFY( tz->name() == "Etc/GMT" );
|
||||
VERIFY( tz == std::chrono::locate_zone("GMT") );
|
||||
VERIFY( tz == db.locate_zone("Etc/GMT") );
|
||||
VERIFY( tz == db.locate_zone("Etc/GMT+0") );
|
||||
|
||||
#ifdef HAVE_TZDB
|
||||
VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() );
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_version();
|
||||
test_current();
|
||||
test_locate();
|
||||
}
|
76
libstdc++-v3/testsuite/std/time/tzdb/leap_seconds.cc
Normal file
76
libstdc++-v3/testsuite/std/time/tzdb/leap_seconds.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } }
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
static bool override_used = true;
|
||||
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
const char* zoneinfo_dir_override() {
|
||||
override_used = true;
|
||||
return "./";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_load_leapseconds()
|
||||
{
|
||||
std::ofstream("leapseconds") << R"(
|
||||
# These are all the real leap seconds as of 2022:
|
||||
Leap 1972 Jun 30 23:59:60 + S
|
||||
Leap 1972 Dec 31 23:59:60 + S
|
||||
Leap 1973 Dec 31 23:59:60 + S
|
||||
Leap 1974 Dec 31 23:59:60 + S
|
||||
Leap 1975 Dec 31 23:59:60 + S
|
||||
Leap 1976 Dec 31 23:59:60 + S
|
||||
Leap 1977 Dec 31 23:59:60 + S
|
||||
Leap 1978 Dec 31 23:59:60 + S
|
||||
Leap 1979 Dec 31 23:59:60 + S
|
||||
Leap 1981 Jun 30 23:59:60 + S
|
||||
Leap 1982 Jun 30 23:59:60 + S
|
||||
Leap 1983 Jun 30 23:59:60 + S
|
||||
Leap 1985 Jun 30 23:59:60 + S
|
||||
Leap 1987 Dec 31 23:59:60 + S
|
||||
Leap 1989 Dec 31 23:59:60 + S
|
||||
Leap 1990 Dec 31 23:59:60 + S
|
||||
Leap 1992 Jun 30 23:59:60 + S
|
||||
Leap 1993 Jun 30 23:59:60 + S
|
||||
Leap 1994 Jun 30 23:59:60 + S
|
||||
Leap 1995 Dec 31 23:59:60 + S
|
||||
Leap 1997 Jun 30 23:59:60 + S
|
||||
Leap 1998 Dec 31 23:59:60 + S
|
||||
Leap 2005 Dec 31 23:59:60 + S
|
||||
Leap 2008 Dec 31 23:59:60 + S
|
||||
Leap 2012 Jun 30 23:59:60 + S
|
||||
Leap 2015 Jun 30 23:59:60 + S
|
||||
Leap 2016 Dec 31 23:59:60 + S
|
||||
# These are fake leap seconds for testing purposes:
|
||||
Leap 2093 Jun 30 23:59:59 - S
|
||||
Leap 2093 Dec 31 23:59:60 + S
|
||||
)";
|
||||
|
||||
const auto& db = std::chrono::get_tzdb();
|
||||
VERIFY( override_used ); // If this fails then XFAIL for the target.
|
||||
|
||||
using namespace std::chrono;
|
||||
// XXX update this value if the number of hardcoded leap seconds changes:
|
||||
VERIFY( db.leap_seconds.size() == 29 );
|
||||
|
||||
auto i = db.leap_seconds.end() - 2;
|
||||
|
||||
VERIFY( i[0].date() == sys_days(2093y/July/1) - 1s );
|
||||
VERIFY( i[0].value() == -1s );
|
||||
|
||||
VERIFY( i[1].date() == sys_days(2094y/January/1) );
|
||||
VERIFY( i[1].value() == 1s );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_load_leapseconds();
|
||||
}
|
123
libstdc++-v3/testsuite/std/time/tzdb_list/1.cc
Normal file
123
libstdc++-v3/testsuite/std/time/tzdb_list/1.cc
Normal file
|
@ -0,0 +1,123 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } }
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
static bool override_used = true;
|
||||
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
const char* zoneinfo_dir_override() {
|
||||
override_used = true;
|
||||
return "./";
|
||||
}
|
||||
}
|
||||
|
||||
std::string tzdata_zi = R"(
|
||||
# version test1
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S
|
||||
Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 -
|
||||
Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S
|
||||
Rule EU 1977 only - Sep lastSun 1:00u 0 -
|
||||
Rule EU 1978 only - Oct 1 1:00u 0 -
|
||||
Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
|
||||
Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
|
||||
Rule EU 1996 max - Oct lastSun 1:00u 0 -
|
||||
|
||||
# Zone NAME STDOFF RULES FORMAT [UNTIL]
|
||||
Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16
|
||||
0:29:45.50 - BMT 1894 Jun
|
||||
1:00 Swiss CE%sT 1981
|
||||
1:00 EU CE%sT
|
||||
|
||||
Link Europe/Zurich Europe/Vaduz
|
||||
|
||||
)";
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
void
|
||||
test_access()
|
||||
{
|
||||
tzdb_list& list = get_tzdb_list();
|
||||
tzdb_list::const_iterator first = list.begin();
|
||||
tzdb_list::const_iterator last = list.end();
|
||||
VERIFY( list.cbegin() == first );
|
||||
VERIFY( list.cend() == last );
|
||||
VERIFY( first != last );
|
||||
VERIFY( &*first == &get_tzdb() );
|
||||
VERIFY( &*first == &list.front() );
|
||||
VERIFY( std::next(first) == last );
|
||||
first++;
|
||||
VERIFY( first == last );
|
||||
}
|
||||
|
||||
void
|
||||
test_reload()
|
||||
{
|
||||
tzdb_list& list = get_tzdb_list();
|
||||
tzdb_list::const_iterator test1 = list.begin();
|
||||
reload_tzdb();
|
||||
VERIFY( list.begin() == test1 );
|
||||
VERIFY( std::distance(list.begin(), list.end()) == 1 );
|
||||
|
||||
std::string new_tzdata_zi = tzdata_zi;
|
||||
auto pos = new_tzdata_zi.find("test");
|
||||
new_tzdata_zi[pos + 4] = '2';
|
||||
std::ofstream("tzdata.zi") << new_tzdata_zi;
|
||||
VERIFY( remote_version() == "test2" );
|
||||
|
||||
// List doesn't reload until requested to.
|
||||
VERIFY( get_tzdb_list().begin() == test1 );
|
||||
VERIFY( &get_tzdb() == &*test1 );
|
||||
reload_tzdb();
|
||||
VERIFY( list.begin() != test1 );
|
||||
VERIFY( std::distance(list.begin(), list.end()) == 2 );
|
||||
VERIFY( test1 == std::next(list.begin()) );
|
||||
VERIFY( &get_tzdb() == &*list.begin() );
|
||||
VERIFY( list.begin()->version == "test2" );
|
||||
VERIFY( test1->version == "test1" );
|
||||
}
|
||||
|
||||
void
|
||||
test_erase()
|
||||
{
|
||||
tzdb_list& list = get_tzdb_list();
|
||||
const int count = std::distance(list.begin(), list.end());
|
||||
tzdb_list::const_iterator test2 = list.begin();
|
||||
|
||||
std::string new_tzdata_zi = tzdata_zi;
|
||||
auto pos = new_tzdata_zi.find("test");
|
||||
new_tzdata_zi[pos + 4] = '3';
|
||||
std::ofstream("tzdata.zi") << new_tzdata_zi;
|
||||
|
||||
reload_tzdb();
|
||||
VERIFY( std::distance(list.begin(), list.end()) == count + 1 );
|
||||
VERIFY( list.begin()->version == "test3" );
|
||||
list.erase_after(list.begin());
|
||||
VERIFY( std::distance(list.begin(), list.end()) == count );
|
||||
VERIFY( list.begin()->version == "test3" );
|
||||
VERIFY( std::next(list.begin())->version == "test1" );
|
||||
|
||||
// As a GCC extension, the erased node is not destroyed
|
||||
// while there are iterators referring to it.
|
||||
VERIFY( test2->version == "test2" );
|
||||
VERIFY( test2->leap_seconds == list.begin()->leap_seconds );
|
||||
// But the iterator points to an unlinked list node now:
|
||||
VERIFY( std::next(test2) == tzdb_list::const_iterator() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::ofstream("leapseconds") << '\n';
|
||||
std::ofstream("tzdata.zi") << tzdata_zi;
|
||||
|
||||
test_access();
|
||||
test_reload();
|
||||
test_erase();
|
||||
}
|
20
libstdc++-v3/testsuite/std/time/tzdb_list/requirements.cc
Normal file
20
libstdc++-v3/testsuite/std/time/tzdb_list/requirements.cc
Normal file
|
@ -0,0 +1,20 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using std::chrono::tzdb_list;
|
||||
|
||||
static_assert( ! std::is_default_constructible_v<tzdb_list> );
|
||||
static_assert( ! std::is_copy_constructible_v<tzdb_list> );
|
||||
static_assert( ! std::is_copy_assignable_v<tzdb_list> );
|
||||
static_assert( ! std::is_move_constructible_v<tzdb_list> );
|
||||
static_assert( ! std::is_move_assignable_v<tzdb_list> );
|
||||
static_assert( std::is_destructible_v<tzdb_list> );
|
||||
|
||||
using IterTraits = std::iterator_traits<tzdb_list::const_iterator>;
|
||||
|
||||
static_assert( std::is_same_v<IterTraits::iterator_category,
|
||||
std::forward_iterator_tag> );
|
||||
static_assert( std::is_same_v<IterTraits::value_type, std::chrono::tzdb> );
|
255
libstdc++-v3/testsuite/std/time/zoned_time/1.cc
Normal file
255
libstdc++-v3/testsuite/std/time/zoned_time/1.cc
Normal file
|
@ -0,0 +1,255 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target tzdb }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test_members()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
const time_zone* const zone = locate_zone("Europe/London");
|
||||
|
||||
sys_time<minutes> t = sys_days(2022y/February/1) + 1h + 23min;
|
||||
zoned_time<minutes> zt("Europe/London", t);
|
||||
VERIFY( zt.get_time_zone() == zone );
|
||||
VERIFY( zt.get_sys_time() == t);
|
||||
VERIFY( zt.get_local_time().time_since_epoch() == t.time_since_epoch() );
|
||||
VERIFY( zt.get_info().offset == 0h );
|
||||
VERIFY( zt.get_info().abbrev == "GMT" );
|
||||
VERIFY( static_cast<sys_seconds>(zt) == t );
|
||||
VERIFY( static_cast<local_seconds>(zt) == zt.get_local_time() );
|
||||
|
||||
t = sys_days(2022y/June/1);
|
||||
zt = t;
|
||||
VERIFY( zt.get_time_zone() == zone );
|
||||
VERIFY( zt.get_sys_time() == t);
|
||||
VERIFY( zt.get_local_time().time_since_epoch() == t.time_since_epoch() + 1h );
|
||||
VERIFY( zt.get_info().offset == 1h );
|
||||
VERIFY( zt.get_info().abbrev == "BST" );
|
||||
VERIFY( static_cast<sys_seconds>(zt) == t );
|
||||
VERIFY( static_cast<local_seconds>(zt) == zt.get_local_time() );
|
||||
|
||||
zoned_seconds zs(zt);
|
||||
VERIFY( zs == zt );
|
||||
|
||||
local_time<seconds> local(zt.get_local_time() + days(1) + hours(2));
|
||||
zt = time_point_cast<minutes>(local);
|
||||
VERIFY( zt.get_sys_time() == zs.get_sys_time() + days(1) + hours(2) );
|
||||
}
|
||||
|
||||
void
|
||||
test_zurich()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
const time_zone* const zurich = locate_zone("Europe/Zurich");
|
||||
|
||||
{
|
||||
sys_days d = 1853y/July/16;
|
||||
|
||||
auto z = zoned_seconds(zurich, sys_seconds(d) - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == (34min + 8s) );
|
||||
VERIFY( info.abbrev == "LMT" );
|
||||
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
z = zoned_seconds(zurich, d + 1s);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
auto z2 = zoned_time(zurich, d + 0.001s);
|
||||
info = z2.get_info();
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1894y/June/1;
|
||||
|
||||
auto z = zoned_seconds(zurich, sys_seconds(d) - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == (29min + 46s) );
|
||||
VERIFY( info.abbrev == "BMT" );
|
||||
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1941y/May/Monday[1];
|
||||
|
||||
auto z = zoned_seconds(zurich, d - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST daylight savings time starts at 1am local time (UTC+1).
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1941y/October/Monday[1];
|
||||
|
||||
auto z = zoned_seconds(zurich, d - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CET standard time starts at 2am local time (UTC+2).
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1942y/May/Monday[1];
|
||||
|
||||
auto z = zoned_seconds(zurich, d - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST daylight savings time starts at 1am local time (UTC+1).
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1942y/October/Monday[1];
|
||||
|
||||
auto z = zoned_seconds(zurich, d - 1s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CET standard time starts at 2am local time (UTC+2).
|
||||
z = zoned_seconds(zurich, d);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1943y/May/Monday[1];
|
||||
|
||||
// No daylight savings from 1943 until 1981.
|
||||
auto z = zoned_seconds(zurich, d);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
z = zoned_seconds(zurich, d + days(60));
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
z = zoned_seconds(zurich, d + years(10));
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
z = zoned_seconds(zurich, sys_days(1979y/June/3));
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
// Switzerland uses EU rules from 1981
|
||||
sys_days d = 1981y/March/Sunday[last];
|
||||
|
||||
auto z = zoned_seconds(zurich, d);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
z = zoned_seconds(zurich, d + 59min + 59s);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
// CEST begins at 1am UTC
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1981y/September/Sunday[last];
|
||||
|
||||
auto z = zoned_seconds(zurich, d + 59min + 59s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CEST ends at 1am UTC
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
|
||||
{
|
||||
sys_days d = 1994y/September/Sunday[last];
|
||||
|
||||
auto z = zoned_seconds(zurich, d + 59min + 59s);
|
||||
auto info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
// CEST ends at 1am UTC
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
d = 1995y/September/Sunday[last];
|
||||
z = zoned_seconds(zurich, d + 59min + 59s);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
// CEST ends at 1am UTC
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
|
||||
d = 1996y/September/Sunday[last];
|
||||
// CEST ends in October since 1996
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 2h );
|
||||
VERIFY( info.abbrev == "CEST" );
|
||||
|
||||
d = 1996y/October/Sunday[last];
|
||||
// CEST ends at 1am UTC
|
||||
z = zoned_seconds(zurich, d + 1h);
|
||||
info = z.get_info();
|
||||
VERIFY( info.offset == 1h );
|
||||
VERIFY( info.abbrev == "CET" );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_members();
|
||||
test_zurich();
|
||||
}
|
75
libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
Normal file
75
libstdc++-v3/testsuite/std/time/zoned_time/custom.cc
Normal file
|
@ -0,0 +1,75 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target tzdb }
|
||||
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
struct local_tz
|
||||
{
|
||||
local_tz() : name(std::chrono::current_zone()->name()) { }
|
||||
|
||||
explicit local_tz(std::string_view name) : name(name) { }
|
||||
|
||||
template<typename Dur>
|
||||
std::chrono::sys_time<Dur> to_sys(const std::chrono::local_time<Dur>& d)
|
||||
{ return std::chrono::locate_zone(name)->to_sys(d); }
|
||||
|
||||
template<typename Dur>
|
||||
std::chrono::sys_time<Dur> to_local(const std::chrono::sys_time<Dur>& d)
|
||||
{ return std::chrono::locate_zone(name)->to_sys(d); }
|
||||
|
||||
template<typename Dur>
|
||||
std::chrono::sys_info get_info(const std::chrono::sys_time<Dur>& d)
|
||||
{ return std::chrono::locate_zone(name)->get_info(d); }
|
||||
|
||||
struct indirect_cmp
|
||||
{
|
||||
bool operator()(const local_tz* lhs, const local_tz* rhs) const
|
||||
{ return lhs->name < rhs->name; }
|
||||
};
|
||||
|
||||
bool eq(const std::chrono::time_zone* tz) const noexcept
|
||||
{ return name == tz->name(); }
|
||||
|
||||
private:
|
||||
std::string_view name;
|
||||
};
|
||||
|
||||
template<> struct std::chrono::zoned_traits<const local_tz*>
|
||||
{
|
||||
static const local_tz* default_zone()
|
||||
{
|
||||
return locate_zone(std::chrono::current_zone()->name());
|
||||
}
|
||||
|
||||
static const local_tz* locate_zone(std::string_view name)
|
||||
{
|
||||
static std::set<const local_tz*, local_tz::indirect_cmp> zones;
|
||||
local_tz tz(name);
|
||||
if (auto z = zones.find(&tz); z != zones.end())
|
||||
return *z;
|
||||
if (std::chrono::locate_zone(name))
|
||||
return *zones.insert(new local_tz(tz)).first;
|
||||
throw std::runtime_error("zone not found");
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
test_custom_tzptr()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
zoned_time<seconds, const local_tz*> z;
|
||||
VERIFY( z.get_time_zone()->eq(std::chrono::current_zone()) );
|
||||
|
||||
zoned_time<seconds, const local_tz*> z2(std::string_view("Europe/London"));
|
||||
VERIFY( z2.get_time_zone()->eq(std::chrono::locate_zone("Europe/London")) );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_custom_tzptr();
|
||||
}
|
79
libstdc++-v3/testsuite/std/time/zoned_time/deduction.cc
Normal file
79
libstdc++-v3/testsuite/std/time/zoned_time/deduction.cc
Normal file
|
@ -0,0 +1,79 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
struct local_tz : time_zone { local_tz(); };
|
||||
|
||||
template<> struct std::chrono::zoned_traits<const local_tz*>
|
||||
{
|
||||
static auto default_zone() { return current_zone(); }
|
||||
|
||||
static auto locate_zone(std::string_view name)
|
||||
{ return std::chrono::locate_zone(name); }
|
||||
};
|
||||
|
||||
void
|
||||
test_ctad()
|
||||
{
|
||||
zoned_time z1;
|
||||
static_assert( std::is_same_v<decltype(z1), zoned_time<seconds>> );
|
||||
zoned_time z2 = z1;
|
||||
static_assert( std::is_same_v<decltype(z2), decltype(z1)> );
|
||||
|
||||
zoned_time z3 = sys_time<milliseconds>();
|
||||
static_assert( std::is_same_v<decltype(z3), zoned_time<milliseconds>> );
|
||||
|
||||
const local_tz ltz;
|
||||
zoned_time z4(<z);
|
||||
static_assert( std::is_same_v<decltype(z4),
|
||||
zoned_time<seconds, const local_tz*>> );
|
||||
|
||||
zoned_time z5("GMT");
|
||||
static_assert( std::is_same_v<decltype(z5), zoned_time<seconds>> );
|
||||
|
||||
zoned_time z6(<z, sys_time<minutes>());
|
||||
static_assert( std::is_same_v<decltype(z6),
|
||||
zoned_time<seconds, const local_tz*>> );
|
||||
|
||||
zoned_time z7(<z, sys_time<milliseconds>());
|
||||
static_assert( std::is_same_v<decltype(z7),
|
||||
zoned_time<milliseconds, const local_tz*>> );
|
||||
|
||||
zoned_time z8("GMT", sys_time<minutes>());
|
||||
static_assert( std::is_same_v<decltype(z8), zoned_time<seconds>> );
|
||||
|
||||
zoned_time z9("GMT", sys_time<microseconds>());
|
||||
static_assert( std::is_same_v<decltype(z9), zoned_time<microseconds>> );
|
||||
|
||||
zoned_time z10(<z, local_time<minutes>());
|
||||
static_assert( std::is_same_v<decltype(z10),
|
||||
zoned_time<seconds, const local_tz*>> );
|
||||
|
||||
zoned_time z11(<z, local_time<nanoseconds>(), choose::earliest);
|
||||
static_assert( std::is_same_v<decltype(z11),
|
||||
zoned_time<nanoseconds, const local_tz*>> );
|
||||
|
||||
zoned_time z12("GMT", local_time<minutes>());
|
||||
static_assert( std::is_same_v<decltype(z12), zoned_time<seconds>> );
|
||||
|
||||
zoned_time z13("GMT", local_time<nanoseconds>(), choose::earliest);
|
||||
static_assert( std::is_same_v<decltype(z13), zoned_time<nanoseconds>> );
|
||||
|
||||
zoned_time z14(<z, z13);
|
||||
static_assert( std::is_same_v<decltype(z14),
|
||||
zoned_time<nanoseconds, const local_tz*>> );
|
||||
|
||||
zoned_time z15(<z, z12, choose::earliest);
|
||||
static_assert( std::is_same_v<decltype(z15),
|
||||
zoned_time<seconds, const local_tz*>> );
|
||||
|
||||
zoned_time z16("GMT", z14);
|
||||
static_assert( std::is_same_v<decltype(z16), zoned_time<nanoseconds>> );
|
||||
|
||||
zoned_time z17("GMT", z12, choose::earliest);
|
||||
static_assert( std::is_same_v<decltype(z17), zoned_time<seconds>> );
|
||||
}
|
9
libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
Normal file
9
libstdc++-v3/testsuite/std/time/zoned_time/req_neg.cc
Normal file
|
@ -0,0 +1,9 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
|
||||
std::chrono::zoned_time<std::chrono::year> z; // { dg-error "here" }
|
||||
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
|
||||
// { dg-prune-output "common_type" }
|
27
libstdc++-v3/testsuite/std/time/zoned_time/requirements.cc
Normal file
27
libstdc++-v3/testsuite/std/time/zoned_time/requirements.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
static_assert( std::is_default_constructible_v<zoned_time<seconds>> );
|
||||
static_assert( std::is_copy_constructible_v<zoned_time<seconds>> );
|
||||
static_assert( std::is_copy_assignable_v<zoned_time<seconds>> );
|
||||
static_assert( std::is_move_constructible_v<zoned_time<seconds>> );
|
||||
static_assert( std::is_move_assignable_v<zoned_time<seconds>> );
|
||||
static_assert( std::is_destructible_v<zoned_time<seconds>> );
|
||||
|
||||
static_assert( std::is_same_v<zoned_time<seconds>::duration, seconds> );
|
||||
static_assert( std::is_same_v<zoned_time<nanoseconds>::duration, nanoseconds> );
|
||||
static_assert( std::is_same_v<zoned_time<minutes>::duration, seconds> );
|
||||
|
||||
extern zoned_time<minutes> z;
|
||||
static_assert( std::is_same_v<decltype(z == z), bool> );
|
||||
|
||||
// requires zoned_traits<time_zone*>::default_zone().
|
||||
static_assert( ! std::is_default_constructible_v<zoned_time<seconds, time_zone*>> );
|
||||
// requires zoned_traits<time_zone*>::locate_zone(string_view).
|
||||
static_assert( ! std::is_constructible_v<zoned_time<seconds, time_zone*>,
|
||||
std::string_view> );
|
39
libstdc++-v3/testsuite/std/time/zoned_traits.cc
Normal file
39
libstdc++-v3/testsuite/std/time/zoned_traits.cc
Normal file
|
@ -0,0 +1,39 @@
|
|||
// { dg-options "-std=gnu++20" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-require-effective-target cxx11_abi }
|
||||
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
static_assert( std::is_empty_v<zoned_traits<const time_zone*>> );
|
||||
static_assert(std::is_default_constructible_v<zoned_traits<const time_zone*>>);
|
||||
|
||||
// The primary template is a complete type, it just has no members.
|
||||
static_assert( std::is_empty_v<zoned_traits<time_zone*>> );
|
||||
static_assert(std::is_default_constructible_v<zoned_traits<time_zone*>>);
|
||||
static_assert( std::is_empty_v<zoned_traits<int>> );
|
||||
static_assert(std::is_default_constructible_v<zoned_traits<int>>);
|
||||
|
||||
void
|
||||
test_default_zone()
|
||||
{
|
||||
auto p = zoned_traits<const time_zone*>::default_zone();
|
||||
static_assert( std::is_same_v<decltype(p), const time_zone*> );
|
||||
VERIFY( p == locate_zone("UTC") );
|
||||
}
|
||||
|
||||
void
|
||||
test_locate_zone()
|
||||
{
|
||||
auto p = zoned_traits<const time_zone*>::locate_zone("GMT");
|
||||
static_assert( std::is_same_v<decltype(p), const time_zone*> );
|
||||
VERIFY( p == locate_zone("GMT") );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_default_zone();
|
||||
test_locate_zone();
|
||||
}
|
Loading…
Add table
Reference in a new issue