Add ZonedDateType definition & helper structures

This commit is contained in:
Ante Pušić 2024-03-25 09:16:11 +01:00
parent 1e04831295
commit 0d4b057491

View File

@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@ -22,6 +22,8 @@
namespace memgraph::utils {
class Timezone;
template <typename T>
concept Chrono = requires(T) {
typename T::rep;
@ -192,8 +194,13 @@ struct LocalTimeParameters {
bool operator==(const LocalTimeParameters &) const = default;
};
// boolean indicates whether the parsed string was in extended format
std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view string);
struct LocalTimeParsing {
LocalTimeParameters parameters;
bool extended_format;
uint64_t remainder_length;
};
LocalTimeParsing ParseLocalTimeParameters(std::string_view string, bool in_zoned_dt = false);
struct LocalTime {
explicit LocalTime() : LocalTime{LocalTimeParameters{}} {}
@ -251,7 +258,13 @@ struct LocalTimeHash {
size_t operator()(const LocalTime &local_time) const;
};
std::pair<DateParameters, LocalTimeParameters> ParseLocalDateTimeParameters(std::string_view string);
struct LocalDateTimeParsing {
DateParameters date_parameters;
LocalTimeParameters local_time_parameters;
uint64_t remainder_length;
};
LocalDateTimeParsing ParseLocalDateTimeParameters(std::string_view string, bool in_zoned_dt = false);
struct LocalDateTime {
explicit LocalDateTime(int64_t microseconds);
@ -294,6 +307,132 @@ struct LocalDateTimeHash {
size_t operator()(const LocalDateTime &local_date_time) const;
};
class Timezone {
private:
std::variant<std::chrono::minutes, const std::chrono::time_zone *> offset_;
public:
explicit Timezone(const std::chrono::minutes offset) : offset_{offset} {}
explicit Timezone(const std::chrono::time_zone *timezone) : offset_{timezone} {}
explicit Timezone(const std::string &timezone_name) : offset_{std::chrono::locate_zone(timezone_name)} {}
const Timezone *operator->() const { return this; }
bool operator==(const Timezone &) const = default;
template <class DurationT>
std::chrono::minutes OffsetInMinutes(std::chrono::sys_time<DurationT> time_point) const {
if (std::holds_alternative<std::chrono::minutes>(offset_)) {
return std::get<std::chrono::minutes>(offset_);
}
return std::chrono::duration_cast<std::chrono::minutes>(
std::get<const std::chrono::time_zone *>(offset_)->get_info(time_point).offset);
}
template <class DurationT>
std::chrono::sys_info get_info(std::chrono::sys_time<DurationT> time_point) const {
if (std::holds_alternative<std::chrono::minutes>(offset_)) {
const auto offset = std::get<std::chrono::minutes>(offset_);
return std::chrono::sys_info{
.begin = std::chrono::sys_seconds::min(),
.end = std::chrono::sys_seconds::max(),
.offset = std::chrono::duration_cast<std::chrono::seconds>(offset),
.save = std::chrono::minutes{0},
.abbrev = "",
// offset >= std::chrono::minutes{0} ? "+" + std::format("{0:%H}:{0:%M}", offset)
// : "-" + std::format("{0:%H}:{0:%M}", -offset)
};
}
return std::get<const std::chrono::time_zone *>(offset_)->get_info(time_point);
}
template <class DurationT>
auto to_local(std::chrono::sys_time<DurationT> time_point) const {
if (std::holds_alternative<std::chrono::minutes>(offset_)) {
using local_time = std::chrono::local_time<std::common_type_t<DurationT, std::chrono::minutes>>;
return local_time{(time_point + OffsetInMinutes(time_point)).time_since_epoch()};
}
return std::get<const std::chrono::time_zone *>(offset_)->to_local(time_point);
}
template <class DurationT>
auto to_sys(std::chrono::local_time<DurationT> time_point) const {
if (std::holds_alternative<std::chrono::minutes>(offset_)) {
using sys_time = std::chrono::sys_time<std::common_type_t<DurationT, std::chrono::minutes>>;
return sys_time{(time_point - std::get<std::chrono::minutes>(offset_)).time_since_epoch()};
}
return std::get<const std::chrono::time_zone *>(offset_)->to_sys(time_point);
}
std::string_view TimezoneName() const {
if (std::holds_alternative<std::chrono::minutes>(offset_)) {
return "";
}
return std::get<const std::chrono::time_zone *>(offset_)->name();
}
};
} // namespace memgraph::utils
namespace std::chrono {
template <>
struct zoned_traits<memgraph::utils::Timezone> {
static memgraph::utils::Timezone default_zone() { return memgraph::utils::Timezone{minutes{0}}; }
};
} // namespace std::chrono
namespace memgraph::utils {
struct ZonedDateTimeParameters {
DateParameters date;
LocalTimeParameters local_time;
Timezone timezone;
bool operator==(const ZonedDateTimeParameters &) const = default;
};
ZonedDateTimeParameters ParseZonedDateTimeParameters(std::string_view string);
struct ZonedDateTime {
explicit ZonedDateTime(const ZonedDateTimeParameters &zoned_date_time_parameters);
explicit ZonedDateTime(const ZonedDateTime &zoned_date_time);
explicit ZonedDateTime(const std::chrono::zoned_time<std::chrono::microseconds, Timezone> &zoned_time);
int64_t MicrosecondsSinceEpoch() const;
int64_t SecondsSinceEpoch() const;
int64_t SubSecondsAsNanoseconds() const;
std::string ToString() const;
bool operator==(const ZonedDateTime &other) const;
std::strong_ordering operator<=>(const ZonedDateTime &other) const;
std::chrono::minutes OffsetInMinutes() const {
return zoned_time.get_time_zone().OffsetInMinutes(zoned_time.get_sys_time());
}
std::string_view TimezoneName() const { return zoned_time.get_time_zone().TimezoneName(); }
friend std::ostream &operator<<(std::ostream &os, const ZonedDateTime &zdt) { return os << zdt.ToString(); }
friend ZonedDateTime operator+(const ZonedDateTime &zdt, const Duration &dur) {
return ZonedDateTime(std::chrono::zoned_time(
zdt.zoned_time.get_time_zone(), zdt.zoned_time.get_sys_time() + std::chrono::microseconds(dur.microseconds)));
}
friend ZonedDateTime operator+(const Duration &dur, const ZonedDateTime &zdt) { return zdt + dur; }
friend ZonedDateTime operator-(const ZonedDateTime &zdt, const Duration &dur) { return zdt + (-dur); }
friend Duration operator-(const ZonedDateTime &lhs, const ZonedDateTime &rhs) {
return Duration(lhs.MicrosecondsSinceEpoch()) - Duration(rhs.MicrosecondsSinceEpoch());
}
std::chrono::zoned_time<std::chrono::microseconds, Timezone> zoned_time;
};
Date CurrentDate();
LocalTime CurrentLocalTime();
LocalDateTime CurrentLocalDateTime();