Libosmium: include/osmium/osm/timestamp.hpp Source File

Libosmium Fast and flexible C++ library for working with OpenStreetMap data

Loading...
Searching...
No Matches
timestamp.hpp
Go to the documentation of this file.
1#ifndef OSMIUM_OSM_TIMESTAMP_HPP
2#define OSMIUM_OSM_TIMESTAMP_HPP
3
4/*
5
6This file is part of Osmium (https://osmcode.org/libosmium).
7
8Copyright 2013-2026 Jochen Topf <jochen@topf.org> and others (see README).
9
10Boost Software License - Version 1.0 - August 17th, 2003
11
12Permission is hereby granted, free of charge, to any person or organization
13obtaining a copy of the software and accompanying documentation covered by
14this license (the "Software") to use, reproduce, display, distribute,
15execute, and transmit the Software, and to prepare derivative works of the
16Software, and to permit third-parties to whom the Software is furnished to
17do so, all subject to the following:
18
19The copyright notices in the Software and this entire statement, including
20the above license grant, this restriction and the following disclaimer,
21must be included in all copies of the Software, in whole or in part, and
22all derivative works of the Software, unless such copies or derivative
23works are solely in the form of machine-executable object code generated by
24a source language processor.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32DEALINGS IN THE SOFTWARE.
33
34*/
35
36#include <osmium/util/minmax.hpp> // IWYU pragma: keep
37
38#include <array>
39#include <cassert>
40#include <cstdint>
41#include <ctime>
42#include <iosfwd>
43#include <limits>
44#include <stdexcept>
45#include <string>
46#include <type_traits>
47
48namespace osmium {
49
50 namespace detail {
51
52 inline void add_2digit_int_to_string(int value, std::string& out) {
53 assert(value >= 0 && value <= 99);
54 if (value > 9) {
55 const int dec = value / 10;
56 out += static_cast<char>('0' + dec);
57 value -= dec * 10;
58 } else {
59 out += '0';
60 }
61 out += static_cast<char>('0' + value);
62 }
63
64 inline void add_4digit_int_to_string(int value, std::string& out) {
65 assert(value >= 1000 && value <= 9999);
66
67 const int dec1 = value / 1000;
68 out += static_cast<char>('0' + dec1);
69 value -= dec1 * 1000;
70
71 const int dec2 = value / 100;
72 out += static_cast<char>('0' + dec2);
73 value -= dec2 * 100;
74
75 const int dec3 = value / 10;
76 out += static_cast<char>('0' + dec3);
77 value -= dec3 * 10;
78
79 out += static_cast<char>('0' + value);
80 }
81
82 inline bool fractional_seconds(const char** s) noexcept {
83 const char* str = *s;
84
85 if (*str != '.' && *str != ',') {
86 return false;
87 }
88
89 ++str;
90 if (*str < '0' || *str > '9') {
91 return false;
92 }
93
94 do {
95 ++str;
96 } while (*str >= '0' && *str <= '9');
97
98 *s = str;
99 return *str == 'Z';
100 }
101
102 inline std::time_t parse_timestamp(const char** s) {
103 const char* str = *s;
104 *s += 19;
105
106 static const std::array<int, 12> mon_lengths = {{
107 31, 29, 31, 30, 31, 30,
108 31, 31, 30, 31, 30, 31
109 }};
110
111 if (str[ 0] >= '0' && str[ 0] <= '9' &&
112 str[ 1] >= '0' && str[ 1] <= '9' &&
113 str[ 2] >= '0' && str[ 2] <= '9' &&
114 str[ 3] >= '0' && str[ 3] <= '9' &&
115 str[ 4] == '-' &&
116 str[ 5] >= '0' && str[ 5] <= '9' &&
117 str[ 6] >= '0' && str[ 6] <= '9' &&
118 str[ 7] == '-' &&
119 str[ 8] >= '0' && str[ 8] <= '9' &&
120 str[ 9] >= '0' && str[ 9] <= '9' &&
121 str[10] == 'T' &&
122 str[11] >= '0' && str[11] <= '9' &&
123 str[12] >= '0' && str[12] <= '9' &&
124 str[13] == ':' &&
125 str[14] >= '0' && str[14] <= '9' &&
126 str[15] >= '0' && str[15] <= '9' &&
127 str[16] == ':' &&
128 str[17] >= '0' && str[17] <= '9' &&
129 str[18] >= '0' && str[18] <= '9' &&
130 (str[19] == 'Z' || fractional_seconds(s))) {
131 ++(*s);
132 std::tm tm; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
133 tm.tm_year = (str[ 0] - '0') * 1000 +
134 (str[ 1] - '0') * 100 +
135 (str[ 2] - '0') * 10 +
136 (str[ 3] - '0') - 1900;
137 tm.tm_mon = (str[ 5] - '0') * 10 + (str[ 6] - '0') - 1;
138 tm.tm_mday = (str[ 8] - '0') * 10 + (str[ 9] - '0');
139 tm.tm_hour = (str[11] - '0') * 10 + (str[12] - '0');
140 tm.tm_min = (str[14] - '0') * 10 + (str[15] - '0');
141 tm.tm_sec = (str[17] - '0') * 10 + (str[18] - '0');
142 tm.tm_wday = 0;
143 tm.tm_yday = 0;
144 tm.tm_isdst = 0;
145 if (tm.tm_year >= 0 &&
146 tm.tm_mon >= 0 && tm.tm_mon <= 11 &&
147 tm.tm_mday >= 1 && tm.tm_mday <= mon_lengths[tm.tm_mon] &&
148 tm.tm_hour >= 0 && tm.tm_hour <= 23 &&
149 tm.tm_min >= 0 && tm.tm_min <= 59 &&
150 tm.tm_sec >= 0 && tm.tm_sec <= 60) {
151#ifndef _WIN32
152 return timegm(&tm);
153#else
154 return _mkgmtime(&tm);
155#endif
156 }
157 }
158 throw std::invalid_argument{std::string{"can not parse timestamp: '"} + str + "'"};
159 }
160
161 inline std::time_t parse_timestamp(const char* s) {
162 const char** str = &s;
163 return parse_timestamp(str);
164 }
165
166 } // namespace detail
167
175 class Timestamp {
176
177 uint32_t m_timestamp = 0;
178
179 void to_iso_str(std::string& s) const {
180 std::tm tm; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
181 const std::time_t sse = seconds_since_epoch();
182#ifndef NDEBUG
183 auto result =
184#endif
185#ifndef _WIN32
186 gmtime_r(&sse, &tm);
187 assert(result != nullptr);
188#else
189 gmtime_s(&tm, &sse);
190 assert(result == 0);
191#endif
192
193 detail::add_4digit_int_to_string(tm.tm_year + 1900, s);
194 s += '-';
195 detail::add_2digit_int_to_string(tm.tm_mon + 1, s);
196 s += '-';
197 detail::add_2digit_int_to_string(tm.tm_mday, s);
198 s += 'T';
199 detail::add_2digit_int_to_string(tm.tm_hour, s);
200 s += ':';
201 detail::add_2digit_int_to_string(tm.tm_min, s);
202 s += ':';
203 detail::add_2digit_int_to_string(tm.tm_sec, s);
204 s += 'Z';
205 }
206
207 public:
208
212 constexpr Timestamp() noexcept = default;
213
223 template <typename T, typename std::enable_if_t<std::is_integral<T>::value, int> = 0>
224 constexpr Timestamp(T timestamp) noexcept : // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
225 m_timestamp(static_cast<uint32_t>(timestamp)) {
226 }
227
234 explicit Timestamp(const char* timestamp) :
235 m_timestamp(static_cast<uint32_t>(detail::parse_timestamp(timestamp))) {
236 }
237
244 explicit Timestamp(const std::string& timestamp) :
245 Timestamp(timestamp.c_str()) {
246 }
247
252 bool valid() const noexcept {
253 return m_timestamp != 0;
254 }
255
257 explicit constexpr operator bool() const noexcept {
258 return m_timestamp != 0;
259 }
260
262 constexpr std::time_t seconds_since_epoch() const noexcept {
263 return static_cast<std::time_t>(m_timestamp);
264 }
265
267 explicit constexpr operator uint32_t() const noexcept {
268 return m_timestamp;
269 }
270
272 explicit constexpr operator uint64_t() const noexcept {
273 return static_cast<uint64_t>(m_timestamp);
274 }
275
276 template <typename T>
277 void operator+=(T time_difference) noexcept {
278 m_timestamp += time_difference;
279 }
280
281 template <typename T>
282 void operator-=(T time_difference) noexcept {
283 m_timestamp -= time_difference;
284 }
285
291 std::string to_iso() const {
292 std::string s;
293
294 if (m_timestamp != 0) {
295 to_iso_str(s);
296 }
297
298 return s;
299 }
300
306 std::string to_iso_all() const {
307 std::string s;
308
309 to_iso_str(s);
310
311 return s;
312 }
313
314 }; // class Timestamp
315
320 constexpr Timestamp start_of_time() noexcept {
321 return {1};
322 }
323
328 constexpr Timestamp end_of_time() noexcept {
329 return {std::numeric_limits<uint32_t>::max()};
330 }
331
332 template <typename TChar, typename TTraits>
333 inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, Timestamp timestamp) {
334 out << timestamp.to_iso();
335 return out;
336 }
337
338 inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) noexcept {
339 return static_cast<uint32_t>(lhs) == static_cast<uint32_t>(rhs);
340 }
341
342 inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
343 return !(lhs == rhs);
344 }
345
346 inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) noexcept {
347 return static_cast<uint32_t>(lhs) < static_cast<uint32_t>(rhs);
348 }
349
350 inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) noexcept {
351 return rhs < lhs;
352 }
353
354 inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
355 return !(rhs < lhs);
356 }
357
358 inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
359 return !(lhs < rhs);
360 }
361
362 template <>
363 inline osmium::Timestamp min_op_start_value<osmium::Timestamp>() {
364 return end_of_time();
365 }
366
367 template <>
368 inline osmium::Timestamp max_op_start_value<osmium::Timestamp>() {
369 return start_of_time();
370 }
371
372} // namespace osmium
373
374#endif // OSMIUM_OSM_TIMESTAMP_HPP
osmium::Timestamp
Definition timestamp.hpp:175
osmium::Timestamp::to_iso_str
void to_iso_str(std::string &s) const
Definition timestamp.hpp:179
osmium::Timestamp::to_iso
std::string to_iso() const
Definition timestamp.hpp:291
osmium::Timestamp::Timestamp
Timestamp(const std::string &timestamp)
Definition timestamp.hpp:244
osmium::Timestamp::Timestamp
constexpr Timestamp() noexcept=default
osmium::Timestamp::m_timestamp
uint32_t m_timestamp
Definition timestamp.hpp:177
osmium::Timestamp::valid
bool valid() const noexcept
Definition timestamp.hpp:252
osmium::Timestamp::seconds_since_epoch
constexpr std::time_t seconds_since_epoch() const noexcept
Explicit conversion into time_t.
Definition timestamp.hpp:262
osmium::Timestamp::operator+=
void operator+=(T time_difference) noexcept
Definition timestamp.hpp:277
osmium::Timestamp::operator-=
void operator-=(T time_difference) noexcept
Definition timestamp.hpp:282
osmium::Timestamp::Timestamp
Timestamp(const char *timestamp)
Definition timestamp.hpp:234
osmium::Timestamp::to_iso_all
std::string to_iso_all() const
Definition timestamp.hpp:306
minmax.hpp
detail
Definition attr.hpp:342
osmium
Namespace for everything in the Osmium library.
Definition assembler.hpp:53
osmium::end_of_time
constexpr Timestamp end_of_time() noexcept
Definition timestamp.hpp:328
osmium::operator==
bool operator==(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:440
osmium::max_op_start_value< osmium::Timestamp >
osmium::Timestamp max_op_start_value< osmium::Timestamp >()
Definition timestamp.hpp:368
osmium::operator<=
bool operator<=(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:459
osmium::operator>
bool operator>(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:455
osmium::min_op_start_value< osmium::Timestamp >
osmium::Timestamp min_op_start_value< osmium::Timestamp >()
Definition timestamp.hpp:363
osmium::operator>=
bool operator>=(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:463
osmium::operator!=
bool operator!=(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:444
osmium::start_of_time
constexpr Timestamp start_of_time() noexcept
Definition timestamp.hpp:320
osmium::operator<<
std::basic_ostream< TChar, TTraits > & operator<<(std::basic_ostream< TChar, TTraits > &out, const item_type item_type)
Definition item_type.hpp:187
osmium::operator<
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition changeset.hpp:451
std
Definition location.hpp:654