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 {
36public:
37 DateParseError(const std::string& timestring);
38};
39
40/// Timezone information lookup error
41class TimezoneLookupError : public std::runtime_error {
42public:
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 {
69public:
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
77 int hour,
78 int min,
79 int hour_from,
80 int min_from,
81 int hour_to,
82 int min_to,
83 bool include_time_to = false
84) noexcept;
85
86/// @brief Returns time in a string of specified format
87///
88/// @throws utils::datetime::TimezoneLookupError
89///
90/// Example:
91///
92/// @snippet utils/datetime/datetime_test.cpp Timestring C time example
93///
94/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
95/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
96std::string Timestring(
97 std::time_t timestamp,
98 const std::string& timezone = kDefaultTimezone,
99 const std::string& format = kDefaultFormat
100);
101
102/// @brief Returns time in a string of specified format
103/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
104/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
105std::string LocalTimezoneTimestring(std::time_t timestamp, const std::string& format = kDefaultFormat);
106
107/// @brief Returns time in a string of specified format
108/// @throws utils::datetime::TimezoneLookupError
109///
110/// Example:
111///
112/// @snippet utils/datetime/datetime_test.cpp Timestring example
113/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
114/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
115std::string Timestring(
116 std::chrono::system_clock::time_point tp,
117 const std::string& timezone = kDefaultTimezone,
118 const std::string& format = kDefaultFormat
119);
120
121/// @brief Returns time in a string of specified format
122/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
123/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
124std::string
125LocalTimezoneTimestring(std::chrono::system_clock::time_point tp, const std::string& format = kDefaultFormat);
126
127/// @brief Extracts time point from a string of a specified format
128/// @throws utils::datetime::DateParseError
129/// @throws utils::datetime::TimezoneLookupError
130///
131/// Example:
132///
133/// @snippet utils/datetime/datetime_test.cpp Stringtime example
134/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
135/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
136std::chrono::system_clock::time_point Stringtime(
137 const std::string& timestring,
138 const std::string& timezone = kDefaultTimezone,
139 const std::string& format = kDefaultFormat
140);
141
142/// @brief Extracts time point from a string of a specified format
143/// @throws utils::datetime::DateParseError
144/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
145/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
146std::chrono::system_clock::time_point
147LocalTimezoneStringtime(const std::string& timestring, const std::string& format = kDefaultFormat);
148
149/// @brief Extracts time point from a string, guessing the format
150/// @throws utils::datetime::DateParseError
151/// @throws utils::datetime::TimezoneLookupError
152///
153/// Example:
154///
155/// @snippet utils/datetime/datetime_test.cpp GuessStringtime example
156std::chrono::system_clock::time_point GuessStringtime(const std::string& timestamp, const std::string& timezone);
157
158/// @brief Extracts time point from a string, guessing the format
159/// @throws utils::datetime::DateParseError
160std::chrono::system_clock::time_point GuessLocalTimezoneStringtime(const std::string& timestamp);
161
162/// @brief Returns optional time in a string of specified format
163///
164/// Example:
165///
166/// @snippet utils/datetime/datetime_test.cpp OptionalStringtime example
167/// @see kRfc3339Format, kTaximeterFormat, kStartOfTheEpoch,
168/// kDefaultDriverTimezone, kDefaultTimezone, kDefaultFormat, kIsoFormat
169std::optional<std::chrono::system_clock::time_point> OptionalStringtime(
170 const std::string& timestring,
171 const std::string& timezone = kDefaultTimezone,
172 const std::string& format = kDefaultFormat
173);
174
175/// @brief Converts time point to std::time_t
176///
177/// Example:
178///
179/// @snippet utils/datetime/datetime_test.cpp Timestring C time example
180std::time_t Timestamp(std::chrono::system_clock::time_point tp) noexcept;
181
182/// @brief Returned current time as std::time_t; could be mocked
183std::time_t Timestamp() noexcept;
184
185/// @brief Parse day time in hh:mm[:ss] format
186/// @param str day time in format hh:mm[:ss]
187/// @return number of second since start of day
188std::uint32_t ParseDayTime(const std::string& str);
189
190/// @brief Converts absolute time in std::chrono::system_clock::time_point to
191/// a civil time of a particular timezone.
192/// @throws utils::datetime::TimezoneLookupError
193///
194/// Example:
195///
196/// @snippet utils/datetime/datetime_test.cpp Localize example
197cctz::civil_second Localize(const std::chrono::system_clock::time_point& tp, const std::string& timezone);
198
199/// @brief Converts absolute time in std::chrono::system_clock::time_point to
200/// a civil time of a local timezone.
201cctz::civil_second LocalTimezoneLocalize(const std::chrono::system_clock::time_point& tp);
202
203/// @brief Converts a civil time in a specified timezone into an absolute time.
204/// @throws utils::datetime::TimezoneLookupError
205///
206/// Example:
207///
208/// @snippet utils/datetime/datetime_test.cpp Localize example
209std::time_t Unlocalize(const cctz::civil_second& local_tp, const std::string& timezone);
210
211/// @brief Converts a civil time in a local timezone into an absolute time.
212std::time_t LocalTimezoneUnlocalize(const cctz::civil_second& local_tp);
213
214/// @brief Returns string with time in ISO8601 format "YYYY-MM-DDTHH:MM:SS+0000"
215/// @param timestamp unix timestamp
216std::string TimestampToString(std::time_t timestamp);
217
218/// @brief Convert time_point to DotNet ticks
219/// @param time point day time
220/// @return number of 100nanosec intervals between current date and 01/01/0001
221///
222/// Example:
223///
224/// @snippet utils/datetime/datetime_test.cpp TimePointToTicks example
225std::int64_t TimePointToTicks(const std::chrono::system_clock::time_point& tp) noexcept;
226
227/// @brief Convert DotNet ticks to a time point
228std::chrono::system_clock::time_point TicksToTimePoint(std::int64_t ticks) noexcept;
229
230/// @brief Compute (a - b) with a specified duration
231template <class Duration, class Clock>
232double CalcTimeDiff(const std::chrono::time_point<Clock>& a, const std::chrono::time_point<Clock>& b) {
233 const auto duration_a = a.time_since_epoch();
234 const auto duration_b = b.time_since_epoch();
235 return std::chrono::duration_cast<Duration>(duration_a - duration_b).count();
236}
237
238} // namespace utils::datetime
239
240USERVER_NAMESPACE_END