diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/timezone_conversion/civil.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/timezone_conversion/civil.cpp')
-rw-r--r-- | library/cpp/timezone_conversion/civil.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/library/cpp/timezone_conversion/civil.cpp b/library/cpp/timezone_conversion/civil.cpp new file mode 100644 index 0000000000..5986318b9a --- /dev/null +++ b/library/cpp/timezone_conversion/civil.cpp @@ -0,0 +1,234 @@ +#include "civil.h" + +#include <util/stream/output.h> +#include <util/stream/format.h> +#include <util/string/ascii.h> + +namespace { + bool TryParseInt(TStringBuf& s, int& dst, size_t maxDigits) { + int res = 0; + size_t i = 0; + while (i < maxDigits && !s.empty() && IsAsciiDigit(s[0])) { + res = res * 10 + (s[0] - '0'); + ++i; + s.Skip(1); + } + if (i == 0) { + return false; + } + dst = res; + return true; + } + + bool TryParseUTCOffsetTimezone(TStringBuf name, int& offset) { + static constexpr TStringBuf OFFSET_PREFIX = "UTC"; + if (!name.SkipPrefix(OFFSET_PREFIX)) { + return false; + } + if (name.empty()) { + return false; + } + bool negative; + if (name[0] == '+') { + negative = false; + } else if (name[0] == '-') { + negative = true; + } else { + return false; + } + name.Skip(1); + int hour; + int minute = 0; + if (!TryParseInt(name, hour, 2) || hour > 24) { + return false; + } + if (!name.empty()) { + if (name[0] == ':') { + name.Skip(1); + } + if (!TryParseInt(name, minute, 2) || minute >= 60) { + return false; + } + if (!name.empty()) { + return false; + } + } + if (hour == 24 && minute != 0) { + return false; + } + offset = (hour * 60 + minute) * 60; + if (negative) + offset = -offset; + return true; + } +} // anonymous namespace + +namespace NDatetime { + TTimeZone GetTimeZone(TStringBuf name) { + int offset; + if (TryParseUTCOffsetTimezone(name, offset)) { + return GetFixedTimeZone(offset); + } + TTimeZone result; + if (!cctz::load_time_zone(static_cast<std::string>(name), &result)) { + ythrow TInvalidTimezone() << "Failed to load time zone " << name << ", " << result.name(); + } + return result; + } + + TTimeZone GetFixedTimeZone(const long offset) { + return cctz::fixed_time_zone(std::chrono::seconds(offset)); + } + + TCivilSecond Convert(const TInstant& absTime, const TTimeZone& tz) { + return cctz::convert(TSystemClock::from_time_t(absTime.TimeT()), tz); + } + + TCivilSecond Convert(const TInstant& absTime, TStringBuf tzName) { + TTimeZone tz = GetTimeZone(tzName); + return cctz::convert(TSystemClock::from_time_t(absTime.TimeT()), tz); + } + + TInstant Convert(const TCivilSecond& tp, const TTimeZone& tz) { + return TInstant::Seconds(cctz::convert(tp, tz).time_since_epoch().count()); + } + + TCivilSecond AddYears(const TCivilSecond& tp, TDiff diff) { + TCivilYear newYear = Calc<TCivilYear>(tp, diff); + return NDatetime::TCivilSecond(newYear.year(), tp.month(), tp.day(), tp.hour(), tp.minute(), tp.second()); + } + + TCivilSecond AddMonths(const TCivilSecond& tp, TDiff diff) { + TCivilMonth newMonth = Calc<TCivilMonth>(tp, diff); + return NDatetime::TCivilSecond(newMonth.year(), newMonth.month(), tp.day(), tp.hour(), tp.minute(), tp.second()); + } + + TCivilSecond AddDays(const TCivilSecond& tp, TDiff diff) { + TCivilDay newDay = Calc<TCivilDay>(tp, diff); + return NDatetime::TCivilSecond(newDay.year(), newDay.month(), newDay.day(), tp.hour(), tp.minute(), tp.second()); + } + + TCivilSecond AddHours(const TCivilSecond& tp, TDiff diff) { + TCivilHour newHour = Calc<TCivilHour>(tp, diff); + return NDatetime::TCivilSecond(newHour.year(), newHour.month(), newHour.day(), newHour.hour(), tp.minute(), tp.second()); + } + + TCivilSecond AddMinutes(const TCivilSecond& tp, TDiff diff) { + TCivilMinute newMinute = Calc<TCivilMinute>(tp, diff); + return NDatetime::TCivilSecond(newMinute.year(), newMinute.month(), newMinute.day(), newMinute.hour(), newMinute.minute(), tp.second()); + } + + TCivilSecond AddSeconds(const TCivilSecond& tp, TDiff diff) { + return Calc<TCivilSecond>(tp, diff); + } + + TCivilSecond AddCivil(const TCivilSecond& tp, TCivilDiff diff) { + switch (diff.Unit) { + case ECivilUnit::Second: { + return AddSeconds(tp, diff.Value); + } + case ECivilUnit::Minute: { + return AddMinutes(tp, diff.Value); + } + case ECivilUnit::Hour: { + return AddHours(tp, diff.Value); + } + case ECivilUnit::Day: { + return AddDays(tp, diff.Value); + } + case ECivilUnit::Month: { + return AddMonths(tp, diff.Value); + } + case ECivilUnit::Year: { + return AddYears(tp, diff.Value); + } + default: { + ythrow yexception() << "Unexpected civil unit value " << static_cast<int>(diff.Unit); + } + } + } + + TCivilDiff GetCivilDiff(const TCivilSecond& tpX, const TCivilSecond& tpY, ECivilUnit unit) { + switch (unit) { + case ECivilUnit::Second: { + return {tpX - tpY, unit}; + } + case ECivilUnit::Minute: { + return {static_cast<TCivilMinute>(tpX) - static_cast<TCivilMinute>(tpY), unit}; + } + case ECivilUnit::Hour: { + return {static_cast<TCivilHour>(tpX) - static_cast<TCivilHour>(tpY), unit}; + } + case ECivilUnit::Day: { + return {static_cast<TCivilDay>(tpX) - static_cast<TCivilDay>(tpY), unit}; + } + case ECivilUnit::Month: { + return {static_cast<TCivilMonth>(tpX) - static_cast<TCivilMonth>(tpY), unit}; + } + case ECivilUnit::Year: { + return {static_cast<TCivilYear>(tpX) - static_cast<TCivilYear>(tpY), unit}; + } + default: { + ythrow yexception() << "Unexpected civil unit value " << static_cast<int>(unit); + } + } + } +} + +template <> +void Out<NDatetime::TCivilYear>(IOutputStream& out, const NDatetime::TCivilYear& y) { + out << y.year(); +} + +template <> +void Out<NDatetime::TCivilMonth>(IOutputStream& out, const NDatetime::TCivilMonth& m) { + out << NDatetime::TCivilYear(m) << '-' << LeftPad(m.month(), 2, '0'); +} + +template <> +void Out<NDatetime::TCivilDay>(IOutputStream& out, const NDatetime::TCivilDay& d) { + out << NDatetime::TCivilMonth(d) << '-' << LeftPad(d.day(), 2, '0'); +} + +template <> +void Out<NDatetime::TCivilHour>(IOutputStream& out, const NDatetime::TCivilHour& h) { + out << NDatetime::TCivilDay(h) << 'T' << LeftPad(h.hour(), 2, '0'); +} + +template <> +void Out<NDatetime::TCivilMinute>(IOutputStream& out, const NDatetime::TCivilMinute& m) { + out << NDatetime::TCivilHour(m) << ':' << LeftPad(m.minute(), 2, '0'); +} + +template <> +void Out<NDatetime::TCivilSecond>(IOutputStream& out, const NDatetime::TCivilSecond& s) { + out << NDatetime::TCivilMinute(s) << ':' << LeftPad(s.second(), 2, '0'); +} + +template <> +void Out<NDatetime::TWeekday>(IOutputStream& out, NDatetime::TWeekday wd) { + using namespace cctz; + switch (wd) { + case weekday::monday: + out << TStringBuf("Monday"); + break; + case weekday::tuesday: + out << TStringBuf("Tuesday"); + break; + case weekday::wednesday: + out << TStringBuf("Wednesday"); + break; + case weekday::thursday: + out << TStringBuf("Thursday"); + break; + case weekday::friday: + out << TStringBuf("Friday"); + break; + case weekday::saturday: + out << TStringBuf("Saturday"); + break; + case weekday::sunday: + out << TStringBuf("Sunday"); + break; + } +} |