]>
git.proxmox.com Git - ceph.git/blob - ceph/src/common/iso_8601.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "include/timegm.h"
10 using std::chrono::duration_cast
;
11 using std::chrono::nanoseconds
;
12 using std::chrono::seconds
;
15 using std::stringstream
;
20 using boost::optional
;
21 using boost::string_ref
;
23 using ceph::real_clock
;
24 using ceph::real_time
;
26 using sriter
= string_ref::const_iterator
;
29 // This assumes a contiguous block of numbers in the correct order.
30 uint16_t digit(char c
) {
31 if (!(c
>= '0' && c
<= '9')) {
32 throw std::invalid_argument("Not a digit.");
34 return static_cast<uint16_t>(c
- '0');
37 optional
<real_time
> calculate(const tm
& t
, uint32_t n
= 0) {
38 ceph_assert(n
< 1000000000);
39 time_t tt
= internal_timegm(&t
);
40 if (tt
== static_cast<time_t>(-1)) {
44 return boost::make_optional
<real_time
>(real_clock::from_time_t(tt
)
49 optional
<real_time
> from_iso_8601(const string_ref s
,
50 const bool ws_terminates
) noexcept
{
52 auto read_digit
= [end
](sriter
& c
) mutable {
54 throw std::invalid_argument("End of input.");
61 auto read_digits
= [end
, &read_digit
](sriter
& c
, std::size_t n
) {
63 for (auto i
= 0U; i
< n
; ++i
) {
64 auto d
= read_digit(c
);
69 auto partial_date
= [end
, ws_terminates
](sriter
& c
) {
70 return (c
== end
|| (ws_terminates
&& std::isspace(*c
)));
72 auto time_end
= [end
, ws_terminates
](sriter
& c
) {
73 return (c
!= end
&& *c
== 'Z' &&
75 (ws_terminates
&& std::isspace(*(c
+ 1)))));
77 auto consume_delimiter
= [end
](sriter
& c
, char q
) {
78 if (c
== end
|| *c
!= q
) {
79 throw std::invalid_argument("Expected delimiter not found.");
98 auto y
= read_digits(c
, 4);
102 t
.tm_year
= y
- 1900;
104 if (partial_date(c
)) {
105 return calculate(t
, 0);
108 consume_delimiter(c
, '-');
109 t
.tm_mon
= (read_digits(c
, 2) - 1);
110 if (partial_date(c
)) {
113 consume_delimiter(c
, '-');
114 t
.tm_mday
= read_digits(c
, 2);
115 if (partial_date(c
)) {
118 consume_delimiter(c
, 'T');
119 t
.tm_hour
= read_digits(c
, 2);
123 consume_delimiter(c
, ':');
124 t
.tm_min
= read_digits(c
, 2);
128 consume_delimiter(c
, ':');
129 t
.tm_sec
= read_digits(c
, 2);
133 consume_delimiter(c
, '.');
136 auto multiplier
= 100000000UL;
137 for (auto i
= 0U; i
< 9U; ++i
) {
138 auto d
= read_digit(c
);
142 return calculate(t
, n
);
145 } catch (std::invalid_argument
& e
) {
151 string
to_iso_8601(const real_time t
,
152 const iso_8601_format f
) noexcept
{
153 ceph_assert(f
>= iso_8601_format::Y
&&
154 f
<= iso_8601_format::YMDhmsn
);
155 stringstream
out(std::ios_base::out
);
157 auto sec
= real_clock::to_time_t(t
);
158 auto nsec
= duration_cast
<nanoseconds
>(t
.time_since_epoch() %
165 out
<< 1900 + bt
.tm_year
;
166 if (f
== iso_8601_format::Y
) {
170 out
<< '-' << setw(2) << bt
.tm_mon
+ 1;
171 if (f
== iso_8601_format::YM
) {
175 out
<< '-' << setw(2) << bt
.tm_mday
;
176 if (f
== iso_8601_format::YMD
) {
180 out
<< 'T' << setw(2) << bt
.tm_hour
;
181 if (f
== iso_8601_format::YMDh
) {
186 out
<< ':' << setw(2) << bt
.tm_min
;
187 if (f
== iso_8601_format::YMDhm
) {
192 out
<< ':' << setw(2) << bt
.tm_sec
;
193 if (f
== iso_8601_format::YMDhms
) {
197 out
<< '.' << setw(9) << nsec
<< 'Z';