-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathdatetime.cpp
180 lines (141 loc) · 4.38 KB
/
datetime.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (c) 2018, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <locale>
#include "datetime.hpp"
#include "vendor/date/date.h"
#include "vendor/nlohmann/json.hpp"
using json = nlohmann::json;
using namespace std;
namespace psicash {
namespace datetime {
static const TimePoint kTimePointZero = TimePoint();
static constexpr const char* ISO8601_FORMAT_STRING = "%FT%TZ";
static constexpr const char* ISO8601_PARSE_STRING = "%FT%T%Z";
// NOTE: Limited to GMT
static constexpr const char* RFC7231_PARSE_STRING = "%a, %d %b %Y %T %Z"; // Wed, 03 Oct 2018 18:41:43 GMT
#ifdef _MSC_VER
#define timegm _mkgmtime
#endif
// TimePoints with different duration resolutions won't compare in an expected way, and can make
// testing and reasoning difficult. We'll make sure that all TimePoints that we produce use the
// same Duration.
datetime::TimePoint NormalizeTimePoint(const datetime::Clock::time_point& tp) {
return chrono::time_point_cast<datetime::Duration>(tp);
}
bool FromString(const char* parseSpecifier, const string& s, TimePoint& tp) {
if (s.empty()) {
return false;
}
TimePoint temp;
istringstream ss(s);
ss.imbue(std::locale::classic());
ss >> date::parse(parseSpecifier, temp);
if (ss.fail()) {
// Parse failed.
return false;
}
tp = temp;
return true;
}
DateTime::DateTime()
: DateTime(kTimePointZero) {
}
DateTime::DateTime(const DateTime& src)
: DateTime(src.time_point_) {
}
DateTime::DateTime(const TimePoint& src)
: time_point_(src) {
}
DateTime DateTime::Zero() {
return DateTime(kTimePointZero);
}
DateTime DateTime::Now() {
return DateTime(NormalizeTimePoint(Clock::now()));
}
bool DateTime::IsZero() const {
// This makes the assumption that we won't be dealing with 1970-01-01 as a legit date.
//return time_point_.time_since_epoch().count() == 0;
return time_point_ == kTimePointZero;
}
string DateTime::ToString() const {
return ToISO8601();
}
string DateTime::ToISO8601() const {
ostringstream ss;
ss.imbue(std::locale::classic());
ss << date::format(ISO8601_FORMAT_STRING, time_point_);
return ss.str();
}
bool DateTime::FromISO8601(const string& s) {
TimePoint temp;
if (!FromString(ISO8601_PARSE_STRING, s, temp)) {
return false;
}
time_point_ = NormalizeTimePoint(temp);
return true;
}
bool DateTime::FromRFC7231(const string& s) {
TimePoint temp;
if (!FromString(RFC7231_PARSE_STRING, s, temp)) {
return false;
}
time_point_ = NormalizeTimePoint(temp);
return true;
}
Duration DateTime::Diff(const DateTime& other) const {
auto d = time_point_ - other.time_point_;
return chrono::duration_cast<Duration>(d);
}
DateTime DateTime::Add(const Duration& d) const {
return DateTime(NormalizeTimePoint(time_point_ + d));
}
DateTime DateTime::Sub(const Duration& d) const {
return DateTime(NormalizeTimePoint(time_point_ - d));
}
int64_t DateTime::MillisSinceEpoch() const {
return time_point_.time_since_epoch().count();
}
bool DateTime::operator<(const DateTime& rhs) const {
return time_point_ < rhs.time_point_;
}
bool DateTime::operator>(const DateTime& rhs) const {
return time_point_ > rhs.time_point_;
}
bool operator==(const DateTime& lhs, const DateTime& rhs) {
return lhs.time_point_ == rhs.time_point_;
}
void to_json(json& j, const DateTime& dt) {
j = dt.ToISO8601();
}
void from_json(const json& j, DateTime& dt) {
dt.FromISO8601(j.get<string>());
}
int64_t DurationToInt64(const Duration& d) {
return d.count();
}
Duration DurationFromInt64(int64_t d) {
return Duration(d);
}
} // namespace datetime
} // namespace psicash