1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___CHRONO_OSTREAM_H 11 #define _LIBCPP___CHRONO_OSTREAM_H 12 13 #include <__config> 14 15 #if _LIBCPP_HAS_LOCALIZATION 16 17 # include <__chrono/calendar.h> 18 # include <__chrono/day.h> 19 # include <__chrono/duration.h> 20 # include <__chrono/file_clock.h> 21 # include <__chrono/hh_mm_ss.h> 22 # include <__chrono/local_info.h> 23 # include <__chrono/month.h> 24 # include <__chrono/month_weekday.h> 25 # include <__chrono/monthday.h> 26 # include <__chrono/statically_widen.h> 27 # include <__chrono/sys_info.h> 28 # include <__chrono/system_clock.h> 29 # include <__chrono/utc_clock.h> 30 # include <__chrono/weekday.h> 31 # include <__chrono/year.h> 32 # include <__chrono/year_month.h> 33 # include <__chrono/year_month_day.h> 34 # include <__chrono/year_month_weekday.h> 35 # include <__chrono/zoned_time.h> 36 # include <__concepts/same_as.h> 37 # include <__format/format_functions.h> 38 # include <__fwd/ostream.h> 39 # include <ratio> 40 # include <sstream> 41 42 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 43 # pragma GCC system_header 44 # endif 45 46 _LIBCPP_BEGIN_NAMESPACE_STD 47 48 # if _LIBCPP_STD_VER >= 20 49 50 namespace chrono { 51 52 template <class _CharT, class _Traits, class _Duration> 53 requires(!treat_as_floating_point_v<typename _Duration::rep> && _Duration{1} < days{1}) 54 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 55 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration>& __tp) { 56 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); 57 } 58 59 template <class _CharT, class _Traits> 60 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 61 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) { 62 return __os << year_month_day{__dp}; 63 } 64 65 # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 66 # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 67 68 template <class _CharT, class _Traits, class _Duration> 69 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 70 operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp) { 71 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); 72 } 73 74 # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 75 # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 76 77 template <class _CharT, class _Traits, class _Duration> 78 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 79 operator<<(basic_ostream<_CharT, _Traits>& __os, const file_time<_Duration> __tp) { 80 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); 81 } 82 83 template <class _CharT, class _Traits, class _Duration> 84 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 85 operator<<(basic_ostream<_CharT, _Traits>& __os, const local_time<_Duration> __tp) { 86 return __os << sys_time<_Duration>{__tp.time_since_epoch()}; 87 } 88 89 // Depending on the type the return is a const _CharT* or a basic_string<_CharT> 90 template <class _CharT, class _Period> 91 _LIBCPP_HIDE_FROM_ABI auto __units_suffix() { 92 // TODO FMT LWG issue the suffixes are always char and not STATICALLY-WIDEN'ed. 93 if constexpr (same_as<typename _Period::type, atto>) 94 return _LIBCPP_STATICALLY_WIDEN(_CharT, "as"); 95 else if constexpr (same_as<typename _Period::type, femto>) 96 return _LIBCPP_STATICALLY_WIDEN(_CharT, "fs"); 97 else if constexpr (same_as<typename _Period::type, pico>) 98 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ps"); 99 else if constexpr (same_as<typename _Period::type, nano>) 100 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ns"); 101 else if constexpr (same_as<typename _Period::type, micro>) 102 # if _LIBCPP_HAS_UNICODE 103 return _LIBCPP_STATICALLY_WIDEN(_CharT, "\u00b5s"); 104 # else 105 return _LIBCPP_STATICALLY_WIDEN(_CharT, "us"); 106 # endif 107 else if constexpr (same_as<typename _Period::type, milli>) 108 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ms"); 109 else if constexpr (same_as<typename _Period::type, centi>) 110 return _LIBCPP_STATICALLY_WIDEN(_CharT, "cs"); 111 else if constexpr (same_as<typename _Period::type, deci>) 112 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ds"); 113 else if constexpr (same_as<typename _Period::type, ratio<1>>) 114 return _LIBCPP_STATICALLY_WIDEN(_CharT, "s"); 115 else if constexpr (same_as<typename _Period::type, deca>) 116 return _LIBCPP_STATICALLY_WIDEN(_CharT, "das"); 117 else if constexpr (same_as<typename _Period::type, hecto>) 118 return _LIBCPP_STATICALLY_WIDEN(_CharT, "hs"); 119 else if constexpr (same_as<typename _Period::type, kilo>) 120 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ks"); 121 else if constexpr (same_as<typename _Period::type, mega>) 122 return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ms"); 123 else if constexpr (same_as<typename _Period::type, giga>) 124 return _LIBCPP_STATICALLY_WIDEN(_CharT, "Gs"); 125 else if constexpr (same_as<typename _Period::type, tera>) 126 return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ts"); 127 else if constexpr (same_as<typename _Period::type, peta>) 128 return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ps"); 129 else if constexpr (same_as<typename _Period::type, exa>) 130 return _LIBCPP_STATICALLY_WIDEN(_CharT, "Es"); 131 else if constexpr (same_as<typename _Period::type, ratio<60>>) 132 return _LIBCPP_STATICALLY_WIDEN(_CharT, "min"); 133 else if constexpr (same_as<typename _Period::type, ratio<3600>>) 134 return _LIBCPP_STATICALLY_WIDEN(_CharT, "h"); 135 else if constexpr (same_as<typename _Period::type, ratio<86400>>) 136 return _LIBCPP_STATICALLY_WIDEN(_CharT, "d"); 137 else if constexpr (_Period::den == 1) 138 return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}]s"), _Period::num); 139 else 140 return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}/{}]s"), _Period::num, _Period::den); 141 } 142 143 template <class _CharT, class _Traits, class _Rep, class _Period> 144 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 145 operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d) { 146 basic_ostringstream<_CharT, _Traits> __s; 147 __s.flags(__os.flags()); 148 __s.imbue(__os.getloc()); 149 __s.precision(__os.precision()); 150 __s << __d.count() << chrono::__units_suffix<_CharT, _Period>(); 151 return __os << __s.str(); 152 } 153 154 template <class _CharT, class _Traits> 155 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) { 156 return __os << (__d.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%d}"), __d) 157 // Note this error differs from the wording of the Standard. The 158 // Standard wording doesn't work well on AIX or Windows. There 159 // the formatted day seems to be either modulo 100 or completely 160 // omitted. Judging by the wording this is valid. 161 // TODO FMT Write a paper of file an LWG issue. 162 : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02} is not a valid day"), 163 static_cast<unsigned>(__d))); 164 } 165 166 template <class _CharT, class _Traits> 167 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 168 operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m) { 169 return __os << (__m.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%b}"), __m) 170 : std::format(__os.getloc(), 171 _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid month"), 172 static_cast<unsigned>(__m))); // TODO FMT Standard mandated locale isn't used. 173 } 174 175 template <class _CharT, class _Traits> 176 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 177 operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) { 178 return __os << (__y.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y}"), __y) 179 : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), __y)); 180 } 181 182 template <class _CharT, class _Traits> 183 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 184 operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) { 185 return __os << (__wd.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%a}"), __wd) 186 : std::format(__os.getloc(), // TODO FMT Standard mandated locale isn't used. 187 _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid weekday"), 188 static_cast<unsigned>(__wd.c_encoding()))); 189 } 190 191 template <class _CharT, class _Traits> 192 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 193 operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_indexed& __wdi) { 194 auto __i = __wdi.index(); 195 return __os << (__i >= 1 && __i <= 5 196 ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{}]"), __wdi.weekday(), __i) 197 : std::format(__os.getloc(), 198 _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{} is not a valid index]"), 199 __wdi.weekday(), 200 __i)); 201 } 202 203 template <class _CharT, class _Traits> 204 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 205 operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_last& __wdl) { 206 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[last]"), __wdl.weekday()); 207 } 208 209 template <class _CharT, class _Traits> 210 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 211 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md) { 212 // TODO FMT The Standard allows 30th of February to be printed. 213 // It would be nice to show an error message instead. 214 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{}"), __md.month(), __md.day()); 215 } 216 217 template <class _CharT, class _Traits> 218 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 219 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day_last& __mdl) { 220 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/last"), __mdl.month()); 221 } 222 223 template <class _CharT, class _Traits> 224 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 225 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday& __mwd) { 226 return __os << std::format( 227 __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}"), __mwd.month(), __mwd.weekday_indexed()); 228 } 229 230 template <class _CharT, class _Traits> 231 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 232 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday_last& __mwdl) { 233 return __os << std::format( 234 __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}"), __mwdl.month(), __mwdl.weekday_last()); 235 } 236 237 template <class _CharT, class _Traits> 238 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 239 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym) { 240 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}"), __ym.year(), __ym.month()); 241 } 242 243 template <class _CharT, class _Traits> 244 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 245 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day& __ymd) { 246 return __os << (__ymd.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F}"), __ymd) 247 : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F} is not a valid date"), __ymd)); 248 } 249 250 template <class _CharT, class _Traits> 251 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 252 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day_last& __ymdl) { 253 return __os << std::format( 254 __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}"), __ymdl.year(), __ymdl.month_day_last()); 255 } 256 257 template <class _CharT, class _Traits> 258 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 259 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday& __ymwd) { 260 return __os << std::format( 261 __os.getloc(), 262 _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}"), 263 __ymwd.year(), 264 __ymwd.month(), 265 __ymwd.weekday_indexed()); 266 } 267 268 template <class _CharT, class _Traits> 269 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 270 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday_last& __ymwdl) { 271 return __os << std::format( 272 __os.getloc(), 273 _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}"), 274 __ymwdl.year(), 275 __ymwdl.month(), 276 __ymwdl.weekday_last()); 277 } 278 279 template <class _CharT, class _Traits, class _Duration> 280 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 281 operator<<(basic_ostream<_CharT, _Traits>& __os, const hh_mm_ss<_Duration> __hms) { 282 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%T}"), __hms); 283 } 284 285 # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 286 287 template <class _CharT, class _Traits> 288 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 289 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) { 290 // __info.abbrev is always std::basic_string<char>. 291 // Since these strings typically are short the conversion should be cheap. 292 std::basic_string<_CharT> __abbrev{__info.abbrev.begin(), __info.abbrev.end()}; 293 return __os << std::format( 294 _LIBCPP_STATICALLY_WIDEN(_CharT, "[{:%F %T}, {:%F %T}) {:%T} {:%Q%q} \"{}\""), 295 __info.begin, 296 __info.end, 297 hh_mm_ss{__info.offset}, 298 __info.save, 299 __abbrev); 300 } 301 302 template <class _CharT, class _Traits> 303 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 304 operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __info) { 305 auto __result = [&]() -> basic_string<_CharT> { 306 switch (__info.result) { 307 case local_info::unique: 308 return _LIBCPP_STATICALLY_WIDEN(_CharT, "unique"); 309 case local_info::nonexistent: 310 return _LIBCPP_STATICALLY_WIDEN(_CharT, "non-existent"); 311 case local_info::ambiguous: 312 return _LIBCPP_STATICALLY_WIDEN(_CharT, "ambiguous"); 313 314 default: 315 return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "unspecified result ({})"), __info.result); 316 }; 317 }; 318 319 return __os << std::format( 320 _LIBCPP_STATICALLY_WIDEN(_CharT, "{}: {{{}, {}}}"), __result(), __info.first, __info.second); 321 } 322 323 # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 324 template <class _CharT, class _Traits, class _Duration, class _TimeZonePtr> 325 _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 326 operator<<(basic_ostream<_CharT, _Traits>& __os, const zoned_time<_Duration, _TimeZonePtr>& __tp) { 327 return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T %Z}"), __tp); 328 } 329 # endif 330 # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 331 332 } // namespace chrono 333 334 # endif // if _LIBCPP_STD_VER >= 20 335 336 _LIBCPP_END_NAMESPACE_STD 337 338 #endif // _LIBCPP_HAS_LOCALIZATION 339 340 #endif // _LIBCPP___CHRONO_OSTREAM_H 341