userver: userver/utils/datetime.hpp Source File
Loading...
Searching...
No Matches
datetime.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/datetime.hpp
4/// @brief Date and Time related converters
5/// @ingroup userver_universal
6
7#include <chrono>
8#include <cstdint>
9#include <optional>
10#include <stdexcept>
11#include <string>
12
13#include <cctz/civil_time.h>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace utils::datetime {
18/// @snippet utils/datetime/from_string_saturating_test.cpp kRfc3339Format
19inline const std::string kRfc3339Format = "%Y-%m-%dT%H:%M:%E*S%Ez";
20/// @snippet utils/datetime/from_string_saturating_test.cpp kTaximeterFormat
21inline const std::string kTaximeterFormat = "%Y-%m-%dT%H:%M:%E6SZ";
22inline constexpr std::time_t kStartOfTheEpoch = 0;
23/// @snippet utils/datetime/datetime_test.cpp kDefaultDriverTimezone
24inline const std::string kDefaultDriverTimezone = "Europe/Moscow";
25/// @snippet utils/datetime/datetime_test.cpp kDefaultTimezone
26inline const std::string kDefaultTimezone = "UTC";
27/// @snippet utils/datetime/from_string_saturating_test.cpp kDefaultFormat
28inline const std::string kDefaultFormat = "%Y-%m-%dT%H:%M:%E*S%z";
29/// @snippet utils/datetime/from_string_saturating_test.cpp kIsoFormat
30inline const std::string kIsoFormat = "%Y-%m-%dT%H:%M:%SZ";
31
32using timepair_t = std::pair<std::uint8_t, std::uint8_t>;
33
34/// Date/time parsing error
35class DateParseError : public std::runtime_error {
36 public:
37 DateParseError(const std::string& timestring);
38};
39
40/// Timezone information lookup error
41class TimezoneLookupError : public std::runtime_error {
42 public:
43 TimezoneLookupError(const std::string& tzname);
44};
45
46/// @brief std::chrono::system_clock::now() that could be mocked
47///
48/// Returns last time point passed to utils::datetime::MockNowSet(), or
49/// std::chrono::system_clock::now() if the timepoint is not mocked.
50std::chrono::system_clock::time_point Now() noexcept;
51
52/// @brief Returns std::chrono::system_clock::time_point from the start of the
53/// epoch
54std::chrono::system_clock::time_point Epoch() noexcept;
55
56/// @brief std::chrono::steady_clock::now() that could be mocked
57///
58/// Returns last time point passed to utils::datetime::MockNowSet(), or
59/// std::chrono::steady_clock::now() if the timepoint is not mocked.
60///
61/// It is only intended for period-based structures/algorithms testing.
62///
63/// @warning You MUST NOT pass time points received from this function outside
64/// of your own code. Otherwise this will break your service in production.
65std::chrono::steady_clock::time_point SteadyNow() noexcept;
66
67// See the comment to SteadyNow()
68class SteadyClock : public std::chrono::steady_clock {
69 public:
70 using time_point = std::chrono::steady_clock::time_point;
71
72 static time_point now() { return SteadyNow(); }
73};
74
75/// @brief Returns true if the time is in range; works over midnight too
76bool IsTimeBetween(int hour, int min, int hour_from, int min_from, int hour_to,
77 int min_to, bool include_time_to = false) noexcept;
78
79/// @brief Returns time in a string of specified format
80///
81/// @throws utils::datetime::TimezoneLookupError
82///
83/// Example:
84///
85/// @snippet utils/datetime/datetime_test.cpp Timestring C time example
86///
87/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
88/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
89std::string Timestring(std::time_t timestamp,
90 const std::string& timezone = kDefaultTimezone,
91 const std::string& format = kDefaultFormat);
92
93/// @brief Returns time in a string of specified format
94/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
95/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
96std::string LocalTimezoneTimestring(std::time_t timestamp,
97 const std::string& format = kDefaultFormat);
98
99/// @brief Returns time in a string of specified format
100/// @throws utils::datetime::TimezoneLookupError
101///
102/// Example:
103///
104/// @snippet utils/datetime/datetime_test.cpp Timestring example
105/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
106/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
107std::string Timestring(std::chrono::system_clock::time_point tp,
108 const std::string& timezone = kDefaultTimezone,
109 const std::string& format = kDefaultFormat);
110
111/// @brief Returns time in a string of specified format
112/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
113/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
114std::string LocalTimezoneTimestring(std::chrono::system_clock::time_point tp,
115 const std::string& format = kDefaultFormat);
116
117/// @brief Extracts time point from a string of a specified format
118/// @throws utils::datetime::DateParseError
119/// @throws utils::datetime::TimezoneLookupError
120///
121/// Example:
122///
123/// @snippet utils/datetime/datetime_test.cpp Stringtime example
124/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
125/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
126std::chrono::system_clock::time_point Stringtime(
127 const std::string& timestring,
128 const std::string& timezone = kDefaultTimezone,
129 const std::string& format = kDefaultFormat);
130
131/// @brief Extracts time point from a string of a specified format
132/// @throws utils::datetime::DateParseError
133/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
134/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
135std::chrono::system_clock::time_point LocalTimezoneStringtime(
136 const std::string& timestring, const std::string& format = kDefaultFormat);
137
138/// @brief Extracts time point from a string, guessing the format
139/// @throws utils::datetime::DateParseError
140/// @throws utils::datetime::TimezoneLookupError
141///
142/// Example:
143///
144/// @snippet utils/datetime/datetime_test.cpp GuessStringtime example
145std::chrono::system_clock::time_point GuessStringtime(
146 const std::string& timestamp, const std::string& timezone);
147
148/// @brief Extracts time point from a string, guessing the format
149/// @throws utils::datetime::DateParseError
150std::chrono::system_clock::time_point GuessLocalTimezoneStringtime(
151 const std::string& timestamp);
152
153/// @brief Returns optional time in a string of specified format
154///
155/// Example:
156///
157/// @snippet utils/datetime/datetime_test.cpp OptionalStringtime example
158/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
159/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
160std::optional<std::chrono::system_clock::time_point> OptionalStringtime(
161 const std::string& timestring,
162 const std::string& timezone = kDefaultTimezone,
163 const std::string& format = kDefaultFormat);
164
165/// @brief Converts time point to std::time_t
166///
167/// Example:
168///
169/// @snippet utils/datetime/datetime_test.cpp Timestring C time example
170std::time_t Timestamp(std::chrono::system_clock::time_point tp) noexcept;
171
172/// @brief Returned current time as std::time_t; could be mocked
173std::time_t Timestamp() noexcept;
174
175/// @brief Parse day time in hh:mm[:ss] format
176/// @param str day time in format hh:mm[:ss]
177/// @return number of second since start of day
178std::uint32_t ParseDayTime(const std::string& str);
179
180/// @brief Converts absolute time in std::chrono::system_clock::time_point to
181/// a civil time of a particular timezone.
182/// @throws utils::datetime::TimezoneLookupError
183///
184/// Example:
185///
186/// @snippet utils/datetime/datetime_test.cpp Localize example
187cctz::civil_second Localize(const std::chrono::system_clock::time_point& tp,
188 const std::string& timezone);
189
190/// @brief Converts absolute time in std::chrono::system_clock::time_point to
191/// a civil time of a local timezone.
192cctz::civil_second LocalTimezoneLocalize(
193 const std::chrono::system_clock::time_point& tp);
194
195/// @brief Converts a civil time in a specified timezone into an absolute time.
196/// @throws utils::datetime::TimezoneLookupError
197///
198/// Example:
199///
200/// @snippet utils/datetime/datetime_test.cpp Localize example
201std::time_t Unlocalize(const cctz::civil_second& local_tp,
202 const std::string& timezone);
203
204/// @brief Converts a civil time in a local timezone into an absolute time.
205std::time_t LocalTimezoneUnlocalize(const cctz::civil_second& local_tp);
206
207/// @brief Returns string with time in ISO8601 format "YYYY-MM-DDTHH:MM:SS+0000"
208/// @param timestamp unix timestamp
209std::string TimestampToString(std::time_t timestamp);
210
211/// @brief Convert time_point to DotNet ticks
212/// @param time point day time
213/// @return number of 100nanosec intervals between current date and 01/01/0001
214///
215/// Example:
216///
217/// @snippet utils/datetime/datetime_test.cpp TimePointToTicks example
218std::int64_t TimePointToTicks(
219 const std::chrono::system_clock::time_point& tp) noexcept;
220
221/// @brief Convert DotNet ticks to a time point
222std::chrono::system_clock::time_point TicksToTimePoint(
223 std::int64_t ticks) noexcept;
224
225/// @brief Compute (a - b) with a specified duration
226template <class Duration, class Clock>
227double CalcTimeDiff(const std::chrono::time_point<Clock>& a,
228 const std::chrono::time_point<Clock>& b) {
229 const auto duration_a = a.time_since_epoch();
230 const auto duration_b = b.time_since_epoch();
231 return std::chrono::duration_cast<Duration>(duration_a - duration_b).count();
232}
233
234} // namespace utils::datetime
235
236USERVER_NAMESPACE_END