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