1e5d2d3eaSMark de Wever // -*- C++ -*- 2e5d2d3eaSMark de Wever //===----------------------------------------------------------------------===// 3e5d2d3eaSMark de Wever // 4e5d2d3eaSMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5e5d2d3eaSMark de Wever // See https://llvm.org/LICENSE.txt for license information. 6e5d2d3eaSMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7e5d2d3eaSMark de Wever // 8e5d2d3eaSMark de Wever //===----------------------------------------------------------------------===// 9e5d2d3eaSMark de Wever 10e5d2d3eaSMark de Wever #ifndef _LIBCPP___CHRONO_CONVERT_TO_TM_H 11e5d2d3eaSMark de Wever #define _LIBCPP___CHRONO_CONVERT_TO_TM_H 12e5d2d3eaSMark de Wever 13bc2cf420SMark de Wever #include <__chrono/calendar.h> 147f5d130aSMark de Wever #include <__chrono/concepts.h> 15e5d2d3eaSMark de Wever #include <__chrono/day.h> 16719c3dc6SMark de Wever #include <__chrono/duration.h> 1796f30332SMark de Wever #include <__chrono/file_clock.h> 18105fef5dSMark de Wever #include <__chrono/hh_mm_ss.h> 198a21d59fSMark de Wever #include <__chrono/local_info.h> 201522f190SMark de Wever #include <__chrono/month.h> 21105fef5dSMark de Wever #include <__chrono/month_weekday.h> 22105fef5dSMark de Wever #include <__chrono/monthday.h> 23105fef5dSMark de Wever #include <__chrono/statically_widen.h> 246f7976c8SMark de Wever #include <__chrono/sys_info.h> 25105fef5dSMark de Wever #include <__chrono/system_clock.h> 26105fef5dSMark de Wever #include <__chrono/time_point.h> 270cd794d4SMark de Wever #include <__chrono/utc_clock.h> 28566868cdSMark de Wever #include <__chrono/weekday.h> 293eb4f16bSMark de Wever #include <__chrono/year.h> 30105fef5dSMark de Wever #include <__chrono/year_month.h> 31105fef5dSMark de Wever #include <__chrono/year_month_day.h> 32105fef5dSMark de Wever #include <__chrono/year_month_weekday.h> 33afbfb16dSMark de Wever #include <__chrono/zoned_time.h> 34e5d2d3eaSMark de Wever #include <__concepts/same_as.h> 35e5d2d3eaSMark de Wever #include <__config> 367f5d130aSMark de Wever #include <__format/format_error.h> 37105fef5dSMark de Wever #include <__memory/addressof.h> 38a4814bdcSMark de Wever #include <__type_traits/is_convertible.h> 39afbfb16dSMark de Wever #include <__type_traits/is_specialization.h> 40719c3dc6SMark de Wever #include <cstdint> 41105fef5dSMark de Wever #include <ctime> 427f5d130aSMark de Wever #include <limits> 43e5d2d3eaSMark de Wever 44e5d2d3eaSMark de Wever #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 45e5d2d3eaSMark de Wever # pragma GCC system_header 46e5d2d3eaSMark de Wever #endif 47e5d2d3eaSMark de Wever 487f5d130aSMark de Wever _LIBCPP_PUSH_MACROS 497f5d130aSMark de Wever #include <__undef_macros> 507f5d130aSMark de Wever 51e5d2d3eaSMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD 52e5d2d3eaSMark de Wever 534f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 20 54e5d2d3eaSMark de Wever 55105fef5dSMark de Wever // Conerts a chrono date and weekday to a given _Tm type. 56105fef5dSMark de Wever // 57105fef5dSMark de Wever // This is an implementation detail for the function 58105fef5dSMark de Wever // template <class _Tm, class _ChronoT> 59105fef5dSMark de Wever // _Tm __convert_to_tm(const _ChronoT& __value) 60105fef5dSMark de Wever // 61105fef5dSMark de Wever // This manually converts the two values to the proper type. It is possible to 62105fef5dSMark de Wever // convert from sys_days to time_t and then to _Tm. But this leads to the Y2K 63105fef5dSMark de Wever // bug when time_t is a 32-bit signed integer. Chrono considers years beyond 64105fef5dSMark de Wever // the year 2038 valid, so instead do the transformation manually. 65105fef5dSMark de Wever template <class _Tm, class _Date> 66105fef5dSMark de Wever requires(same_as<_Date, chrono::year_month_day> || same_as<_Date, chrono::year_month_day_last>) 67105fef5dSMark de Wever _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _Date& __date, chrono::weekday __weekday) { 68105fef5dSMark de Wever _Tm __result = {}; 69105fef5dSMark de Wever # ifdef __GLIBC__ 70105fef5dSMark de Wever __result.tm_zone = "UTC"; 71105fef5dSMark de Wever # endif 72105fef5dSMark de Wever __result.tm_year = static_cast<int>(__date.year()) - 1900; 73105fef5dSMark de Wever __result.tm_mon = static_cast<unsigned>(__date.month()) - 1; 74105fef5dSMark de Wever __result.tm_mday = static_cast<unsigned>(__date.day()); 75105fef5dSMark de Wever __result.tm_wday = static_cast<unsigned>(__weekday.c_encoding()); 76105fef5dSMark de Wever __result.tm_yday = 77105fef5dSMark de Wever (static_cast<chrono::sys_days>(__date) - 78105fef5dSMark de Wever static_cast<chrono::sys_days>(chrono::year_month_day{__date.year(), chrono::January, chrono::day{1}})) 79105fef5dSMark de Wever .count(); 80105fef5dSMark de Wever 81105fef5dSMark de Wever return __result; 82105fef5dSMark de Wever } 83105fef5dSMark de Wever 8496f30332SMark de Wever template <class _Tm, class _Duration> 8596f30332SMark de Wever _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const chrono::sys_time<_Duration> __tp) { 86b9f3d241SMark de Wever chrono::sys_days __days = chrono::floor<chrono::days>(__tp); 8796f30332SMark de Wever chrono::year_month_day __ymd{__days}; 8896f30332SMark de Wever 8996f30332SMark de Wever _Tm __result = std::__convert_to_tm<_Tm>(chrono::year_month_day{__ymd}, chrono::weekday{__days}); 9096f30332SMark de Wever 9196f30332SMark de Wever uint64_t __sec = 9296f30332SMark de Wever chrono::duration_cast<chrono::seconds>(__tp - chrono::time_point_cast<chrono::seconds>(__days)).count(); 9396f30332SMark de Wever __sec %= 24 * 3600; 9496f30332SMark de Wever __result.tm_hour = __sec / 3600; 9596f30332SMark de Wever __sec %= 3600; 9696f30332SMark de Wever __result.tm_min = __sec / 60; 9796f30332SMark de Wever __result.tm_sec = __sec % 60; 9896f30332SMark de Wever 9996f30332SMark de Wever return __result; 10096f30332SMark de Wever } 10196f30332SMark de Wever 1020cd794d4SMark de Wever # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 103*3b30f20cSMark de Wever # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 1040cd794d4SMark de Wever 1050cd794d4SMark de Wever template <class _Tm, class _Duration> 1060cd794d4SMark de Wever _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) { 1070cd794d4SMark de Wever _Tm __result = std::__convert_to_tm<_Tm>(chrono::utc_clock::to_sys(__tp)); 1080cd794d4SMark de Wever 1090cd794d4SMark de Wever if (chrono::get_leap_second_info(__tp).is_leap_second) 1100cd794d4SMark de Wever ++__result.tm_sec; 1110cd794d4SMark de Wever 1120cd794d4SMark de Wever return __result; 1130cd794d4SMark de Wever } 1140cd794d4SMark de Wever 115*3b30f20cSMark de Wever # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 1160cd794d4SMark de Wever # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 1170cd794d4SMark de Wever 118719c3dc6SMark de Wever // Convert a chrono (calendar) time point, or dururation to the given _Tm type, 119d529e811SLouis Dionne // which must have the same properties as std::tm. 120719c3dc6SMark de Wever template <class _Tm, class _ChronoT> 121719c3dc6SMark de Wever _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { 122d529e811SLouis Dionne _Tm __result = {}; 123e5d2d3eaSMark de Wever # ifdef __GLIBC__ 124e5d2d3eaSMark de Wever __result.tm_zone = "UTC"; 125e5d2d3eaSMark de Wever # endif 126e5d2d3eaSMark de Wever 1272c1d7959SMark de Wever if constexpr (__is_time_point<_ChronoT>) { 12896f30332SMark de Wever if constexpr (same_as<typename _ChronoT::clock, chrono::system_clock>) 12996f30332SMark de Wever return std::__convert_to_tm<_Tm>(__value); 1300cd794d4SMark de Wever # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 131*3b30f20cSMark de Wever # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 1320cd794d4SMark de Wever else if constexpr (same_as<typename _ChronoT::clock, chrono::utc_clock>) 1330cd794d4SMark de Wever return std::__convert_to_tm<_Tm>(__value); 134*3b30f20cSMark de Wever # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 1350cd794d4SMark de Wever # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 13696f30332SMark de Wever else if constexpr (same_as<typename _ChronoT::clock, chrono::file_clock>) 13796f30332SMark de Wever return std::__convert_to_tm<_Tm>(_ChronoT::clock::to_sys(__value)); 138bc2cf420SMark de Wever else if constexpr (same_as<typename _ChronoT::clock, chrono::local_t>) 139bc2cf420SMark de Wever return std::__convert_to_tm<_Tm>(chrono::sys_time<typename _ChronoT::duration>{__value.time_since_epoch()}); 14096f30332SMark de Wever else 1412c1d7959SMark de Wever static_assert(sizeof(_ChronoT) == 0, "TODO: Add the missing clock specialization"); 1427c010bfdSNikolas Klauser } else if constexpr (chrono::__is_duration_v<_ChronoT>) { 143719c3dc6SMark de Wever // [time.format]/6 144719c3dc6SMark de Wever // ... However, if a flag refers to a "time of day" (e.g. %H, %I, %p, 145719c3dc6SMark de Wever // etc.), then a specialization of duration is interpreted as the time of 146719c3dc6SMark de Wever // day elapsed since midnight. 147a4814bdcSMark de Wever 148a4814bdcSMark de Wever // Not all values can be converted to hours, it may run into ratio 149a4814bdcSMark de Wever // conversion errors. In that case the conversion to seconds works. 150a4814bdcSMark de Wever if constexpr (is_convertible_v<_ChronoT, chrono::hours>) { 151a4814bdcSMark de Wever auto __hour = chrono::floor<chrono::hours>(__value); 152a4814bdcSMark de Wever auto __sec = chrono::duration_cast<chrono::seconds>(__value - __hour); 153a4814bdcSMark de Wever __result.tm_hour = __hour.count() % 24; 154a4814bdcSMark de Wever __result.tm_min = __sec.count() / 60; 155a4814bdcSMark de Wever __result.tm_sec = __sec.count() % 60; 156a4814bdcSMark de Wever } else { 157719c3dc6SMark de Wever uint64_t __sec = chrono::duration_cast<chrono::seconds>(__value).count(); 158719c3dc6SMark de Wever __sec %= 24 * 3600; 159719c3dc6SMark de Wever __result.tm_hour = __sec / 3600; 160719c3dc6SMark de Wever __sec %= 3600; 161719c3dc6SMark de Wever __result.tm_min = __sec / 60; 162719c3dc6SMark de Wever __result.tm_sec = __sec % 60; 163a4814bdcSMark de Wever } 164719c3dc6SMark de Wever } else if constexpr (same_as<_ChronoT, chrono::day>) 165e5d2d3eaSMark de Wever __result.tm_mday = static_cast<unsigned>(__value); 166719c3dc6SMark de Wever else if constexpr (same_as<_ChronoT, chrono::month>) 1671522f190SMark de Wever __result.tm_mon = static_cast<unsigned>(__value) - 1; 168719c3dc6SMark de Wever else if constexpr (same_as<_ChronoT, chrono::year>) 1693eb4f16bSMark de Wever __result.tm_year = static_cast<int>(__value) - 1900; 1709f8340efSMark de Wever else if constexpr (same_as<_ChronoT, chrono::weekday>) 171566868cdSMark de Wever __result.tm_wday = __value.c_encoding(); 172105fef5dSMark de Wever else if constexpr (same_as<_ChronoT, chrono::weekday_indexed> || same_as<_ChronoT, chrono::weekday_last>) 173105fef5dSMark de Wever __result.tm_wday = __value.weekday().c_encoding(); 174105fef5dSMark de Wever else if constexpr (same_as<_ChronoT, chrono::month_day>) { 175105fef5dSMark de Wever __result.tm_mday = static_cast<unsigned>(__value.day()); 176105fef5dSMark de Wever __result.tm_mon = static_cast<unsigned>(__value.month()) - 1; 177105fef5dSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::month_day_last>) { 178105fef5dSMark de Wever __result.tm_mon = static_cast<unsigned>(__value.month()) - 1; 179105fef5dSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::month_weekday> || same_as<_ChronoT, chrono::month_weekday_last>) { 180105fef5dSMark de Wever __result.tm_wday = __value.weekday_indexed().weekday().c_encoding(); 181105fef5dSMark de Wever __result.tm_mon = static_cast<unsigned>(__value.month()) - 1; 182105fef5dSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::year_month>) { 183105fef5dSMark de Wever __result.tm_year = static_cast<int>(__value.year()) - 1900; 184105fef5dSMark de Wever __result.tm_mon = static_cast<unsigned>(__value.month()) - 1; 185105fef5dSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::year_month_day> || same_as<_ChronoT, chrono::year_month_day_last>) { 186243b1e97SMark de Wever return std::__convert_to_tm<_Tm>( 187105fef5dSMark de Wever chrono::year_month_day{__value}, chrono::weekday{static_cast<chrono::sys_days>(__value)}); 188105fef5dSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::year_month_weekday> || 189105fef5dSMark de Wever same_as<_ChronoT, chrono::year_month_weekday_last>) { 190243b1e97SMark de Wever return std::__convert_to_tm<_Tm>(chrono::year_month_day{static_cast<chrono::sys_days>(__value)}, __value.weekday()); 1917f5d130aSMark de Wever } else if constexpr (__is_hh_mm_ss<_ChronoT>) { 1927f5d130aSMark de Wever __result.tm_sec = __value.seconds().count(); 1937f5d130aSMark de Wever __result.tm_min = __value.minutes().count(); 1947f5d130aSMark de Wever // In libc++ hours is stored as a long. The type in std::tm is an int. So 1957f5d130aSMark de Wever // the overflow can only occur when hour uses more bits than an int 1967f5d130aSMark de Wever // provides. 1977f5d130aSMark de Wever if constexpr (sizeof(std::chrono::hours::rep) > sizeof(__result.tm_hour)) 1987f5d130aSMark de Wever if (__value.hours().count() > std::numeric_limits<decltype(__result.tm_hour)>::max()) 1997f5d130aSMark de Wever std::__throw_format_error("Formatting hh_mm_ss, encountered an hour overflow"); 2007f5d130aSMark de Wever __result.tm_hour = __value.hours().count(); 20124e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 2026f7976c8SMark de Wever } else if constexpr (same_as<_ChronoT, chrono::sys_info>) { 2036f7976c8SMark de Wever // Has no time information. 2048a21d59fSMark de Wever } else if constexpr (same_as<_ChronoT, chrono::local_info>) { 2058a21d59fSMark de Wever // Has no time information. 206c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 207afbfb16dSMark de Wever } else if constexpr (__is_specialization_v<_ChronoT, chrono::zoned_time>) { 208afbfb16dSMark de Wever return std::__convert_to_tm<_Tm>( 209afbfb16dSMark de Wever chrono::sys_time<typename _ChronoT::duration>{__value.get_local_time().time_since_epoch()}); 2106f7976c8SMark de Wever # endif 21124e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 212105fef5dSMark de Wever } else 213719c3dc6SMark de Wever static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization"); 214e5d2d3eaSMark de Wever 215e5d2d3eaSMark de Wever return __result; 216e5d2d3eaSMark de Wever } 217e5d2d3eaSMark de Wever 2184f15267dSNikolas Klauser #endif // if _LIBCPP_STD_VER >= 20 219e5d2d3eaSMark de Wever 220e5d2d3eaSMark de Wever _LIBCPP_END_NAMESPACE_STD 221e5d2d3eaSMark de Wever 2227f5d130aSMark de Wever _LIBCPP_POP_MACROS 2237f5d130aSMark de Wever 224e5d2d3eaSMark de Wever #endif // _LIBCPP___CHRONO_CONVERT_TO_TM_H 225