userver: userver/utils/datetime/date.hpp Source File
Loading...
Searching...
No Matches
date.hpp
1#pragma once
2
3/// @file userver/utils/datetime/date.hpp
4/// @brief @copybrief utils::datetime::Date
5
6#include <chrono>
7#include <iosfwd>
8#include <stdexcept>
9#include <string>
10
11#include <userver/formats/common/meta.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace logging {
16class LogHelper;
17}
18
19/// Date and time utilities
20namespace utils::datetime {
21
22/// @ingroup userver_universal userver_containers
23///
24/// @brief Date in format YYYY-MM-DD, std::chrono::year_month_day like type.
25///
26/// Convertible to std::sys_days and could be constructed from year,
27/// month and day integers.
28class Date final {
29public:
30 using Days = std::chrono::duration<long long, std::ratio<86400>>;
31 using SysDays = std::chrono::time_point<std::chrono::system_clock, Days>;
32
33 Date() = default;
34 Date(const Date&) noexcept = default;
35 Date& operator=(const Date&) noexcept = default;
36
37 /// @brief Constructs Date without validation of input arguments
38 Date(int year, int month, int day);
39
40 /// @brief constructor from system clock time point in days.
41 constexpr Date(SysDays tp) noexcept : sys_days_(tp) {}
42
43 /// @brief Returns a time point corresponding to the date.
44 ///
45 /// This function may return the same time point, that was passed to
46 /// constructor.
47 constexpr SysDays GetSysDays() const { return sys_days_; }
48
49 /// @copydoc GetSysDays()
50 constexpr explicit operator SysDays() const { return sys_days_; }
51
52 constexpr bool operator==(Date other) const { return sys_days_ == other.sys_days_; }
53 constexpr bool operator!=(Date other) const { return !(*this == other); }
54
55private:
56 SysDays sys_days_{};
57};
58
59/// Validates date_string and constructs date from YYYY-MM-DD string and
60Date DateFromRFC3339String(const std::string& date_string);
61
62/// Outputs date as a YYYY-MM-DD string
63std::string ToString(Date date);
64
65template <typename Value>
66std::enable_if_t<formats::common::kIsFormatValue<Value>, Date> Parse(const Value& value, formats::parse::To<Date>) {
67 std::string str;
68 try {
69 str = value.template As<std::string>();
70 } catch (const std::exception& e) {
71 throw typename Value::ParseException("Only strings can be parsed as `utils::datetime::Date`");
72 }
73
74 try {
75 return utils::datetime::DateFromRFC3339String(str);
76 } catch (const std::exception& e) {
77 throw typename Value::ParseException("'" + str + "' cannot be parsed to `utils::datetime::Date`");
78 }
79}
80
81template <typename Value>
82std::enable_if_t<formats::common::kIsFormatValue<Value>, Value> Serialize(Date date, formats::serialize::To<Value>) {
83 return typename Value::Builder(ToString(date)).ExtractValue();
84}
85
86template <typename StringBuilder>
87void WriteToStream(Date value, StringBuilder& sw) {
88 WriteToStream(ToString(value), sw);
89}
90
91template <typename LogHelper = USERVER_NAMESPACE::logging::LogHelper>
92USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const Date& date) {
93 static_assert(
94 std::is_same_v<LogHelper, USERVER_NAMESPACE::logging::LogHelper>,
95 "This was made template to work well with forward declared "
96 "logging::LogHelper"
97 );
98 return static_cast<LogHelper&>(lh) << ToString(date);
99}
100
101std::ostream& operator<<(std::ostream& os, Date date);
102
103} // namespace utils::datetime
104
105USERVER_NAMESPACE_END