userver: /data/code/userver/libraries/proto-structs/src/proto-structs/io/std/chrono/time_point.cpp Source File
Loading...
Searching...
No Matches
time_point.cpp
1#include <userver/proto-structs/io/std/chrono/time_point.hpp>
2
3#include <google/protobuf/timestamp.pb.h>
4#include <google/protobuf/util/time_util.h>
5
6#include <userver/proto-structs/io/context.hpp>
7#include <userver/utils/assert.hpp>
8
9namespace proto_structs::io {
10
11std::chrono::time_point<std::chrono::system_clock> ReadProtoStruct(
12 ReadContext& ctx,
13 To<std::chrono::time_point<std::chrono::system_clock>>,
14 const ::google::protobuf::Timestamp& msg
15) {
16 using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
17 constexpr std::int64_t kMaxSecondsInTimePoint =
18 std::chrono::duration_cast<std::chrono::seconds>(TimePoint::duration::max()).count();
19 constexpr std::int64_t kMinSecondsInTimePoint =
20 std::chrono::duration_cast<std::chrono::seconds>(TimePoint::duration::min()).count();
21
22 TimePoint result;
23
24 if (::google::protobuf::util::TimeUtil::IsTimestampValid(msg)) {
25 if (msg.seconds() > kMaxSecondsInTimePoint - 1) {
26 result = TimePoint::max();
27 } else if (msg.seconds() < kMinSecondsInTimePoint) {
28 result = TimePoint::min();
29 } else {
30 result = TimePoint{std::chrono::duration_cast<TimePoint::duration>(
31 std::chrono::seconds(msg.seconds()) + std::chrono::nanoseconds(msg.nanos())
32 )};
33 }
34 } else {
35 ctx.AddError("invalid 'google.protobuf.Timestamp' value");
36 }
37
38 return result;
39}
40
41void WriteProtoStruct(
42 WriteContext&,
43 const std::chrono::time_point<std::chrono::system_clock>& obj,
44 ::google::protobuf::Timestamp& msg
45) {
46 using TimeUtil = ::google::protobuf::util::TimeUtil;
47 const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(obj.time_since_epoch());
48 const std::chrono::nanoseconds nanos = obj.time_since_epoch() - seconds;
49
50 if (seconds.count() > TimeUtil::kTimestampMaxSeconds) {
51 msg.set_seconds(TimeUtil::kTimestampMaxSeconds);
52 msg.set_nanos(0);
53 } else if (seconds.count() < TimeUtil::kTimestampMinSeconds) {
54 msg.set_seconds(TimeUtil::kTimestampMinSeconds);
55 msg.set_nanos(0);
56 } else if (nanos.count() >= 0) {
57 msg.set_seconds(seconds.count());
58 msg.set_nanos(nanos.count());
59 } else {
60 // Timestamp.nanos should be from [0, 999'999'999]
61 msg.set_seconds(seconds.count() - 1);
62 msg.set_nanos(nanos.count() + 1'000'000'000);
63 }
64
65 UASSERT(TimeUtil::IsTimestampValid(msg));
66}
67
68} // namespace proto_structs::io