datetime.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //
  2. // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_IMPL_DATETIME_HPP
  8. #define BOOST_MYSQL_IMPL_DATETIME_HPP
  9. #pragma once
  10. #include <boost/mysql/datetime.hpp>
  11. #include <boost/mysql/days.hpp>
  12. #include <boost/mysql/detail/auxiliar/datetime.hpp>
  13. #include <cassert>
  14. #include <cstdio>
  15. #include <ostream>
  16. #include <stdexcept>
  17. BOOST_CXX14_CONSTEXPR boost::mysql::datetime::datetime(time_point tp)
  18. {
  19. using std::chrono::duration_cast;
  20. using std::chrono::hours;
  21. using std::chrono::microseconds;
  22. using std::chrono::minutes;
  23. using std::chrono::seconds;
  24. // Avoiding using -= for durations as it's not constexpr until C++17
  25. auto input_dur = tp.time_since_epoch();
  26. auto rem = input_dur % days(1);
  27. if (rem.count() < 0)
  28. rem = rem + days(1);
  29. auto num_days = duration_cast<days>(input_dur - rem);
  30. auto num_hours = duration_cast<hours>(rem);
  31. rem = rem - num_hours;
  32. auto num_minutes = duration_cast<minutes>(rem);
  33. rem = rem - num_minutes;
  34. auto num_seconds = duration_cast<seconds>(rem);
  35. rem = rem - num_seconds;
  36. auto num_microseconds = duration_cast<microseconds>(rem);
  37. assert(num_hours.count() >= 0 && num_hours.count() <= detail::max_hour);
  38. assert(num_minutes.count() >= 0 && num_minutes.count() <= detail::max_min);
  39. assert(num_seconds.count() >= 0 && num_seconds.count() <= detail::max_sec);
  40. assert(num_microseconds.count() >= 0 && num_microseconds.count() <= detail::max_micro);
  41. bool ok = detail::days_to_ymd(num_days.count(), year_, month_, day_);
  42. if (!ok)
  43. throw std::out_of_range("datetime::datetime: time_point was out of range");
  44. microsecond_ = static_cast<std::uint32_t>(num_microseconds.count());
  45. second_ = static_cast<std::uint8_t>(num_seconds.count());
  46. minute_ = static_cast<std::uint8_t>(num_minutes.count());
  47. hour_ = static_cast<std::uint8_t>(num_hours.count());
  48. }
  49. constexpr bool boost::mysql::datetime::valid() const noexcept
  50. {
  51. return detail::is_valid(year_, month_, day_) && hour_ <= detail::max_hour && minute_ <= detail::max_min &&
  52. second_ <= detail::max_sec && microsecond_ <= detail::max_micro;
  53. }
  54. BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::get_time_point(
  55. ) const noexcept
  56. {
  57. assert(valid());
  58. return unch_get_time_point();
  59. }
  60. BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::as_time_point() const
  61. {
  62. if (!valid())
  63. throw std::invalid_argument("datetime::as_time_point: invalid datetime");
  64. return unch_get_time_point();
  65. }
  66. constexpr bool boost::mysql::datetime::operator==(const datetime& rhs) const noexcept
  67. {
  68. return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_ && hour_ == rhs.hour_ &&
  69. minute_ == rhs.minute_ && second_ == rhs.second_ && microsecond_ == rhs.microsecond_;
  70. }
  71. BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::unch_get_time_point(
  72. ) const noexcept
  73. {
  74. // Doing time of day independently to prevent overflow
  75. days d(detail::ymd_to_days(year_, month_, day_));
  76. auto time_of_day = std::chrono::hours(hour_) + std::chrono::minutes(minute_) +
  77. std::chrono::seconds(second_) + std::chrono::microseconds(microsecond_);
  78. return time_point(d) + time_of_day;
  79. }
  80. std::ostream& boost::mysql::operator<<(std::ostream& os, const datetime& value)
  81. {
  82. // Worst-case output is 37 chars, extra space just in case
  83. char buffer[64]{};
  84. snprintf(
  85. buffer,
  86. sizeof(buffer),
  87. "%04u-%02u-%02u %02d:%02u:%02u.%06u",
  88. static_cast<unsigned>(value.year()),
  89. static_cast<unsigned>(value.month()),
  90. static_cast<unsigned>(value.day()),
  91. static_cast<unsigned>(value.hour()),
  92. static_cast<unsigned>(value.minute()),
  93. static_cast<unsigned>(value.second()),
  94. static_cast<unsigned>(value.microsecond())
  95. );
  96. os << buffer;
  97. return os;
  98. }
  99. #endif