diff options
-rw-r--r-- | include/erebos/storage.h | 15 | ||||
-rw-r--r-- | src/storage.cpp | 41 |
2 files changed, 56 insertions, 0 deletions
diff --git a/include/erebos/storage.h b/include/erebos/storage.h index 0859dc8..b6595b6 100644 --- a/include/erebos/storage.h +++ b/include/erebos/storage.h @@ -1,6 +1,7 @@ #pragma once #include <array> +#include <chrono> #include <cstring> #include <filesystem> #include <memory> @@ -156,6 +157,18 @@ protected: Ref(const std::shared_ptr<const Priv> p): PartialRef(p) {} }; +struct ZonedTime +{ + explicit ZonedTime(std::string); + ZonedTime(std::chrono::system_clock::time_point t): time(t), zone(0) {} + explicit operator std::string() const; + + static ZonedTime now(); + + std::chrono::system_clock::time_point time; + std::chrono::minutes zone; // zone offset +}; + struct UUID { explicit UUID(std::string); @@ -184,6 +197,7 @@ public: int, std::string, std::vector<uint8_t>, + ZonedTime, UUID, typename S::Ref, UnknownType> Variant; @@ -204,6 +218,7 @@ public: std::optional<int> asInteger() const; std::optional<std::string> asText() const; std::optional<std::vector<uint8_t>> asBinary() const; + std::optional<ZonedTime> asDate() const; std::optional<UUID> asUUID() const; std::optional<typename S::Ref> asRef() const; std::optional<UnknownType> asUnknown() const; diff --git a/src/storage.cpp b/src/storage.cpp index e0819d4..525d83d 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -536,6 +536,34 @@ const Storage & Ref::storage() const } +ZonedTime::ZonedTime(string str) +{ + intmax_t t; + unsigned int h, m; + char sign[2]; + if (sscanf(str.c_str(), "%jd %1[+-]%2u%2u", &t, sign, &h, &m) != 4) + throw runtime_error("invalid zoned time"); + + time = std::chrono::system_clock::time_point(std::chrono::seconds(t)); + zone = std::chrono::minutes((sign[0] == '-' ? -1 : 1) * (60 * h + m)); +} + +ZonedTime::operator string() const +{ + char buf[32]; + unsigned int az = std::chrono::abs(zone).count(); + snprintf(buf, sizeof(buf), "%jd %c%02u%02u", + (intmax_t) std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count(), + zone < decltype(zone)::zero() ? '-' : '+', az / 60, az % 60); + return string(buf); +} + +ZonedTime ZonedTime::now() +{ + return ZonedTime(std::chrono::system_clock::now()); +} + + UUID::UUID(string str) { if (uuid_parse(str.c_str(), uuid) != 0) @@ -591,6 +619,14 @@ optional<vector<uint8_t>> RecordT<S>::Item::asBinary() const } template<class S> +optional<ZonedTime> RecordT<S>::Item::asDate() const +{ + if (holds_alternative<ZonedTime>(value)) + return std::get<ZonedTime>(value); + return nullopt; +} + +template<class S> optional<UUID> RecordT<S>::Item::asUUID() const { if (holds_alternative<UUID>(value)) @@ -655,6 +691,8 @@ optional<RecordT<S>> RecordT<S>::decode(const S & st, items->emplace_back(name, value); else if (type == "b") items->emplace_back(name, base64::decode(value)); + else if (type == "d") + items->emplace_back(name, ZonedTime(value)); else if (type == "u") items->emplace_back(name, UUID(value)); else if (type == "r.b2") { @@ -736,6 +774,9 @@ vector<uint8_t> RecordT<S>::encodeInner() const } else if (auto x = item.asBinary()) { type = "b"; value = base64::encode(*x); + } else if (auto x = item.asDate()) { + type = "d"; + value = string(*x); } else if (auto x = item.asUUID()) { type = "u"; value = string(*x); |