1//
2// Copyright (c) 2019-2024 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
8#ifndef BOOST_MYSQL_DATE_HPP
9#define BOOST_MYSQL_DATE_HPP
10
11#include <boost/mysql/days.hpp>
12
13#include <boost/mysql/detail/config.hpp>
14#include <boost/mysql/detail/datetime.hpp>
15
16#include <boost/assert.hpp>
17#include <boost/config.hpp>
18#include <boost/throw_exception.hpp>
19
20#include <chrono>
21#include <cstdint>
22#include <iosfwd>
23#include <stdexcept>
24
25namespace boost {
26namespace mysql {
27
28/**
29 * \brief Type representing MySQL `DATE` data type.
30 * \details Represents a broken date by its year, month and day components.
31 * This type is close to the protocol and should not be used as a vocabulary type.
32 * Instead, cast it to a `std::chrono::time_point` by calling \ref as_time_point
33 * or \ref get_time_point.
34 * \n
35 * As opposed to `time_point`, this type allows representing invalid and zero dates.
36 */
37class date
38{
39public:
40 /// A `std::chrono::time_point` that can represent any valid `date`.
41 using time_point = std::chrono::time_point<std::chrono::system_clock, days>;
42
43 /**
44 * \brief Constructs a zero date.
45 * \details
46 * Results in a date with all of its components set to zero.
47 *
48 * \par Exception safety
49 * No-throw guarantee.
50 */
51 constexpr date() noexcept = default;
52
53 /**
54 * \brief Constructs a date from its year, month and date components.
55 * \par Exception safety
56 * No-throw guarantee.
57 */
58 constexpr date(std::uint16_t year, std::uint8_t month, std::uint8_t day) noexcept
59 : year_(year), month_(month), day_(day)
60 {
61 }
62
63 /**
64 * \brief Constructs a date from a `time_point`.
65 * \par Exception safety
66 * Strong guarantee. Throws on invalid input.
67 * \throws std::out_of_range If the resulting `date` would be
68 * out of the [\ref min_date, \ref max_date] range.
69 */
70 BOOST_CXX14_CONSTEXPR explicit date(time_point tp)
71 {
72 bool ok = detail::days_to_ymd(num_days: tp.time_since_epoch().count(), years&: year_, month&: month_, day&: day_);
73 if (!ok)
74 BOOST_THROW_EXCEPTION(std::out_of_range("date::date: time_point was out of range"));
75 }
76
77 /**
78 * \brief Retrieves the year component.
79 * \par Exception safety
80 * No-throw guarantee.
81 */
82 constexpr std::uint16_t year() const noexcept { return year_; }
83
84 /**
85 * \brief Retrieves the month component.
86 * \par Exception safety
87 * No-throw guarantee.
88 */
89 constexpr std::uint8_t month() const noexcept { return month_; }
90
91 /**
92 * \brief Retrieves the day component.
93 * \par Exception safety
94 * No-throw guarantee.
95 */
96 constexpr std::uint8_t day() const noexcept { return day_; }
97
98 /**
99 * \brief Returns `true` if `*this` represents a valid `time_point`.
100 * \details If any of the individual components is out of range, the date
101 * doesn't represent an actual `time_point` (e.g. `date(2020, 2, 30)`) or
102 * the date is not in the [\ref min_date, \ref max_date] validity range,
103 * returns `false`. Otherwise, returns `true`.
104 * \par Exception safety
105 * No-throw guarantee.
106 */
107 constexpr bool valid() const noexcept { return detail::is_valid(years: year_, month: month_, day: day_); }
108
109 /**
110 * \brief Converts `*this` into a `time_point` (unchecked access).
111 * \par Preconditions
112 * `this->valid() == true` (if violated, results in undefined behavior).
113 *
114 * \par Exception safety
115 * No-throw guarantee.
116 */
117 BOOST_CXX14_CONSTEXPR time_point get_time_point() const noexcept
118 {
119 BOOST_ASSERT(valid());
120 return unch_get_time_point();
121 }
122
123 /**
124 * \brief Converts `*this` into a `time_point` (checked access).
125 * \par Exception safety
126 * Strong guarantee.
127 * \throws std::invalid_argument If `!this->valid()`.
128 */
129 BOOST_CXX14_CONSTEXPR time_point as_time_point() const
130 {
131 if (!valid())
132 BOOST_THROW_EXCEPTION(std::invalid_argument("date::as_time_point: invalid date"));
133 return unch_get_time_point();
134 }
135
136 /**
137 * \brief Tests for equality.
138 * \details Two dates are considered equal if all of its individual components
139 * are equal. This function works for invalid dates, too.
140 *
141 * \par Exception safety
142 * No-throw guarantee.
143 */
144 constexpr bool operator==(const date& rhs) const noexcept
145 {
146 return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_;
147 }
148
149 /**
150 * \brief Tests for inequality.
151 *
152 * \par Exception safety
153 * No-throw guarantee.
154 */
155 constexpr bool operator!=(const date& rhs) const noexcept { return !(rhs == *this); }
156
157 /**
158 * \brief Returns the current system time as a date object.
159 * \par Exception safety
160 * Strong guarantee. Only throws if obtaining the current time throws.
161 */
162 static date now()
163 {
164 auto now = time_point::clock::now();
165 return date(std::chrono::time_point_cast<time_point::duration>(t: now));
166 }
167
168private:
169 std::uint16_t year_{};
170 std::uint8_t month_{};
171 std::uint8_t day_{};
172
173 BOOST_CXX14_CONSTEXPR time_point unch_get_time_point() const noexcept
174 {
175 return time_point(days(detail::ymd_to_days(years: year_, month: month_, day: day_)));
176 }
177};
178
179/**
180 * \relates date
181 * \brief Streams a date.
182 * \details This function works for invalid dates, too.
183 */
184BOOST_MYSQL_DECL
185std::ostream& operator<<(std::ostream& os, const date& v);
186
187/// The minimum allowed value for \ref date.
188constexpr date min_date{0u, 1u, 1u};
189
190/// The maximum allowed value for \ref date.
191constexpr date max_date{9999u, 12u, 31u};
192
193} // namespace mysql
194} // namespace boost
195
196#ifdef BOOST_MYSQL_HEADER_ONLY
197#include <boost/mysql/impl/date.ipp>
198#endif
199
200#endif
201

source code of boost/libs/mysql/include/boost/mysql/date.hpp