X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fiso_8601.cc;fp=src%2Fceph%2Fsrc%2Fcommon%2Fiso_8601.cc;h=39e00e0b31f9c648d79b54c7e94fbab56b83ca67;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/common/iso_8601.cc b/src/ceph/src/common/iso_8601.cc new file mode 100644 index 0000000..39e00e0 --- /dev/null +++ b/src/ceph/src/common/iso_8601.cc @@ -0,0 +1,200 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "iso_8601.h" +#include "include/timegm.h" + +#include + +namespace ceph { +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::seconds; +using std::setw; +using std::size_t; +using std::stringstream; +using std::string; +using std::uint16_t; + +using boost::none; +using boost::optional; +using boost::string_ref; + +using ceph::real_clock; +using ceph::real_time; + +using sriter = string_ref::const_iterator; + +namespace { +// This assumes a contiguous block of numbers in the correct order. +uint16_t digit(char c) { + if (!(c >= '0' && c <= '9')) { + throw std::invalid_argument("Not a digit."); + } + return static_cast(c - '0'); +} + +optional calculate(const tm& t, uint32_t n = 0) { + ceph_assert(n < 1000000000); + time_t tt = internal_timegm(&t); + if (tt == static_cast(-1)) { + return none; + } + + return boost::make_optional(real_clock::from_time_t(tt) + + nanoseconds(n)); +} +} + +optional from_iso_8601(const string_ref s, + const bool ws_terminates) noexcept { + auto end = s.cend(); + auto read_digit = [end](sriter& c) mutable { + if (c == end) { + throw std::invalid_argument("End of input."); + } + auto f = digit(*c); + ++c; + return f; + }; + + auto read_digits = [end, &read_digit](sriter& c, std::size_t n) { + auto v = 0ULL; + for (auto i = 0U; i < n; ++i) { + auto d = read_digit(c); + v = (10ULL * v) + d; + } + return v; + }; + auto partial_date = [end, ws_terminates](sriter& c) { + return (c == end || (ws_terminates && std::isspace(*c))); + }; + auto time_end = [end, ws_terminates](sriter& c) { + return (c != end && *c == 'Z' && + ((c + 1) == end || + (ws_terminates && std::isspace(*(c + 1))))); + }; + auto consume_delimiter = [end](sriter& c, char q) { + if (c == end || *c != q) { + throw std::invalid_argument("Expected delimiter not found."); + } else { + ++c; + } + }; + + tm t = { 0, // tm_sec + 0, // tm_min + 0, // tm_hour + 1, // tm_mday + 0, // tm_mon + 70, // tm_year + 0, // tm_wday + 0, // tm_yday + 0, // tm_isdst + }; + try { + auto c = s.cbegin(); + { + auto y = read_digits(c, 4); + if (y < 1970) { + return none; + } + t.tm_year = y - 1900; + } + if (partial_date(c)) { + return calculate(t, 0); + } + + consume_delimiter(c, '-'); + t.tm_mon = (read_digits(c, 2) - 1); + if (partial_date(c)) { + return calculate(t); + } + consume_delimiter(c, '-'); + t.tm_mday = read_digits(c, 2); + if (partial_date(c)) { + return calculate(t); + } + consume_delimiter(c, 'T'); + t.tm_hour = read_digits(c, 2); + if (time_end(c)) { + return calculate(t); + } + consume_delimiter(c, ':'); + t.tm_min = read_digits(c, 2); + if (time_end(c)) { + return calculate(t); + } + consume_delimiter(c, ':'); + t.tm_sec = read_digits(c, 2); + if (time_end(c)) { + return calculate(t); + } + consume_delimiter(c, '.'); + + auto n = 0UL; + auto multiplier = 100000000UL; + for (auto i = 0U; i < 9U; ++i) { + auto d = read_digit(c); + n += d * multiplier; + multiplier /= 10; + if (time_end(c)) { + return calculate(t, n); + } + } + } catch (std::invalid_argument& e) { + // fallthrough + } + return none; +} + +string to_iso_8601(const real_time t, + const iso_8601_format f) noexcept { + ceph_assert(f >= iso_8601_format::Y && + f <= iso_8601_format::YMDhmsn); + stringstream out(std::ios_base::out); + + auto sec = real_clock::to_time_t(t); + auto nsec = duration_cast(t.time_since_epoch() % + seconds(1)).count(); + + struct tm bt; + gmtime_r(&sec, &bt); + out.fill('0'); + + out << 1900 + bt.tm_year; + if (f == iso_8601_format::Y) { + return out.str(); + } + + out << '-' << setw(2) << bt.tm_mon + 1; + if (f == iso_8601_format::YM) { + return out.str(); + } + + out << '-' << setw(2) << bt.tm_mday; + if (f == iso_8601_format::YMD) { + return out.str(); + } + + out << 'T' << setw(2) << bt.tm_hour; + if (f == iso_8601_format::YMDh) { + out << 'Z'; + return out.str(); + } + + out << ':' << setw(2) << bt.tm_min; + if (f == iso_8601_format::YMDhm) { + out << 'Z'; + return out.str(); + } + + out << ':' << setw(2) << bt.tm_sec; + if (f == iso_8601_format::YMDhms) { + out << 'Z'; + return out.str(); + } + out << '.' << setw(9) << nsec << 'Z'; + return out.str(); +} +}