1*4bdff4beSrobert // -*- C++ -*-
2*4bdff4beSrobert //===----------------------------------------------------------------------===//
3*4bdff4beSrobert //
4*4bdff4beSrobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*4bdff4beSrobert // See https://llvm.org/LICENSE.txt for license information.
6*4bdff4beSrobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*4bdff4beSrobert //
8*4bdff4beSrobert //===----------------------------------------------------------------------===//
9*4bdff4beSrobert
10*4bdff4beSrobert #ifndef _LIBCPP___CHRONO_CONVERT_TO_TM_H
11*4bdff4beSrobert #define _LIBCPP___CHRONO_CONVERT_TO_TM_H
12*4bdff4beSrobert
13*4bdff4beSrobert #include <__chrono/day.h>
14*4bdff4beSrobert #include <__chrono/duration.h>
15*4bdff4beSrobert #include <__chrono/hh_mm_ss.h>
16*4bdff4beSrobert #include <__chrono/month.h>
17*4bdff4beSrobert #include <__chrono/month_weekday.h>
18*4bdff4beSrobert #include <__chrono/monthday.h>
19*4bdff4beSrobert #include <__chrono/statically_widen.h>
20*4bdff4beSrobert #include <__chrono/system_clock.h>
21*4bdff4beSrobert #include <__chrono/time_point.h>
22*4bdff4beSrobert #include <__chrono/weekday.h>
23*4bdff4beSrobert #include <__chrono/year.h>
24*4bdff4beSrobert #include <__chrono/year_month.h>
25*4bdff4beSrobert #include <__chrono/year_month_day.h>
26*4bdff4beSrobert #include <__chrono/year_month_weekday.h>
27*4bdff4beSrobert #include <__concepts/same_as.h>
28*4bdff4beSrobert #include <__config>
29*4bdff4beSrobert #include <__memory/addressof.h>
30*4bdff4beSrobert #include <cstdint>
31*4bdff4beSrobert #include <ctime>
32*4bdff4beSrobert
33*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34*4bdff4beSrobert # pragma GCC system_header
35*4bdff4beSrobert #endif
36*4bdff4beSrobert
37*4bdff4beSrobert _LIBCPP_BEGIN_NAMESPACE_STD
38*4bdff4beSrobert
39*4bdff4beSrobert #if _LIBCPP_STD_VER > 17
40*4bdff4beSrobert
41*4bdff4beSrobert // Conerts a chrono date and weekday to a given _Tm type.
42*4bdff4beSrobert //
43*4bdff4beSrobert // This is an implementation detail for the function
44*4bdff4beSrobert // template <class _Tm, class _ChronoT>
45*4bdff4beSrobert // _Tm __convert_to_tm(const _ChronoT& __value)
46*4bdff4beSrobert //
47*4bdff4beSrobert // This manually converts the two values to the proper type. It is possible to
48*4bdff4beSrobert // convert from sys_days to time_t and then to _Tm. But this leads to the Y2K
49*4bdff4beSrobert // bug when time_t is a 32-bit signed integer. Chrono considers years beyond
50*4bdff4beSrobert // the year 2038 valid, so instead do the transformation manually.
51*4bdff4beSrobert template <class _Tm, class _Date>
52*4bdff4beSrobert requires(same_as<_Date, chrono::year_month_day> || same_as<_Date, chrono::year_month_day_last>)
__convert_to_tm(const _Date & __date,chrono::weekday __weekday)53*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _Date& __date, chrono::weekday __weekday) {
54*4bdff4beSrobert _Tm __result = {};
55*4bdff4beSrobert # ifdef __GLIBC__
56*4bdff4beSrobert __result.tm_zone = "UTC";
57*4bdff4beSrobert # endif
58*4bdff4beSrobert __result.tm_year = static_cast<int>(__date.year()) - 1900;
59*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__date.month()) - 1;
60*4bdff4beSrobert __result.tm_mday = static_cast<unsigned>(__date.day());
61*4bdff4beSrobert __result.tm_wday = static_cast<unsigned>(__weekday.c_encoding());
62*4bdff4beSrobert __result.tm_yday =
63*4bdff4beSrobert (static_cast<chrono::sys_days>(__date) -
64*4bdff4beSrobert static_cast<chrono::sys_days>(chrono::year_month_day{__date.year(), chrono::January, chrono::day{1}}))
65*4bdff4beSrobert .count();
66*4bdff4beSrobert
67*4bdff4beSrobert return __result;
68*4bdff4beSrobert }
69*4bdff4beSrobert
70*4bdff4beSrobert // Convert a chrono (calendar) time point, or dururation to the given _Tm type,
71*4bdff4beSrobert // which must have the same properties as std::tm.
72*4bdff4beSrobert template <class _Tm, class _ChronoT>
__convert_to_tm(const _ChronoT & __value)73*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
74*4bdff4beSrobert _Tm __result = {};
75*4bdff4beSrobert # ifdef __GLIBC__
76*4bdff4beSrobert __result.tm_zone = "UTC";
77*4bdff4beSrobert # endif
78*4bdff4beSrobert
79*4bdff4beSrobert if constexpr (chrono::__is_duration<_ChronoT>::value) {
80*4bdff4beSrobert // [time.format]/6
81*4bdff4beSrobert // ... However, if a flag refers to a "time of day" (e.g. %H, %I, %p,
82*4bdff4beSrobert // etc.), then a specialization of duration is interpreted as the time of
83*4bdff4beSrobert // day elapsed since midnight.
84*4bdff4beSrobert uint64_t __sec = chrono::duration_cast<chrono::seconds>(__value).count();
85*4bdff4beSrobert __sec %= 24 * 3600;
86*4bdff4beSrobert __result.tm_hour = __sec / 3600;
87*4bdff4beSrobert __sec %= 3600;
88*4bdff4beSrobert __result.tm_min = __sec / 60;
89*4bdff4beSrobert __result.tm_sec = __sec % 60;
90*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::day>)
91*4bdff4beSrobert __result.tm_mday = static_cast<unsigned>(__value);
92*4bdff4beSrobert else if constexpr (same_as<_ChronoT, chrono::month>)
93*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__value) - 1;
94*4bdff4beSrobert else if constexpr (same_as<_ChronoT, chrono::year>)
95*4bdff4beSrobert __result.tm_year = static_cast<int>(__value) - 1900;
96*4bdff4beSrobert else if constexpr (same_as<_ChronoT, chrono::weekday>)
97*4bdff4beSrobert __result.tm_wday = __value.c_encoding();
98*4bdff4beSrobert else if constexpr (same_as<_ChronoT, chrono::weekday_indexed> || same_as<_ChronoT, chrono::weekday_last>)
99*4bdff4beSrobert __result.tm_wday = __value.weekday().c_encoding();
100*4bdff4beSrobert else if constexpr (same_as<_ChronoT, chrono::month_day>) {
101*4bdff4beSrobert __result.tm_mday = static_cast<unsigned>(__value.day());
102*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__value.month()) - 1;
103*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::month_day_last>) {
104*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__value.month()) - 1;
105*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::month_weekday> || same_as<_ChronoT, chrono::month_weekday_last>) {
106*4bdff4beSrobert __result.tm_wday = __value.weekday_indexed().weekday().c_encoding();
107*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__value.month()) - 1;
108*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::year_month>) {
109*4bdff4beSrobert __result.tm_year = static_cast<int>(__value.year()) - 1900;
110*4bdff4beSrobert __result.tm_mon = static_cast<unsigned>(__value.month()) - 1;
111*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::year_month_day> || same_as<_ChronoT, chrono::year_month_day_last>) {
112*4bdff4beSrobert return std::__convert_to_tm<_Tm>(
113*4bdff4beSrobert chrono::year_month_day{__value}, chrono::weekday{static_cast<chrono::sys_days>(__value)});
114*4bdff4beSrobert } else if constexpr (same_as<_ChronoT, chrono::year_month_weekday> ||
115*4bdff4beSrobert same_as<_ChronoT, chrono::year_month_weekday_last>) {
116*4bdff4beSrobert return std::__convert_to_tm<_Tm>(chrono::year_month_day{static_cast<chrono::sys_days>(__value)}, __value.weekday());
117*4bdff4beSrobert } else
118*4bdff4beSrobert static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization");
119*4bdff4beSrobert
120*4bdff4beSrobert return __result;
121*4bdff4beSrobert }
122*4bdff4beSrobert
123*4bdff4beSrobert #endif //if _LIBCPP_STD_VER > 17
124*4bdff4beSrobert
125*4bdff4beSrobert _LIBCPP_END_NAMESPACE_STD
126*4bdff4beSrobert
127*4bdff4beSrobert #endif // _LIBCPP___CHRONO_CONVERT_TO_TM_H
128