You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

631 lines
22 KiB

11 months ago
  1. // Copyright Toru Niina 2017.
  2. // Distributed under the MIT License.
  3. #ifndef TOML11_DATETIME_HPP
  4. #define TOML11_DATETIME_HPP
  5. #include <cstdint>
  6. #include <cstdlib>
  7. #include <ctime>
  8. #include <array>
  9. #include <chrono>
  10. #include <iomanip>
  11. #include <ostream>
  12. #include <tuple>
  13. namespace toml
  14. {
  15. // To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is
  16. // provided in the absolutely same purpose, but C++11 is actually not compatible
  17. // with C11. We need to dispatch the function depending on the OS.
  18. namespace detail
  19. {
  20. // TODO: find more sophisticated way to handle this
  21. #if defined(_MSC_VER)
  22. inline std::tm localtime_s(const std::time_t* src)
  23. {
  24. std::tm dst;
  25. const auto result = ::localtime_s(&dst, src);
  26. if (result) { throw std::runtime_error("localtime_s failed."); }
  27. return dst;
  28. }
  29. inline std::tm gmtime_s(const std::time_t* src)
  30. {
  31. std::tm dst;
  32. const auto result = ::gmtime_s(&dst, src);
  33. if (result) { throw std::runtime_error("gmtime_s failed."); }
  34. return dst;
  35. }
  36. #elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
  37. inline std::tm localtime_s(const std::time_t* src)
  38. {
  39. std::tm dst;
  40. const auto result = ::localtime_r(src, &dst);
  41. if (!result) { throw std::runtime_error("localtime_r failed."); }
  42. return dst;
  43. }
  44. inline std::tm gmtime_s(const std::time_t* src)
  45. {
  46. std::tm dst;
  47. const auto result = ::gmtime_r(src, &dst);
  48. if (!result) { throw std::runtime_error("gmtime_r failed."); }
  49. return dst;
  50. }
  51. #else // fallback. not threadsafe
  52. inline std::tm localtime_s(const std::time_t* src)
  53. {
  54. const auto result = std::localtime(src);
  55. if (!result) { throw std::runtime_error("localtime failed."); }
  56. return *result;
  57. }
  58. inline std::tm gmtime_s(const std::time_t* src)
  59. {
  60. const auto result = std::gmtime(src);
  61. if (!result) { throw std::runtime_error("gmtime failed."); }
  62. return *result;
  63. }
  64. #endif
  65. } // detail
  66. enum class month_t : std::uint8_t
  67. {
  68. Jan = 0,
  69. Feb = 1,
  70. Mar = 2,
  71. Apr = 3,
  72. May = 4,
  73. Jun = 5,
  74. Jul = 6,
  75. Aug = 7,
  76. Sep = 8,
  77. Oct = 9,
  78. Nov = 10,
  79. Dec = 11
  80. };
  81. struct local_date
  82. {
  83. std::int16_t year{}; // A.D. (like, 2018)
  84. std::uint8_t month{}; // [0, 11]
  85. std::uint8_t day{}; // [1, 31]
  86. local_date(int y, month_t m, int d)
  87. : year (static_cast<std::int16_t>(y)),
  88. month(static_cast<std::uint8_t>(m)),
  89. day (static_cast<std::uint8_t>(d))
  90. {}
  91. explicit local_date(const std::tm& t)
  92. : year (static_cast<std::int16_t>(t.tm_year + 1900)),
  93. month(static_cast<std::uint8_t>(t.tm_mon)),
  94. day (static_cast<std::uint8_t>(t.tm_mday))
  95. {}
  96. explicit local_date(const std::chrono::system_clock::time_point& tp)
  97. {
  98. const auto t = std::chrono::system_clock::to_time_t(tp);
  99. const auto time = detail::localtime_s(&t);
  100. *this = local_date(time);
  101. }
  102. explicit local_date(const std::time_t t)
  103. : local_date(std::chrono::system_clock::from_time_t(t))
  104. {}
  105. operator std::chrono::system_clock::time_point() const
  106. {
  107. // std::mktime returns date as local time zone. no conversion needed
  108. std::tm t;
  109. t.tm_sec = 0;
  110. t.tm_min = 0;
  111. t.tm_hour = 0;
  112. t.tm_mday = static_cast<int>(this->day);
  113. t.tm_mon = static_cast<int>(this->month);
  114. t.tm_year = static_cast<int>(this->year) - 1900;
  115. t.tm_wday = 0; // the value will be ignored
  116. t.tm_yday = 0; // the value will be ignored
  117. t.tm_isdst = -1;
  118. return std::chrono::system_clock::from_time_t(std::mktime(&t));
  119. }
  120. operator std::time_t() const
  121. {
  122. return std::chrono::system_clock::to_time_t(
  123. std::chrono::system_clock::time_point(*this));
  124. }
  125. local_date() = default;
  126. ~local_date() = default;
  127. local_date(local_date const&) = default;
  128. local_date(local_date&&) = default;
  129. local_date& operator=(local_date const&) = default;
  130. local_date& operator=(local_date&&) = default;
  131. };
  132. inline bool operator==(const local_date& lhs, const local_date& rhs)
  133. {
  134. return std::make_tuple(lhs.year, lhs.month, lhs.day) ==
  135. std::make_tuple(rhs.year, rhs.month, rhs.day);
  136. }
  137. inline bool operator!=(const local_date& lhs, const local_date& rhs)
  138. {
  139. return !(lhs == rhs);
  140. }
  141. inline bool operator< (const local_date& lhs, const local_date& rhs)
  142. {
  143. return std::make_tuple(lhs.year, lhs.month, lhs.day) <
  144. std::make_tuple(rhs.year, rhs.month, rhs.day);
  145. }
  146. inline bool operator<=(const local_date& lhs, const local_date& rhs)
  147. {
  148. return (lhs < rhs) || (lhs == rhs);
  149. }
  150. inline bool operator> (const local_date& lhs, const local_date& rhs)
  151. {
  152. return !(lhs <= rhs);
  153. }
  154. inline bool operator>=(const local_date& lhs, const local_date& rhs)
  155. {
  156. return !(lhs < rhs);
  157. }
  158. template<typename charT, typename traits>
  159. std::basic_ostream<charT, traits>&
  160. operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
  161. {
  162. os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
  163. os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
  164. os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
  165. return os;
  166. }
  167. struct local_time
  168. {
  169. std::uint8_t hour{}; // [0, 23]
  170. std::uint8_t minute{}; // [0, 59]
  171. std::uint8_t second{}; // [0, 60]
  172. std::uint16_t millisecond{}; // [0, 999]
  173. std::uint16_t microsecond{}; // [0, 999]
  174. std::uint16_t nanosecond{}; // [0, 999]
  175. local_time(int h, int m, int s,
  176. int ms = 0, int us = 0, int ns = 0)
  177. : hour (static_cast<std::uint8_t>(h)),
  178. minute(static_cast<std::uint8_t>(m)),
  179. second(static_cast<std::uint8_t>(s)),
  180. millisecond(static_cast<std::uint16_t>(ms)),
  181. microsecond(static_cast<std::uint16_t>(us)),
  182. nanosecond (static_cast<std::uint16_t>(ns))
  183. {}
  184. explicit local_time(const std::tm& t)
  185. : hour (static_cast<std::uint8_t>(t.tm_hour)),
  186. minute(static_cast<std::uint8_t>(t.tm_min)),
  187. second(static_cast<std::uint8_t>(t.tm_sec)),
  188. millisecond(0), microsecond(0), nanosecond(0)
  189. {}
  190. template<typename Rep, typename Period>
  191. explicit local_time(const std::chrono::duration<Rep, Period>& t)
  192. {
  193. const auto h = std::chrono::duration_cast<std::chrono::hours>(t);
  194. this->hour = static_cast<std::uint8_t>(h.count());
  195. const auto t2 = t - h;
  196. const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);
  197. this->minute = static_cast<std::uint8_t>(m.count());
  198. const auto t3 = t2 - m;
  199. const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);
  200. this->second = static_cast<std::uint8_t>(s.count());
  201. const auto t4 = t3 - s;
  202. const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);
  203. this->millisecond = static_cast<std::uint16_t>(ms.count());
  204. const auto t5 = t4 - ms;
  205. const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);
  206. this->microsecond = static_cast<std::uint16_t>(us.count());
  207. const auto t6 = t5 - us;
  208. const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);
  209. this->nanosecond = static_cast<std::uint16_t>(ns.count());
  210. }
  211. operator std::chrono::nanoseconds() const
  212. {
  213. return std::chrono::nanoseconds (this->nanosecond) +
  214. std::chrono::microseconds(this->microsecond) +
  215. std::chrono::milliseconds(this->millisecond) +
  216. std::chrono::seconds(this->second) +
  217. std::chrono::minutes(this->minute) +
  218. std::chrono::hours(this->hour);
  219. }
  220. local_time() = default;
  221. ~local_time() = default;
  222. local_time(local_time const&) = default;
  223. local_time(local_time&&) = default;
  224. local_time& operator=(local_time const&) = default;
  225. local_time& operator=(local_time&&) = default;
  226. };
  227. inline bool operator==(const local_time& lhs, const local_time& rhs)
  228. {
  229. return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) ==
  230. std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);
  231. }
  232. inline bool operator!=(const local_time& lhs, const local_time& rhs)
  233. {
  234. return !(lhs == rhs);
  235. }
  236. inline bool operator< (const local_time& lhs, const local_time& rhs)
  237. {
  238. return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) <
  239. std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);
  240. }
  241. inline bool operator<=(const local_time& lhs, const local_time& rhs)
  242. {
  243. return (lhs < rhs) || (lhs == rhs);
  244. }
  245. inline bool operator> (const local_time& lhs, const local_time& rhs)
  246. {
  247. return !(lhs <= rhs);
  248. }
  249. inline bool operator>=(const local_time& lhs, const local_time& rhs)
  250. {
  251. return !(lhs < rhs);
  252. }
  253. template<typename charT, typename traits>
  254. std::basic_ostream<charT, traits>&
  255. operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
  256. {
  257. os << std::setfill('0') << std::setw(2) << static_cast<int>(time.hour ) << ':';
  258. os << std::setfill('0') << std::setw(2) << static_cast<int>(time.minute) << ':';
  259. os << std::setfill('0') << std::setw(2) << static_cast<int>(time.second);
  260. if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0)
  261. {
  262. os << '.';
  263. os << std::setfill('0') << std::setw(3) << static_cast<int>(time.millisecond);
  264. if(time.microsecond != 0 || time.nanosecond != 0)
  265. {
  266. os << std::setfill('0') << std::setw(3) << static_cast<int>(time.microsecond);
  267. if(time.nanosecond != 0)
  268. {
  269. os << std::setfill('0') << std::setw(3) << static_cast<int>(time.nanosecond);
  270. }
  271. }
  272. }
  273. return os;
  274. }
  275. struct time_offset
  276. {
  277. std::int8_t hour{}; // [-12, 12]
  278. std::int8_t minute{}; // [-59, 59]
  279. time_offset(int h, int m)
  280. : hour (static_cast<std::int8_t>(h)),
  281. minute(static_cast<std::int8_t>(m))
  282. {}
  283. operator std::chrono::minutes() const
  284. {
  285. return std::chrono::minutes(this->minute) +
  286. std::chrono::hours(this->hour);
  287. }
  288. time_offset() = default;
  289. ~time_offset() = default;
  290. time_offset(time_offset const&) = default;
  291. time_offset(time_offset&&) = default;
  292. time_offset& operator=(time_offset const&) = default;
  293. time_offset& operator=(time_offset&&) = default;
  294. };
  295. inline bool operator==(const time_offset& lhs, const time_offset& rhs)
  296. {
  297. return std::make_tuple(lhs.hour, lhs.minute) ==
  298. std::make_tuple(rhs.hour, rhs.minute);
  299. }
  300. inline bool operator!=(const time_offset& lhs, const time_offset& rhs)
  301. {
  302. return !(lhs == rhs);
  303. }
  304. inline bool operator< (const time_offset& lhs, const time_offset& rhs)
  305. {
  306. return std::make_tuple(lhs.hour, lhs.minute) <
  307. std::make_tuple(rhs.hour, rhs.minute);
  308. }
  309. inline bool operator<=(const time_offset& lhs, const time_offset& rhs)
  310. {
  311. return (lhs < rhs) || (lhs == rhs);
  312. }
  313. inline bool operator> (const time_offset& lhs, const time_offset& rhs)
  314. {
  315. return !(lhs <= rhs);
  316. }
  317. inline bool operator>=(const time_offset& lhs, const time_offset& rhs)
  318. {
  319. return !(lhs < rhs);
  320. }
  321. template<typename charT, typename traits>
  322. std::basic_ostream<charT, traits>&
  323. operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
  324. {
  325. if(offset.hour == 0 && offset.minute == 0)
  326. {
  327. os << 'Z';
  328. return os;
  329. }
  330. int minute = static_cast<int>(offset.hour) * 60 + offset.minute;
  331. if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';}
  332. os << std::setfill('0') << std::setw(2) << minute / 60 << ':';
  333. os << std::setfill('0') << std::setw(2) << minute % 60;
  334. return os;
  335. }
  336. struct local_datetime
  337. {
  338. local_date date{};
  339. local_time time{};
  340. local_datetime(local_date d, local_time t): date(d), time(t) {}
  341. explicit local_datetime(const std::tm& t): date(t), time(t){}
  342. explicit local_datetime(const std::chrono::system_clock::time_point& tp)
  343. {
  344. const auto t = std::chrono::system_clock::to_time_t(tp);
  345. std::tm ltime = detail::localtime_s(&t);
  346. this->date = local_date(ltime);
  347. this->time = local_time(ltime);
  348. // std::tm lacks subsecond information, so diff between tp and tm
  349. // can be used to get millisecond & microsecond information.
  350. const auto t_diff = tp -
  351. std::chrono::system_clock::from_time_t(std::mktime(&ltime));
  352. this->time.millisecond = static_cast<std::uint16_t>(
  353. std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
  354. this->time.microsecond = static_cast<std::uint16_t>(
  355. std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
  356. this->time.nanosecond = static_cast<std::uint16_t>(
  357. std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());
  358. }
  359. explicit local_datetime(const std::time_t t)
  360. : local_datetime(std::chrono::system_clock::from_time_t(t))
  361. {}
  362. operator std::chrono::system_clock::time_point() const
  363. {
  364. using internal_duration =
  365. typename std::chrono::system_clock::time_point::duration;
  366. // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
  367. // of local_date and local_time independently, the conversion fails if
  368. // it is the day when DST begins or ends. Since local_date considers the
  369. // time is 00:00 A.M. and local_time does not consider DST because it
  370. // does not have any date information. We need to consider both date and
  371. // time information at the same time to convert it correctly.
  372. std::tm t;
  373. t.tm_sec = static_cast<int>(this->time.second);
  374. t.tm_min = static_cast<int>(this->time.minute);
  375. t.tm_hour = static_cast<int>(this->time.hour);
  376. t.tm_mday = static_cast<int>(this->date.day);
  377. t.tm_mon = static_cast<int>(this->date.month);
  378. t.tm_year = static_cast<int>(this->date.year) - 1900;
  379. t.tm_wday = 0; // the value will be ignored
  380. t.tm_yday = 0; // the value will be ignored
  381. t.tm_isdst = -1;
  382. // std::mktime returns date as local time zone. no conversion needed
  383. auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
  384. dt += std::chrono::duration_cast<internal_duration>(
  385. std::chrono::milliseconds(this->time.millisecond) +
  386. std::chrono::microseconds(this->time.microsecond) +
  387. std::chrono::nanoseconds (this->time.nanosecond));
  388. return dt;
  389. }
  390. operator std::time_t() const
  391. {
  392. return std::chrono::system_clock::to_time_t(
  393. std::chrono::system_clock::time_point(*this));
  394. }
  395. local_datetime() = default;
  396. ~local_datetime() = default;
  397. local_datetime(local_datetime const&) = default;
  398. local_datetime(local_datetime&&) = default;
  399. local_datetime& operator=(local_datetime const&) = default;
  400. local_datetime& operator=(local_datetime&&) = default;
  401. };
  402. inline bool operator==(const local_datetime& lhs, const local_datetime& rhs)
  403. {
  404. return std::make_tuple(lhs.date, lhs.time) ==
  405. std::make_tuple(rhs.date, rhs.time);
  406. }
  407. inline bool operator!=(const local_datetime& lhs, const local_datetime& rhs)
  408. {
  409. return !(lhs == rhs);
  410. }
  411. inline bool operator< (const local_datetime& lhs, const local_datetime& rhs)
  412. {
  413. return std::make_tuple(lhs.date, lhs.time) <
  414. std::make_tuple(rhs.date, rhs.time);
  415. }
  416. inline bool operator<=(const local_datetime& lhs, const local_datetime& rhs)
  417. {
  418. return (lhs < rhs) || (lhs == rhs);
  419. }
  420. inline bool operator> (const local_datetime& lhs, const local_datetime& rhs)
  421. {
  422. return !(lhs <= rhs);
  423. }
  424. inline bool operator>=(const local_datetime& lhs, const local_datetime& rhs)
  425. {
  426. return !(lhs < rhs);
  427. }
  428. template<typename charT, typename traits>
  429. std::basic_ostream<charT, traits>&
  430. operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
  431. {
  432. os << dt.date << 'T' << dt.time;
  433. return os;
  434. }
  435. struct offset_datetime
  436. {
  437. local_date date{};
  438. local_time time{};
  439. time_offset offset{};
  440. offset_datetime(local_date d, local_time t, time_offset o)
  441. : date(d), time(t), offset(o)
  442. {}
  443. offset_datetime(const local_datetime& dt, time_offset o)
  444. : date(dt.date), time(dt.time), offset(o)
  445. {}
  446. explicit offset_datetime(const local_datetime& ld)
  447. : date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
  448. // use the current local timezone offset
  449. {}
  450. explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
  451. : offset(0, 0) // use gmtime
  452. {
  453. const auto timet = std::chrono::system_clock::to_time_t(tp);
  454. const auto tm = detail::gmtime_s(&timet);
  455. this->date = local_date(tm);
  456. this->time = local_time(tm);
  457. }
  458. explicit offset_datetime(const std::time_t& t)
  459. : offset(0, 0) // use gmtime
  460. {
  461. const auto tm = detail::gmtime_s(&t);
  462. this->date = local_date(tm);
  463. this->time = local_time(tm);
  464. }
  465. explicit offset_datetime(const std::tm& t)
  466. : offset(0, 0) // assume gmtime
  467. {
  468. this->date = local_date(t);
  469. this->time = local_time(t);
  470. }
  471. operator std::chrono::system_clock::time_point() const
  472. {
  473. // get date-time
  474. using internal_duration =
  475. typename std::chrono::system_clock::time_point::duration;
  476. // first, convert it to local date-time information in the same way as
  477. // local_datetime does. later we will use time_t to adjust time offset.
  478. std::tm t;
  479. t.tm_sec = static_cast<int>(this->time.second);
  480. t.tm_min = static_cast<int>(this->time.minute);
  481. t.tm_hour = static_cast<int>(this->time.hour);
  482. t.tm_mday = static_cast<int>(this->date.day);
  483. t.tm_mon = static_cast<int>(this->date.month);
  484. t.tm_year = static_cast<int>(this->date.year) - 1900;
  485. t.tm_wday = 0; // the value will be ignored
  486. t.tm_yday = 0; // the value will be ignored
  487. t.tm_isdst = -1;
  488. const std::time_t tp_loc = std::mktime(std::addressof(t));
  489. auto tp = std::chrono::system_clock::from_time_t(tp_loc);
  490. tp += std::chrono::duration_cast<internal_duration>(
  491. std::chrono::milliseconds(this->time.millisecond) +
  492. std::chrono::microseconds(this->time.microsecond) +
  493. std::chrono::nanoseconds (this->time.nanosecond));
  494. // Since mktime uses local time zone, it should be corrected.
  495. // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
  496. // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
  497. // to add `+09:00` to `03:00:00Z`.
  498. // Here, it uses the time_t converted from date-time info to handle
  499. // daylight saving time.
  500. const auto ofs = get_local_offset(std::addressof(tp_loc));
  501. tp += std::chrono::hours (ofs.hour);
  502. tp += std::chrono::minutes(ofs.minute);
  503. // We got `12:00:00Z` by correcting local timezone applied by mktime.
  504. // Then we will apply the offset. Let's say `12:00:00-08:00` is given.
  505. // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
  506. // So we need to subtract the offset.
  507. tp -= std::chrono::minutes(this->offset);
  508. return tp;
  509. }
  510. operator std::time_t() const
  511. {
  512. return std::chrono::system_clock::to_time_t(
  513. std::chrono::system_clock::time_point(*this));
  514. }
  515. offset_datetime() = default;
  516. ~offset_datetime() = default;
  517. offset_datetime(offset_datetime const&) = default;
  518. offset_datetime(offset_datetime&&) = default;
  519. offset_datetime& operator=(offset_datetime const&) = default;
  520. offset_datetime& operator=(offset_datetime&&) = default;
  521. private:
  522. static time_offset get_local_offset(const std::time_t* tp)
  523. {
  524. // get local timezone with the same date-time information as mktime
  525. const auto t = detail::localtime_s(tp);
  526. std::array<char, 6> buf;
  527. const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0
  528. if(result != 5)
  529. {
  530. throw std::runtime_error("toml::offset_datetime: cannot obtain "
  531. "timezone information of current env");
  532. }
  533. const int ofs = std::atoi(buf.data());
  534. const int ofs_h = ofs / 100;
  535. const int ofs_m = ofs - (ofs_h * 100);
  536. return time_offset(ofs_h, ofs_m);
  537. }
  538. };
  539. inline bool operator==(const offset_datetime& lhs, const offset_datetime& rhs)
  540. {
  541. return std::make_tuple(lhs.date, lhs.time, lhs.offset) ==
  542. std::make_tuple(rhs.date, rhs.time, rhs.offset);
  543. }
  544. inline bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs)
  545. {
  546. return !(lhs == rhs);
  547. }
  548. inline bool operator< (const offset_datetime& lhs, const offset_datetime& rhs)
  549. {
  550. return std::make_tuple(lhs.date, lhs.time, lhs.offset) <
  551. std::make_tuple(rhs.date, rhs.time, rhs.offset);
  552. }
  553. inline bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs)
  554. {
  555. return (lhs < rhs) || (lhs == rhs);
  556. }
  557. inline bool operator> (const offset_datetime& lhs, const offset_datetime& rhs)
  558. {
  559. return !(lhs <= rhs);
  560. }
  561. inline bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs)
  562. {
  563. return !(lhs < rhs);
  564. }
  565. template<typename charT, typename traits>
  566. std::basic_ostream<charT, traits>&
  567. operator<<(std::basic_ostream<charT, traits>& os, const offset_datetime& dt)
  568. {
  569. os << dt.date << 'T' << dt.time << dt.offset;
  570. return os;
  571. }
  572. }//toml
  573. #endif// TOML11_DATETIME