Github   Telegram
Loading...
Searching...
No Matches
chrono.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <chrono>
8#include <limits>
9
11#include <userver/storages/postgres/io/buffer_io_base.hpp>
13#include <userver/storages/postgres/io/transform_io.hpp>
14#include <userver/storages/postgres/io/type_mapping.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace storages::postgres {
20
21using ClockType = std::chrono::system_clock;
22
25using TimePoint = ClockType::time_point;
26
29using TimePointTz = USERVER_NAMESPACE::utils::StrongTypedef<
30 struct TimestampWithTz, TimePoint,
32using IntervalType = std::chrono::microseconds;
33
36
40inline constexpr TimePoint kTimestampPositiveInfinity = TimePoint::max();
44inline constexpr TimePoint kTimestampNegativeInfinity = TimePoint::min();
45
86namespace io {
87
89template <typename Duration>
90struct BufferFormatter<std::chrono::time_point<ClockType, Duration>> {
91 using ValueType = std::chrono::time_point<ClockType, Duration>;
92
93 const ValueType value;
94
95 explicit BufferFormatter(ValueType val) : value{val} {}
96
97 template <typename Buffer>
98 void operator()(const UserTypes& types, Buffer& buf) const {
99 static const ValueType pg_epoch =
100 std::chrono::time_point_cast<Duration>(PostgresEpochTimePoint());
101 if (value == kTimestampPositiveInfinity) {
102 WriteBuffer(types, buf, std::numeric_limits<Bigint>::max());
103 } else if (value == kTimestampNegativeInfinity) {
104 WriteBuffer(types, buf, std::numeric_limits<Bigint>::min());
105 } else {
106 auto tmp = std::chrono::duration_cast<std::chrono::microseconds>(value -
107 pg_epoch)
108 .count();
109 WriteBuffer(types, buf, tmp);
110 }
111 }
112};
113
115template <typename Duration>
116struct BufferParser<std::chrono::time_point<ClockType, Duration>>
117 : detail::BufferParserBase<std::chrono::time_point<ClockType, Duration>> {
118 using BaseType =
119 detail::BufferParserBase<std::chrono::time_point<ClockType, Duration>>;
120 using ValueType = typename BaseType::ValueType;
121 using BaseType::BaseType;
122
123 void operator()(const FieldBuffer& buffer) {
124 static const ValueType pg_epoch =
125 std::chrono::time_point_cast<Duration>(PostgresEpochTimePoint());
126 Bigint usec{0};
127 ReadBuffer(buffer, usec);
128 if (usec == std::numeric_limits<Bigint>::max()) {
129 this->value = kTimestampPositiveInfinity;
130 } else if (usec == std::numeric_limits<Bigint>::min()) {
131 this->value = kTimestampNegativeInfinity;
132 } else {
133 ValueType tmp = pg_epoch + std::chrono::microseconds{usec};
134 std::swap(tmp, this->value);
135 }
136 }
137};
138
139namespace detail {
140
141template <typename Rep, typename Period>
142struct DurationIntervalCvt {
143 using UserType = std::chrono::duration<Rep, Period>;
144 UserType operator()(const Interval& wire_val) const {
145 return std::chrono::duration_cast<UserType>(wire_val.GetDuration());
146 }
147 Interval operator()(const UserType& user_val) const {
148 return Interval{std::chrono::duration_cast<IntervalType>(user_val)};
149 }
150};
151
152} // namespace detail
153
154namespace traits {
155
157template <typename Rep, typename Period>
158struct Output<std::chrono::duration<Rep, Period>> {
160 io::detail::Interval,
161 io::detail::DurationIntervalCvt<Rep, Period>>;
162};
163
165template <typename Rep, typename Period>
166struct Input<std::chrono::duration<Rep, Period>> {
167 using type =
169 io::detail::DurationIntervalCvt<Rep, Period>>;
170};
171
172} // namespace traits
173
174template <>
176 : PredefinedOid<PredefinedOids::kTimestamptz> {};
177
178template <typename Duration>
179struct CppToSystemPg<std::chrono::time_point<ClockType, Duration>>
180 : PredefinedOid<PredefinedOids::kTimestamp> {};
181
182template <typename Rep, typename Period>
183struct CppToSystemPg<std::chrono::duration<Rep, Period>>
184 : PredefinedOid<PredefinedOids::kInterval> {};
185
186} // namespace io
187} // namespace storages::postgres
188
189USERVER_NAMESPACE_END