// // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_MYSQL_IMPL_DATETIME_HPP #define BOOST_MYSQL_IMPL_DATETIME_HPP #pragma once #include #include #include #include #include #include #include BOOST_CXX14_CONSTEXPR boost::mysql::datetime::datetime(time_point tp) { using std::chrono::duration_cast; using std::chrono::hours; using std::chrono::microseconds; using std::chrono::minutes; using std::chrono::seconds; // Avoiding using -= for durations as it's not constexpr until C++17 auto input_dur = tp.time_since_epoch(); auto rem = input_dur % days(1); if (rem.count() < 0) rem = rem + days(1); auto num_days = duration_cast(input_dur - rem); auto num_hours = duration_cast(rem); rem = rem - num_hours; auto num_minutes = duration_cast(rem); rem = rem - num_minutes; auto num_seconds = duration_cast(rem); rem = rem - num_seconds; auto num_microseconds = duration_cast(rem); assert(num_hours.count() >= 0 && num_hours.count() <= detail::max_hour); assert(num_minutes.count() >= 0 && num_minutes.count() <= detail::max_min); assert(num_seconds.count() >= 0 && num_seconds.count() <= detail::max_sec); assert(num_microseconds.count() >= 0 && num_microseconds.count() <= detail::max_micro); bool ok = detail::days_to_ymd(num_days.count(), year_, month_, day_); if (!ok) throw std::out_of_range("datetime::datetime: time_point was out of range"); microsecond_ = static_cast(num_microseconds.count()); second_ = static_cast(num_seconds.count()); minute_ = static_cast(num_minutes.count()); hour_ = static_cast(num_hours.count()); } constexpr bool boost::mysql::datetime::valid() const noexcept { return detail::is_valid(year_, month_, day_) && hour_ <= detail::max_hour && minute_ <= detail::max_min && second_ <= detail::max_sec && microsecond_ <= detail::max_micro; } BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::get_time_point( ) const noexcept { assert(valid()); return unch_get_time_point(); } BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::as_time_point() const { if (!valid()) throw std::invalid_argument("datetime::as_time_point: invalid datetime"); return unch_get_time_point(); } constexpr bool boost::mysql::datetime::operator==(const datetime& rhs) const noexcept { return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_ && hour_ == rhs.hour_ && minute_ == rhs.minute_ && second_ == rhs.second_ && microsecond_ == rhs.microsecond_; } BOOST_CXX14_CONSTEXPR boost::mysql::datetime::time_point boost::mysql::datetime::unch_get_time_point( ) const noexcept { // Doing time of day independently to prevent overflow days d(detail::ymd_to_days(year_, month_, day_)); auto time_of_day = std::chrono::hours(hour_) + std::chrono::minutes(minute_) + std::chrono::seconds(second_) + std::chrono::microseconds(microsecond_); return time_point(d) + time_of_day; } std::ostream& boost::mysql::operator<<(std::ostream& os, const datetime& value) { // Worst-case output is 37 chars, extra space just in case char buffer[64]{}; snprintf( buffer, sizeof(buffer), "%04u-%02u-%02u %02d:%02u:%02u.%06u", static_cast(value.year()), static_cast(value.month()), static_cast(value.day()), static_cast(value.hour()), static_cast(value.minute()), static_cast(value.second()), static_cast(value.microsecond()) ); os << buffer; return os; } #endif