base.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. #pragma once
  2. #include "systime.h"
  3. #include <util/str_stl.h>
  4. #include <util/system/platform.h>
  5. #include <util/system/datetime.h>
  6. #include <util/generic/string.h>
  7. #include <util/generic/strbuf.h>
  8. #include <util/generic/ylimits.h>
  9. #include <util/generic/utility.h>
  10. #include <util/generic/typetraits.h>
  11. #include <util/generic/yexception.h>
  12. #include <chrono>
  13. #if defined(__cpp_lib_three_way_comparison)
  14. #include <compare>
  15. #endif
  16. #include <ctime>
  17. #include <cstdio>
  18. #include <ratio>
  19. #include <time.h>
  20. #ifdef _MSC_VER
  21. #pragma warning(push)
  22. #pragma warning(disable : 4244) // conversion from 'time_t' to 'long', possible loss of data
  23. #endif // _MSC_VER
  24. // Microseconds since epoch
  25. class TInstant;
  26. // Duration is microseconds. Could be used to store timeouts, for example.
  27. class TDuration;
  28. /// Current time
  29. static inline TInstant Now() noexcept;
  30. /// Use Now() method to obtain current time instead of *Seconds() unless you understand what are you doing.
  31. class TDateTimeParseException: public yexception {
  32. };
  33. const int DATE_BUF_LEN = 4 + 2 + 2 + 1; // [YYYYMMDD*]
  34. constexpr long seconds(const struct tm& theTm) {
  35. return 60 * (60 * theTm.tm_hour + theTm.tm_min) + theTm.tm_sec;
  36. }
  37. void sprint_gm_date(char* buf, time_t when, long* sec = nullptr);
  38. bool sscan_date(const char* date, struct tm& theTm);
  39. const int DATE_8601_LEN = 21; // strlen("YYYY-MM-DDThh:mm:ssZ") = 20 + '\0'
  40. size_t FormatDate8601(char* buf, size_t len, time_t when);
  41. inline void sprint_date8601(char* buf, time_t when) {
  42. buf[FormatDate8601(buf, 64, when)] = 0;
  43. }
  44. bool ParseISO8601DateTimeDeprecated(const char* date, time_t& utcTime);
  45. bool ParseISO8601DateTimeDeprecated(const char* date, size_t dateLen, time_t& utcTime);
  46. bool ParseRFC822DateTimeDeprecated(const char* date, time_t& utcTime);
  47. bool ParseRFC822DateTimeDeprecated(const char* date, size_t dateLen, time_t& utcTime);
  48. bool ParseHTTPDateTimeDeprecated(const char* date, time_t& utcTime);
  49. bool ParseHTTPDateTimeDeprecated(const char* date, size_t dateLen, time_t& utcTime);
  50. bool ParseX509ValidityDateTimeDeprecated(const char* date, time_t& utcTime);
  51. bool ParseX509ValidityDateTimeDeprecated(const char* date, size_t dateLen, time_t& utcTime);
  52. bool ParseISO8601DateTime(const char* date, time_t& utcTime);
  53. bool ParseISO8601DateTime(const char* date, size_t dateLen, time_t& utcTime);
  54. bool ParseRFC822DateTime(const char* date, time_t& utcTime);
  55. bool ParseRFC822DateTime(const char* date, size_t dateLen, time_t& utcTime);
  56. bool ParseHTTPDateTime(const char* date, time_t& utcTime);
  57. bool ParseHTTPDateTime(const char* date, size_t dateLen, time_t& utcTime);
  58. bool ParseX509ValidityDateTime(const char* date, time_t& utcTime);
  59. bool ParseX509ValidityDateTime(const char* date, size_t dateLen, time_t& utcTime);
  60. constexpr long TVdiff(timeval r1, timeval r2) {
  61. return (1000000 * (r2.tv_sec - r1.tv_sec) + (r2.tv_usec - r1.tv_usec));
  62. }
  63. TString Strftime(const char* format, const struct tm* tm);
  64. // Use functions below instead of sprint_date (check IGNIETFERRO-892 for details)
  65. void DateToString(char* buf, const struct tm& theTm);
  66. void DateToString(char* buf, time_t when, long* sec = nullptr);
  67. TString DateToString(const struct tm& theTm);
  68. TString DateToString(time_t when, long* sec = nullptr);
  69. // Year in format "YYYY", throws an exception if year not in range [0, 9999]
  70. TString YearToString(const struct tm& theTm);
  71. TString YearToString(time_t when);
  72. template <class S>
  73. class TTimeBase {
  74. public:
  75. using TValue = ui64;
  76. protected:
  77. constexpr TTimeBase(const TValue& value) noexcept
  78. : Value_(value)
  79. {
  80. }
  81. public:
  82. constexpr TTimeBase() noexcept
  83. : Value_(0)
  84. {
  85. }
  86. constexpr TTimeBase(const struct timeval& tv) noexcept
  87. : Value_(tv.tv_sec * (ui64)1000000 + tv.tv_usec)
  88. {
  89. }
  90. constexpr TValue GetValue() const noexcept {
  91. return Value_;
  92. }
  93. constexpr double SecondsFloat() const noexcept {
  94. return Value_ * (1 / 1000000.0);
  95. }
  96. constexpr double MillisecondsFloat() const noexcept {
  97. return Value_ * (1 / 1000.0);
  98. }
  99. constexpr TValue MicroSeconds() const noexcept {
  100. return Value_;
  101. }
  102. constexpr TValue MilliSeconds() const noexcept {
  103. return MicroSeconds() / 1000;
  104. }
  105. constexpr TValue Seconds() const noexcept {
  106. return MilliSeconds() / 1000;
  107. }
  108. constexpr TValue Minutes() const noexcept {
  109. return Seconds() / 60;
  110. }
  111. constexpr TValue Hours() const noexcept {
  112. return Minutes() / 60;
  113. }
  114. constexpr TValue Days() const noexcept {
  115. return Hours() / 24;
  116. }
  117. constexpr TValue NanoSeconds() const noexcept {
  118. return MicroSeconds() >= (Max<TValue>() / (TValue)1000) ? Max<TValue>() : MicroSeconds() * (TValue)1000;
  119. }
  120. constexpr ui32 MicroSecondsOfSecond() const noexcept {
  121. return MicroSeconds() % (TValue)1000000;
  122. }
  123. constexpr ui32 MilliSecondsOfSecond() const noexcept {
  124. return MicroSecondsOfSecond() / (TValue)1000;
  125. }
  126. constexpr ui32 NanoSecondsOfSecond() const noexcept {
  127. return MicroSecondsOfSecond() * (TValue)1000;
  128. }
  129. constexpr explicit operator bool() const noexcept {
  130. return Value_;
  131. }
  132. protected:
  133. TValue Value_; // microseconds count
  134. };
  135. namespace NDateTimeHelpers {
  136. template <typename T>
  137. struct TPrecisionHelper {
  138. using THighPrecision = ui64;
  139. };
  140. template <>
  141. struct TPrecisionHelper<float> {
  142. using THighPrecision = double;
  143. };
  144. template <>
  145. struct TPrecisionHelper<double> {
  146. using THighPrecision = double;
  147. };
  148. }
  149. class TDuration: public TTimeBase<TDuration> {
  150. using TBase = TTimeBase<TDuration>;
  151. private:
  152. /**
  153. * private construct from microseconds
  154. */
  155. constexpr explicit TDuration(TValue value) noexcept
  156. : TBase(value)
  157. {
  158. }
  159. public:
  160. constexpr TDuration() noexcept {
  161. }
  162. constexpr TDuration(const struct timeval& tv) noexcept
  163. : TBase(tv)
  164. {
  165. }
  166. /**
  167. * TDuration is compatible with std::chrono::duration:
  168. * it can be constructed and compared with std::chrono::duration.
  169. * But there are two significant and dangerous differences between them:
  170. * 1) TDuration is never negative and use saturation between 0 and maximum value.
  171. * std::chrono::duration can be negative and can overflow.
  172. * 2) TDuration uses integer number of microseconds.
  173. * std::chrono::duration is flexible, can be integer of floating point,
  174. * can have different precisions.
  175. * So when casted from std::chrono::duration to TDuration value is clamped and rounded.
  176. * In arithmetic operations std::chrono::duration argument is only rounded,
  177. * result is TDuration and it clamped and rounded.
  178. * In comparisons std::chrono::duration argument is rounded.
  179. */
  180. template <typename T, typename TRatio>
  181. constexpr TDuration(std::chrono::duration<T, TRatio> duration) noexcept {
  182. static_assert(
  183. std::ratio_greater_equal<TRatio, std::micro>::value &&
  184. (!std::is_floating_point<T>::value || std::ratio_greater<TRatio, std::micro>::value),
  185. "Extremely likely it is loss of precision, because TDuration stores microseconds. "
  186. "Cast you duration explicitly to microseconds if you really need it.");
  187. if (duration.count() < 0) {
  188. *this = TDuration::Zero(); // clamp from the bottom
  189. } else {
  190. if
  191. #if !defined(__NVCC__)
  192. constexpr
  193. #endif
  194. /* if [constexpr] */ (std::ratio_greater<TRatio, std::micro>::value || std::is_floating_point<T>::value) {
  195. // clamp from the top
  196. using TCommonDuration = std::chrono::duration<typename std::common_type<T, TValue>::type, TRatio>;
  197. constexpr auto maxDuration = std::chrono::duration<TValue, std::micro>(::Max<TValue>());
  198. if (std::chrono::duration_cast<TCommonDuration>(duration) >= std::chrono::duration_cast<TCommonDuration>(maxDuration)) {
  199. *this = TDuration::Max();
  200. return;
  201. }
  202. }
  203. const TValue us = std::chrono::duration_cast<std::chrono::duration<TValue, std::micro>>(duration).count();
  204. *this = TDuration::MicroSeconds(us);
  205. }
  206. }
  207. static constexpr TDuration FromValue(TValue value) noexcept {
  208. return TDuration(value);
  209. }
  210. static constexpr TDuration MicroSeconds(ui64 us) noexcept {
  211. return TDuration(us);
  212. }
  213. /* noexcept(false) as conversion from T might throw, for example FromString("abc") */
  214. template <typename T>
  215. static constexpr TDuration MilliSeconds(T ms) noexcept(false) {
  216. return MicroSeconds((ui64)(typename NDateTimeHelpers::TPrecisionHelper<T>::THighPrecision(ms) * 1000));
  217. }
  218. using TBase::Days;
  219. using TBase::Hours;
  220. using TBase::MicroSeconds;
  221. using TBase::MilliSeconds;
  222. using TBase::Minutes;
  223. using TBase::Seconds;
  224. /// DeadLineFromTimeOut
  225. inline TInstant ToDeadLine() const;
  226. constexpr TInstant ToDeadLine(TInstant now) const;
  227. static constexpr TDuration Max() noexcept {
  228. return TDuration(::Max<TValue>());
  229. }
  230. static constexpr TDuration Zero() noexcept {
  231. return TDuration();
  232. }
  233. /* noexcept(false) as conversion from T might throw, for example FromString("abc") */
  234. template <typename T>
  235. static constexpr TDuration Seconds(T s) noexcept(false) {
  236. return MilliSeconds(typename NDateTimeHelpers::TPrecisionHelper<T>::THighPrecision(s) * 1000);
  237. }
  238. static constexpr TDuration Minutes(ui64 m) noexcept {
  239. return Seconds(m * 60);
  240. }
  241. static constexpr TDuration Hours(ui64 h) noexcept {
  242. return Minutes(h * 60);
  243. }
  244. static constexpr TDuration Days(ui64 d) noexcept {
  245. return Hours(d * 24);
  246. }
  247. /// parses strings like 10s, 15ms, 15.05s, 20us, or just 25 (s). See parser_ut.cpp for details
  248. static TDuration Parse(const TStringBuf input);
  249. static bool TryParse(const TStringBuf input, TDuration& result);
  250. // note global Out method is defined for TDuration, so it could be written to IOutputStream as text
  251. template <class T>
  252. inline TDuration& operator+=(const T& t) noexcept {
  253. return (*this = (*this + t));
  254. }
  255. template <class T>
  256. inline TDuration& operator-=(const T& t) noexcept {
  257. return (*this = (*this - t));
  258. }
  259. template <class T>
  260. inline TDuration& operator*=(const T& t) noexcept {
  261. return (*this = (*this * t));
  262. }
  263. template <class T>
  264. inline TDuration& operator/=(const T& t) noexcept {
  265. return (*this = (*this / t));
  266. }
  267. TString ToString() const;
  268. };
  269. Y_DECLARE_PODTYPE(TDuration);
  270. template <>
  271. struct THash<TDuration> {
  272. size_t operator()(const TDuration& key) const {
  273. return THash<TDuration::TValue>()(key.GetValue());
  274. }
  275. };
  276. /// TInstant and TDuration are guaranteed to have same precision
  277. class TInstant: public TTimeBase<TInstant> {
  278. using TBase = TTimeBase<TInstant>;
  279. private:
  280. /**
  281. * private construct from microseconds since epoch
  282. */
  283. constexpr explicit TInstant(TValue value) noexcept
  284. : TBase(value)
  285. {
  286. }
  287. public:
  288. constexpr TInstant() noexcept {
  289. }
  290. constexpr TInstant(const struct timeval& tv) noexcept
  291. : TBase(tv)
  292. {
  293. }
  294. static constexpr TInstant FromValue(TValue value) noexcept {
  295. return TInstant(value);
  296. }
  297. static inline TInstant Now() {
  298. return TInstant::MicroSeconds(::MicroSeconds());
  299. }
  300. using TBase::Days;
  301. using TBase::Hours;
  302. using TBase::MicroSeconds;
  303. using TBase::MilliSeconds;
  304. using TBase::Minutes;
  305. using TBase::Seconds;
  306. static constexpr TInstant Max() noexcept {
  307. return TInstant(::Max<TValue>());
  308. }
  309. static constexpr TInstant Zero() noexcept {
  310. return TInstant();
  311. }
  312. /// us since epoch
  313. static constexpr TInstant MicroSeconds(ui64 us) noexcept {
  314. return TInstant(us);
  315. }
  316. /// ms since epoch
  317. static constexpr TInstant MilliSeconds(ui64 ms) noexcept {
  318. return MicroSeconds(ms * 1000);
  319. }
  320. /// seconds since epoch
  321. static constexpr TInstant Seconds(ui64 s) noexcept {
  322. return MilliSeconds(s * 1000);
  323. }
  324. /// minutes since epoch
  325. static constexpr TInstant Minutes(ui64 m) noexcept {
  326. return Seconds(m * 60);
  327. }
  328. /// hours since epoch
  329. static constexpr TInstant Hours(ui64 h) noexcept {
  330. return Minutes(h * 60);
  331. }
  332. /// days since epoch
  333. static constexpr TInstant Days(ui64 d) noexcept {
  334. return Hours(d * 24);
  335. }
  336. constexpr time_t TimeT() const noexcept {
  337. return (time_t)Seconds();
  338. }
  339. inline struct timeval TimeVal() const noexcept {
  340. struct timeval tv;
  341. ::Zero(tv);
  342. tv.tv_sec = TimeT();
  343. tv.tv_usec = MicroSecondsOfSecond();
  344. return tv;
  345. }
  346. inline struct tm* LocalTime(struct tm* tm) const noexcept {
  347. time_t clock = Seconds();
  348. return localtime_r(&clock, tm);
  349. }
  350. inline struct tm* GmTime(struct tm* tm) const noexcept {
  351. time_t clock = Seconds();
  352. return GmTimeR(&clock, tm);
  353. }
  354. /**
  355. * Formats the instant using the UTC time zone, with microsecond precision.
  356. *
  357. * @returns An ISO 8601 formatted string, e.g. '2015-11-21T23:30:27.991669Z'.
  358. * @note Global Out method is defined to TInstant, so it can be written as text to IOutputStream.
  359. */
  360. TString ToString() const;
  361. /**
  362. * Formats the instant using the UTC time zone.
  363. *
  364. * @returns An RFC822 formatted string, e.g. 'Sun, 06 Nov 1994 08:49:37 GMT'.
  365. */
  366. TString ToRfc822String() const;
  367. /**
  368. * Formats the instant using the UTC time zone, with second precision.
  369. *
  370. * @returns An ISO 8601 formatted string, e.g. '2015-11-21T23:30:27Z'.
  371. */
  372. TString ToStringUpToSeconds() const;
  373. /**
  374. * Formats the instant using the system time zone, with microsecond precision.
  375. *
  376. * @returns An ISO 8601 / RFC 3339 formatted string,
  377. * e.g. '2015-11-22T04:30:27.991669+05:00'.
  378. */
  379. TString ToIsoStringLocal() const;
  380. /**
  381. * Formats the instant using the system time zone, with microsecond precision.
  382. *
  383. * @returns A semi-ISO 8601 formatted string with timezone without colon,
  384. * e.g. '2015-11-22T04:30:27.991669+0500'.
  385. */
  386. TString ToStringLocal() const;
  387. /**
  388. * Formats the instant using the system time zone.
  389. *
  390. * @returns An RFC822 formatted string, e.g. 'Sun, 06 Nov 1994 08:49:37 MSK'.
  391. */
  392. TString ToRfc822StringLocal() const;
  393. /**
  394. * Formats the instant using the system time zone, with second precision.
  395. *
  396. * @returns An ISO 8601 / RFC 3339 formatted string,
  397. * e.g. '2015-11-22T04:30:27+05:00'.
  398. */
  399. TString ToIsoStringLocalUpToSeconds() const;
  400. /**
  401. * Formats the instant using the system time zone, with second precision.
  402. *
  403. * @returns A semi-ISO 8601 formatted string with timezone without colon,
  404. * e.g. '2015-11-22T04:30:27+0500'.
  405. */
  406. TString ToStringLocalUpToSeconds() const;
  407. TString FormatLocalTime(const char* format) const noexcept;
  408. TString FormatGmTime(const char* format) const noexcept;
  409. /// See #TryParseIso8601.
  410. static TInstant ParseIso8601(TStringBuf);
  411. /// See #TryParseRfc822.
  412. static TInstant ParseRfc822(TStringBuf);
  413. /// See #TryParseHttp.
  414. static TInstant ParseHttp(TStringBuf);
  415. /// See #TryParseX509.
  416. static TInstant ParseX509Validity(TStringBuf);
  417. /// ISO 8601 Representation of Dates and Times
  418. ///
  419. /// @link https://www.iso.org/standard/40874.html Description of format.
  420. static bool TryParseIso8601(TStringBuf input, TInstant& instant);
  421. /// RFC 822 Date and Time specification
  422. ///
  423. /// @link https://tools.ietf.org/html/rfc822#section-5 Description of format.
  424. static bool TryParseRfc822(TStringBuf input, TInstant& instant);
  425. /// RFC 2616 3.3.1 Full Date
  426. ///
  427. /// @link https://tools.ietf.org/html/rfc2616#section-3.3.1 Description of format.
  428. static bool TryParseHttp(TStringBuf input, TInstant& instant);
  429. /// X.509 certificate validity time (see rfc5280 4.1.2.5.*)
  430. ///
  431. /// @link https://tools.ietf.org/html/rfc5280#section-4.1.2.5 Description of format.
  432. static bool TryParseX509(TStringBuf input, TInstant& instant);
  433. static TInstant ParseIso8601Deprecated(TStringBuf);
  434. static TInstant ParseRfc822Deprecated(TStringBuf);
  435. static TInstant ParseHttpDeprecated(TStringBuf);
  436. static TInstant ParseX509ValidityDeprecated(TStringBuf);
  437. static bool TryParseIso8601Deprecated(TStringBuf input, TInstant& instant);
  438. static bool TryParseRfc822Deprecated(TStringBuf input, TInstant& instant);
  439. static bool TryParseHttpDeprecated(TStringBuf input, TInstant& instant);
  440. static bool TryParseX509Deprecated(TStringBuf input, TInstant& instant);
  441. template <class T>
  442. inline TInstant& operator+=(const T& t) noexcept {
  443. return (*this = (*this + t));
  444. }
  445. template <class T>
  446. inline TInstant& operator-=(const T& t) noexcept {
  447. return (*this = (*this - t));
  448. }
  449. };
  450. Y_DECLARE_PODTYPE(TInstant);
  451. template <>
  452. struct THash<TInstant> {
  453. size_t operator()(const TInstant& key) const {
  454. return THash<TInstant::TValue>()(key.GetValue());
  455. }
  456. };
  457. namespace NPrivate {
  458. template <bool PrintUpToSeconds, bool iso>
  459. struct TPrintableLocalTime {
  460. TInstant MomentToPrint;
  461. constexpr explicit TPrintableLocalTime(TInstant momentToPrint)
  462. : MomentToPrint(momentToPrint)
  463. {
  464. }
  465. };
  466. }
  467. /** @name Helpers for printing local times to `IOutputStream`s.
  468. * The FormatLocal* functions create an opaque object that, when written to
  469. * a `IOutputStream`, outputs this instant as an ISO 8601 formatted string
  470. * using the system time zone.
  471. *
  472. * @note The only reason behind this set of functions is to avoid excessive
  473. * allocations when you directly print the local time to a stream.
  474. *
  475. * If you need something beyond just printing the value or your code
  476. * is not performance-critical, feel free to use the corresponding
  477. * TInstant::ToString*() functions.
  478. */
  479. ///@{
  480. /// @see TInstant::ToIsoStringLocal()
  481. ::NPrivate::TPrintableLocalTime<false, true> FormatIsoLocal(TInstant instant);
  482. /// @see TInstant::ToStringLocal()
  483. ::NPrivate::TPrintableLocalTime<false, false> FormatLocal(TInstant instant);
  484. /// @see TInstant::ToIsoStringLocalUpToSeconds()
  485. ::NPrivate::TPrintableLocalTime<true, true> FormatIsoLocalUpToSeconds(TInstant instant);
  486. /// @see TInstant::ToStringLocalUpToSeconds()
  487. ::NPrivate::TPrintableLocalTime<true, false> FormatLocalUpToSeconds(TInstant instant);
  488. ///@}
  489. template <class S>
  490. static constexpr bool operator<(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  491. return l.GetValue() < r.GetValue();
  492. }
  493. template <class S>
  494. static constexpr bool operator<=(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  495. return l.GetValue() <= r.GetValue();
  496. }
  497. template <class S>
  498. static constexpr bool operator==(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  499. return l.GetValue() == r.GetValue();
  500. }
  501. template <class S>
  502. static constexpr bool operator!=(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  503. return l.GetValue() != r.GetValue();
  504. }
  505. template <class S>
  506. static constexpr bool operator>(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  507. return l.GetValue() > r.GetValue();
  508. }
  509. template <class S>
  510. static constexpr bool operator>=(const TTimeBase<S>& l, const TTimeBase<S>& r) noexcept {
  511. return l.GetValue() >= r.GetValue();
  512. }
  513. namespace NDateTimeHelpers {
  514. template <typename T>
  515. static constexpr T SumWithSaturation(T a, T b) {
  516. static_assert(!std::numeric_limits<T>::is_signed, "expect !std::numeric_limits<T>::is_signed");
  517. return Max<T>() - a < b ? Max<T>() : a + b;
  518. }
  519. template <typename T>
  520. static constexpr T DiffWithSaturation(T a, T b) {
  521. static_assert(!std::numeric_limits<T>::is_signed, "expect !std::numeric_limits<T>::is_signed");
  522. return a < b ? 0 : a - b;
  523. }
  524. }
  525. constexpr TDuration operator-(const TInstant& l, const TInstant& r) noexcept {
  526. return TDuration::FromValue(::NDateTimeHelpers::DiffWithSaturation(l.GetValue(), r.GetValue()));
  527. }
  528. constexpr TInstant operator+(const TInstant& i, const TDuration& d) noexcept {
  529. return TInstant::FromValue(::NDateTimeHelpers::SumWithSaturation(i.GetValue(), d.GetValue()));
  530. }
  531. constexpr TInstant operator-(const TInstant& i, const TDuration& d) noexcept {
  532. return TInstant::FromValue(::NDateTimeHelpers::DiffWithSaturation(i.GetValue(), d.GetValue()));
  533. }
  534. constexpr TDuration operator-(const TDuration& l, const TDuration& r) noexcept {
  535. return TDuration::FromValue(::NDateTimeHelpers::DiffWithSaturation(l.GetValue(), r.GetValue()));
  536. }
  537. constexpr TDuration operator+(const TDuration& l, const TDuration& r) noexcept {
  538. return TDuration::FromValue(::NDateTimeHelpers::SumWithSaturation(l.GetValue(), r.GetValue()));
  539. }
  540. template <typename T, typename TRatio>
  541. constexpr bool operator==(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  542. return r.count() >= 0 && l == TDuration(r);
  543. }
  544. #if defined(__cpp_lib_three_way_comparison)
  545. template <typename T, typename TRatio>
  546. constexpr std::strong_ordering operator<=>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  547. if (r.count() < 0) {
  548. return std::strong_ordering::greater;
  549. }
  550. return l.GetValue() <=> TDuration(r).GetValue();
  551. }
  552. #else
  553. template <typename T, typename TRatio>
  554. constexpr bool operator<(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  555. return r.count() >= 0 && l < TDuration(r);
  556. }
  557. template <typename T, typename TRatio>
  558. constexpr bool operator<=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  559. return r.count() >= 0 && l <= TDuration(r);
  560. }
  561. template <typename T, typename TRatio>
  562. constexpr bool operator!=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  563. return !(l == r);
  564. }
  565. template <typename T, typename TRatio>
  566. constexpr bool operator>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  567. return r.count() < 0 || l > TDuration(r);
  568. }
  569. template <typename T, typename TRatio>
  570. constexpr bool operator>=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  571. return r.count() < 0 || l >= TDuration(r);
  572. }
  573. template <typename T, typename TRatio>
  574. constexpr bool operator<(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  575. return r > l;
  576. }
  577. template <typename T, typename TRatio>
  578. constexpr bool operator<=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  579. return r >= l;
  580. }
  581. template <typename T, typename TRatio>
  582. constexpr bool operator==(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  583. return r == l;
  584. }
  585. template <typename T, typename TRatio>
  586. constexpr bool operator!=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  587. return r != l;
  588. }
  589. template <typename T, typename TRatio>
  590. constexpr bool operator>(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  591. return r < l;
  592. }
  593. template <typename T, typename TRatio>
  594. constexpr bool operator>=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  595. return r >= l;
  596. }
  597. #endif
  598. template <typename T, typename TRatio>
  599. constexpr TDuration operator+(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  600. return r < r.zero() ? l - TDuration(-r) : l + TDuration(r);
  601. }
  602. template <typename T, typename TRatio>
  603. constexpr TDuration operator+(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  604. return r + l;
  605. }
  606. template <typename T, typename TRatio>
  607. constexpr TDuration operator-(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  608. return l + (-r);
  609. }
  610. template <typename T, typename TRatio>
  611. constexpr TDuration operator-(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept {
  612. return TDuration(l) - r;
  613. }
  614. template <typename T, typename TRatio>
  615. constexpr TInstant operator+(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  616. return r < r.zero() ? l - TDuration(-r) : l + TDuration(r);
  617. }
  618. template <typename T, typename TRatio>
  619. constexpr TInstant operator-(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept {
  620. return l + (-r);
  621. }
  622. template <class T>
  623. inline TDuration operator*(TDuration d, T t) noexcept {
  624. Y_ASSERT(t >= T());
  625. Y_ASSERT(t == T() || Max<TDuration::TValue>() / t >= d.GetValue());
  626. return TDuration::FromValue(d.GetValue() * t);
  627. }
  628. template <>
  629. inline TDuration operator*(TDuration d, double t) noexcept {
  630. Y_ASSERT(t >= 0 && MaxFloor<TDuration::TValue>() >= d.GetValue() * t);
  631. return TDuration::FromValue(d.GetValue() * t);
  632. }
  633. template <>
  634. inline TDuration operator*(TDuration d, float t) noexcept {
  635. return d * static_cast<double>(t);
  636. }
  637. template <class T>
  638. inline TDuration operator*(T t, TDuration d) noexcept {
  639. return d * t;
  640. }
  641. template <class T, std::enable_if_t<!std::is_same<TDuration, T>::value, int> = 0>
  642. constexpr TDuration operator/(const TDuration& d, const T& t) noexcept {
  643. return TDuration::FromValue(d.GetValue() / t);
  644. }
  645. constexpr double operator/(const TDuration& x, const TDuration& y) noexcept {
  646. return static_cast<double>(x.GetValue()) / static_cast<double>(y.GetValue());
  647. }
  648. inline TInstant TDuration::ToDeadLine() const {
  649. return ToDeadLine(TInstant::Now());
  650. }
  651. constexpr TInstant TDuration::ToDeadLine(TInstant now) const {
  652. return now + *this;
  653. }
  654. void Sleep(TDuration duration);
  655. void SleepUntil(TInstant instant);
  656. static inline TInstant Now() noexcept {
  657. return TInstant::Now();
  658. }
  659. #ifdef _MSC_VER
  660. #pragma warning(pop)
  661. #endif // _MSC_VER