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 {
29 public:
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 {
53 return sys_days_ == other.sys_days_;
54 }
55 constexpr bool operator!=(Date other) const { return !(*this == other); }
56
57 private:
58 SysDays sys_days_{};
59};
60
61/// Validates date_string and constructs date from YYYY-MM-DD string and
62Date DateFromRFC3339String(const std::string& date_string);
63
64/// Outputs date as a YYYY-MM-DD string
65std::string ToString(Date date);
66
67template <typename Value>
68std::enable_if_t<formats::common::kIsFormatValue<Value>, Date> Parse(
69 const Value& value, formats::parse::To<Date>) {
70 std::string str;
71 try {
72 str = value.template As<std::string>();
73 } catch (const std::exception& e) {
74 throw typename Value::ParseException(
75 "Only strings can be parsed as `utils::datetime::Date`");
76 }
77
78 try {
79 return utils::datetime::DateFromRFC3339String(str);
80 } catch (const std::exception& e) {
81 throw typename Value::ParseException(
82 "'" + str + "' cannot be parsed to `utils::datetime::Date`");
83 }
84}
85
86template <typename Value>
87std::enable_if_t<formats::common::kIsFormatValue<Value>, Value> Serialize(
88 Date date, formats::serialize::To<Value>) {
89 return typename Value::Builder(ToString(date)).ExtractValue();
90}
91
92template <typename StringBuilder>
93void WriteToStream(Date value, StringBuilder& sw) {
94 WriteToStream(ToString(value), sw);
95}
96
97template <typename LogHelper = USERVER_NAMESPACE::logging::LogHelper>
98USERVER_NAMESPACE::logging::LogHelper& operator<<(
99 USERVER_NAMESPACE::logging::LogHelper& lh, const Date& date) {
100 static_assert(
101 std::is_same_v<LogHelper, USERVER_NAMESPACE::logging::LogHelper>,
102 "This was made template to work well with forward declared "
103 "logging::LogHelper");
104 return static_cast<LogHelper&>(lh) << ToString(date);
105}
106
107std::ostream& operator<<(std::ostream& os, Date date);
108
109} // namespace utils::datetime
110
111USERVER_NAMESPACE_END