diff options
author | Ivan Komarov <Ivan.Komarov@dfyz.info> | 2022-02-10 16:46:48 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:48 +0300 |
commit | 4de97ab2fe437cbe83e4c63234e809ddd5ac34f2 (patch) | |
tree | ff8fb38b661955e6c99d1d000d6c72f739199590 /library/cpp | |
parent | 9abfb1a53b7f7b791444d1378e645d8fad9b06ed (diff) | |
download | ydb-4de97ab2fe437cbe83e4c63234e809ddd5ac34f2.tar.gz |
Restoring authorship annotation for Ivan Komarov <Ivan.Komarov@dfyz.info>. Commit 1 of 2.
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/containers/bitseq/bitvector.h | 14 | ||||
-rw-r--r-- | library/cpp/containers/bitseq/bitvector_ut.cpp | 40 | ||||
-rw-r--r-- | library/cpp/containers/bitseq/readonly_bitvector.cpp | 2 | ||||
-rw-r--r-- | library/cpp/containers/bitseq/readonly_bitvector.h | 136 | ||||
-rw-r--r-- | library/cpp/containers/bitseq/traits.h | 40 | ||||
-rw-r--r-- | library/cpp/containers/bitseq/ya.make | 2 | ||||
-rw-r--r-- | library/cpp/pop_count/popcount.h | 2 | ||||
-rw-r--r-- | library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp | 2 | ||||
-rw-r--r-- | library/cpp/testing/unittest/gtest.h | 2 | ||||
-rw-r--r-- | library/cpp/testing/unittest/registar.h | 44 | ||||
-rw-r--r-- | library/cpp/testing/unittest/registar_ut.cpp | 10 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/README.md | 26 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/convert.cpp | 56 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/convert.h | 88 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/ut/convert_ut.cpp | 292 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/ut/ya.make | 24 | ||||
-rw-r--r-- | library/cpp/timezone_conversion/ya.make | 26 | ||||
-rw-r--r-- | library/cpp/uri/uri_ut.cpp | 2 |
18 files changed, 404 insertions, 404 deletions
diff --git a/library/cpp/containers/bitseq/bitvector.h b/library/cpp/containers/bitseq/bitvector.h index 3f8fd81ee5..5c6495d1bd 100644 --- a/library/cpp/containers/bitseq/bitvector.h +++ b/library/cpp/containers/bitseq/bitvector.h @@ -8,16 +8,16 @@ #include <util/ysaveload.h> template <typename T> -class TReadonlyBitVector; - -template <typename T> +class TReadonlyBitVector; + +template <typename T> class TBitVector { public: using TWord = T; using TTraits = TBitSeqTraits<TWord>; private: - friend class TReadonlyBitVector<T>; + friend class TReadonlyBitVector<T>; ui64 Size_; TVector<TWord> Data_; @@ -61,7 +61,7 @@ public: } bool Test(ui64 pos) const { - return TTraits::Test(Data(), pos, Size_); + return TTraits::Test(Data(), pos, Size_); } void Reset(ui64 pos) { @@ -70,7 +70,7 @@ public: } TWord Get(ui64 pos, ui8 width, TWord mask) const { - return TTraits::Get(Data(), pos, width, mask, Size_); + return TTraits::Get(Data(), pos, width, mask, Size_); } TWord Get(ui64 pos, ui8 width) const { @@ -127,7 +127,7 @@ public: } const TWord* Data() const { - return Data_.data(); + return Data_.data(); } void Save(IOutputStream* out) const { diff --git a/library/cpp/containers/bitseq/bitvector_ut.cpp b/library/cpp/containers/bitseq/bitvector_ut.cpp index 6137adab1e..3ba2791354 100644 --- a/library/cpp/containers/bitseq/bitvector_ut.cpp +++ b/library/cpp/containers/bitseq/bitvector_ut.cpp @@ -1,11 +1,11 @@ #include "bitvector.h" -#include "readonly_bitvector.h" +#include "readonly_bitvector.h" #include <library/cpp/testing/unittest/registar.h> -#include <util/memory/blob.h> -#include <util/stream/buffer.h> - +#include <util/memory/blob.h> +#include <util/stream/buffer.h> + Y_UNIT_TEST_SUITE(TBitVectorTest) { Y_UNIT_TEST(TestEmpty) { TBitVector<ui64> v64; @@ -66,21 +66,21 @@ Y_UNIT_TEST_SUITE(TBitVectorTest) { v.Set(10 * 32, 100500, 32); UNIT_ASSERT_EQUAL(v.Get(10 * 32, 32), 100500); } - + Y_UNIT_TEST(TestReadonlyVector) { - TBitVector<ui64> v(100); - for (ui64 i = 0; i < v.Size(); ++i) { - if (i % 3 == 0) { - v.Set(i); - } - } - TBufferStream bs; - TReadonlyBitVector<ui64>::SaveForReadonlyAccess(&bs, v); - const auto blob = TBlob::FromBuffer(bs.Buffer()); - TReadonlyBitVector<ui64> rv; - rv.LoadFromBlob(blob); - for (ui64 i = 0; i < rv.Size(); ++i) { - UNIT_ASSERT_VALUES_EQUAL(rv.Test(i), i % 3 == 0); - } - } + TBitVector<ui64> v(100); + for (ui64 i = 0; i < v.Size(); ++i) { + if (i % 3 == 0) { + v.Set(i); + } + } + TBufferStream bs; + TReadonlyBitVector<ui64>::SaveForReadonlyAccess(&bs, v); + const auto blob = TBlob::FromBuffer(bs.Buffer()); + TReadonlyBitVector<ui64> rv; + rv.LoadFromBlob(blob); + for (ui64 i = 0; i < rv.Size(); ++i) { + UNIT_ASSERT_VALUES_EQUAL(rv.Test(i), i % 3 == 0); + } + } } diff --git a/library/cpp/containers/bitseq/readonly_bitvector.cpp b/library/cpp/containers/bitseq/readonly_bitvector.cpp index 891aa7cde2..e38b381838 100644 --- a/library/cpp/containers/bitseq/readonly_bitvector.cpp +++ b/library/cpp/containers/bitseq/readonly_bitvector.cpp @@ -1 +1 @@ -#include "readonly_bitvector.h" +#include "readonly_bitvector.h" diff --git a/library/cpp/containers/bitseq/readonly_bitvector.h b/library/cpp/containers/bitseq/readonly_bitvector.h index 8612739c3f..bed2cfc061 100644 --- a/library/cpp/containers/bitseq/readonly_bitvector.h +++ b/library/cpp/containers/bitseq/readonly_bitvector.h @@ -1,76 +1,76 @@ -#pragma once - -#include "bitvector.h" -#include "traits.h" - -#include <util/memory/blob.h> - -#include <cstring> - -template <typename T> -class TReadonlyBitVector { -public: - using TWord = T; - using TTraits = TBitSeqTraits<TWord>; - - TReadonlyBitVector() - : Size_() - , Data_() +#pragma once + +#include "bitvector.h" +#include "traits.h" + +#include <util/memory/blob.h> + +#include <cstring> + +template <typename T> +class TReadonlyBitVector { +public: + using TWord = T; + using TTraits = TBitSeqTraits<TWord>; + + TReadonlyBitVector() + : Size_() + , Data_() { } - + explicit TReadonlyBitVector(const TBitVector<T>& vector) : Size_(vector.Size_) , Data_(vector.Data_.data()) { } - bool Test(ui64 pos) const { - return TTraits::Test(Data_, pos, Size_); - } - - TWord Get(ui64 pos, ui8 width, TWord mask) const { - return TTraits::Get(Data_, pos, width, mask, Size_); - } - - TWord Get(ui64 pos, ui8 width) const { - return Get(pos, width, TTraits::ElemMask(width)); - } - - ui64 Size() const { - return Size_; - } - - const T* Data() const { - return Data_; - } - - static void SaveForReadonlyAccess(IOutputStream* out, const TBitVector<T>& bv) { - ::Save(out, bv.Size_); - ::Save(out, static_cast<ui64>(bv.Data_.size())); - ::SavePodArray(out, bv.Data_.data(), bv.Data_.size()); - } - - virtual TBlob LoadFromBlob(const TBlob& blob) { - size_t read = 0; - auto cursor = [&]() { return blob.AsUnsignedCharPtr() + read; }; - auto readToPtr = [&](auto* ptr) { - memcpy(ptr, cursor(), sizeof(*ptr)); - read += sizeof(*ptr); - }; - - readToPtr(&Size_); - - ui64 wordCount{}; - readToPtr(&wordCount); - - Data_ = reinterpret_cast<const T*>(cursor()); - read += wordCount * sizeof(T); - - return blob.SubBlob(read, blob.Size()); - } - -private: - ui64 Size_; - const T* Data_; -}; + bool Test(ui64 pos) const { + return TTraits::Test(Data_, pos, Size_); + } + + TWord Get(ui64 pos, ui8 width, TWord mask) const { + return TTraits::Get(Data_, pos, width, mask, Size_); + } + + TWord Get(ui64 pos, ui8 width) const { + return Get(pos, width, TTraits::ElemMask(width)); + } + + ui64 Size() const { + return Size_; + } + + const T* Data() const { + return Data_; + } + + static void SaveForReadonlyAccess(IOutputStream* out, const TBitVector<T>& bv) { + ::Save(out, bv.Size_); + ::Save(out, static_cast<ui64>(bv.Data_.size())); + ::SavePodArray(out, bv.Data_.data(), bv.Data_.size()); + } + + virtual TBlob LoadFromBlob(const TBlob& blob) { + size_t read = 0; + auto cursor = [&]() { return blob.AsUnsignedCharPtr() + read; }; + auto readToPtr = [&](auto* ptr) { + memcpy(ptr, cursor(), sizeof(*ptr)); + read += sizeof(*ptr); + }; + + readToPtr(&Size_); + + ui64 wordCount{}; + readToPtr(&wordCount); + + Data_ = reinterpret_cast<const T*>(cursor()); + read += wordCount * sizeof(T); + + return blob.SubBlob(read, blob.Size()); + } + +private: + ui64 Size_; + const T* Data_; +}; diff --git a/library/cpp/containers/bitseq/traits.h b/library/cpp/containers/bitseq/traits.h index 2330b1b4f2..99047363de 100644 --- a/library/cpp/containers/bitseq/traits.h +++ b/library/cpp/containers/bitseq/traits.h @@ -2,7 +2,7 @@ #include <util/generic/bitops.h> #include <util/generic/typetraits.h> -#include <util/system/yassert.h> +#include <util/system/yassert.h> template <typename TWord> struct TBitSeqTraits { @@ -25,25 +25,25 @@ struct TBitSeqTraits { return (bits + NumBits - 1) >> DivShift; } - static bool Test(const TWord* data, ui64 pos, ui64 size) { - Y_ASSERT(pos < size); - return data[pos >> DivShift] & BitMask(pos & ModMask); - } - - static TWord Get(const TWord* data, ui64 pos, ui8 width, TWord mask, ui64 size) { - if (!width) - return 0; - Y_ASSERT((pos + width) <= size); - size_t word = pos >> DivShift; - TWord shift1 = pos & ModMask; - TWord shift2 = NumBits - shift1; - TWord res = data[word] >> shift1 & mask; - if (shift2 < width) { - res |= data[word + 1] << shift2 & mask; - } - return res; - } - + static bool Test(const TWord* data, ui64 pos, ui64 size) { + Y_ASSERT(pos < size); + return data[pos >> DivShift] & BitMask(pos & ModMask); + } + + static TWord Get(const TWord* data, ui64 pos, ui8 width, TWord mask, ui64 size) { + if (!width) + return 0; + Y_ASSERT((pos + width) <= size); + size_t word = pos >> DivShift; + TWord shift1 = pos & ModMask; + TWord shift2 = NumBits - shift1; + TWord res = data[word] >> shift1 & mask; + if (shift2 < width) { + res |= data[word + 1] << shift2 & mask; + } + return res; + } + static_assert(std::is_unsigned<TWord>::value, "Expected std::is_unsigned<T>::value."); static_assert((NumBits & (NumBits - 1)) == 0, "NumBits should be a power of 2."); }; diff --git a/library/cpp/containers/bitseq/ya.make b/library/cpp/containers/bitseq/ya.make index 7090956c55..c69d13b721 100644 --- a/library/cpp/containers/bitseq/ya.make +++ b/library/cpp/containers/bitseq/ya.make @@ -9,7 +9,7 @@ PEERDIR( SRCS( bitvector.cpp - readonly_bitvector.cpp + readonly_bitvector.cpp ) END() diff --git a/library/cpp/pop_count/popcount.h b/library/cpp/pop_count/popcount.h index 3d67737ed2..0aa063d488 100644 --- a/library/cpp/pop_count/popcount.h +++ b/library/cpp/pop_count/popcount.h @@ -66,7 +66,7 @@ static inline ui32 PopCountImpl(ui32 n) { } static inline ui32 PopCountImpl(ui64 n) { -#if defined(_MSC_VER) && !defined(_i386_) +#if defined(_MSC_VER) && !defined(_i386_) return __popcnt64(n); #else #if defined(_x86_64_) diff --git a/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp b/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp index c3ed068a37..4d482168ad 100644 --- a/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp +++ b/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp @@ -38,7 +38,7 @@ Y_UNIT_TEST_SUITE(TBase64DecodeUneven) { const TString lp = "Linkin Park"; UNIT_ASSERT_VALUES_EQUAL(lp, Base64DecodeUneven(Base64Encode(lp))); UNIT_ASSERT_VALUES_EQUAL(lp, Base64DecodeUneven(Base64EncodeUrl(lp))); - + const TString dp = "ADP GmbH\nAnalyse Design & Programmierung\nGesellschaft mit beschränkter Haftung"; UNIT_ASSERT_VALUES_EQUAL(dp, Base64DecodeUneven(Base64Encode(dp))); UNIT_ASSERT_VALUES_EQUAL(dp, Base64DecodeUneven(Base64EncodeUrl(dp))); diff --git a/library/cpp/testing/unittest/gtest.h b/library/cpp/testing/unittest/gtest.h index b6768b1bf0..3818b2096d 100644 --- a/library/cpp/testing/unittest/gtest.h +++ b/library/cpp/testing/unittest/gtest.h @@ -80,7 +80,7 @@ namespace testing { #define EXPECT_NE(A, B) UNIT_ASSERT_UNEQUAL(A, B) #define EXPECT_LE(A, B) UNIT_ASSERT((A) <= (B)) #define EXPECT_LT(A, B) UNIT_ASSERT((A) < (B)) -#define EXPECT_GE(A, B) UNIT_ASSERT((A) >= (B)) +#define EXPECT_GE(A, B) UNIT_ASSERT((A) >= (B)) #define EXPECT_GT(A, B) UNIT_ASSERT((A) > (B)) #define EXPECT_NO_THROW(A) UNIT_ASSERT_NO_EXCEPTION(A) #define EXPECT_THROW(A, B) UNIT_ASSERT_EXCEPTION(A, B) diff --git a/library/cpp/testing/unittest/registar.h b/library/cpp/testing/unittest/registar.h index 44517a0092..4965e0bbb7 100644 --- a/library/cpp/testing/unittest/registar.h +++ b/library/cpp/testing/unittest/registar.h @@ -383,9 +383,9 @@ public: \ } while (false) //doubles -// UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED* macros do not handle NaNs correctly (see IGNIETFERRO-1419) and are for backward compatibility -// only. Consider switching to regular UNIT_ASSERT_DOUBLES_EQUAL* macros if you're still using the deprecated version. -#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, C) \ +// UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED* macros do not handle NaNs correctly (see IGNIETFERRO-1419) and are for backward compatibility +// only. Consider switching to regular UNIT_ASSERT_DOUBLES_EQUAL* macros if you're still using the deprecated version. +#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, C) \ do { \ if (std::abs((E) - (A)) > (D)) { \ const auto _es = ToString((long double)(E)); \ @@ -396,32 +396,32 @@ public: \ } \ } while (false) -#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, "") - -#define UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, C) \ - do { \ - const auto _ed = (E); \ - const auto _ad = (A); \ - const auto _dd = (D); \ +#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, "") + +#define UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, C) \ + do { \ + const auto _ed = (E); \ + const auto _ad = (A); \ + const auto _dd = (D); \ if (std::isnan((long double)_ed) && !std::isnan((long double)_ad)) { \ const auto _as = ToString((long double)_ad); \ auto&& failMsg = Sprintf("expected NaN, got %s %s", _as.data(), (::TStringBuilder() << C).data()); \ - UNIT_FAIL_IMPL("assertion failure", failMsg); \ - } \ + UNIT_FAIL_IMPL("assertion failure", failMsg); \ + } \ if (!std::isnan((long double)_ed) && std::isnan((long double)_ad)) { \ const auto _es = ToString((long double)_ed); \ auto&& failMsg = Sprintf("expected %s, got NaN %s", _es.data(), (::TStringBuilder() << C).data()); \ - UNIT_FAIL_IMPL("assertion failure", failMsg); \ - } \ - if (std::abs((_ed) - (_ad)) > (_dd)) { \ - const auto _es = ToString((long double)_ed); \ - const auto _as = ToString((long double)_ad); \ - const auto _ds = ToString((long double)_dd); \ + UNIT_FAIL_IMPL("assertion failure", failMsg); \ + } \ + if (std::abs((_ed) - (_ad)) > (_dd)) { \ + const auto _es = ToString((long double)_ed); \ + const auto _as = ToString((long double)_ad); \ + const auto _ds = ToString((long double)_dd); \ auto&& failMsg = Sprintf("std::abs(%s - %s) > %s %s", _es.data(), _as.data(), _ds.data(), (::TStringBuilder() << C).data()); \ - UNIT_FAIL_IMPL("assertion failure", failMsg); \ - } \ - } while (false) - + UNIT_FAIL_IMPL("assertion failure", failMsg); \ + } \ + } while (false) + #define UNIT_ASSERT_DOUBLES_EQUAL(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, "") //strings diff --git a/library/cpp/testing/unittest/registar_ut.cpp b/library/cpp/testing/unittest/registar_ut.cpp index 1f36d53abb..5db231c49d 100644 --- a/library/cpp/testing/unittest/registar_ut.cpp +++ b/library/cpp/testing/unittest/registar_ut.cpp @@ -28,11 +28,11 @@ Y_UNIT_TEST_SUITE(TUnitTestMacroTest) { UNIT_ASSERT_DOUBLES_EQUAL(0.0, 0.01, 0.1); UNIT_ASSERT_DOUBLES_EQUAL(0.01, 0.0, 0.1); - - constexpr auto nan = std::numeric_limits<double>::quiet_NaN(); - UNIT_ASSERT_TEST_FAILS(doublesEqual(nan, 0.5, 0.1)); - UNIT_ASSERT_TEST_FAILS(doublesEqual(0.5, nan, 0.1)); - UNIT_ASSERT_DOUBLES_EQUAL(nan, nan, 0.1); + + constexpr auto nan = std::numeric_limits<double>::quiet_NaN(); + UNIT_ASSERT_TEST_FAILS(doublesEqual(nan, 0.5, 0.1)); + UNIT_ASSERT_TEST_FAILS(doublesEqual(0.5, nan, 0.1)); + UNIT_ASSERT_DOUBLES_EQUAL(nan, nan, 0.1); } Y_UNIT_TEST(StringsEqual) { diff --git a/library/cpp/timezone_conversion/README.md b/library/cpp/timezone_conversion/README.md index 828f1880bc..631579c60b 100644 --- a/library/cpp/timezone_conversion/README.md +++ b/library/cpp/timezone_conversion/README.md @@ -1,25 +1,25 @@ A library for translating between absolute times (i.e., `TInstant`) and civil times (i.e., `NDatetime::TSimpleTM`) using the rules defined by a time zone (i.e., `NDatetime::TTimeZone`). - + (the terms `absolute` and `civil` come from [cctz#fundamental-concepts][cctz-fundamental-concepts]) - + This is basically a wrapper around [CCTZ][cctz] with one important change: the time zone database is in Arcadia and is compiled with the library (which means your executable will end up ~2MB larger). - + See [contrib/libs/cctz/README][update] if you think zone database is outdated. -Quick start: -============ +Quick start: +============ ``` #include <library/cpp/timezone_conversion/convert.h> - -// NDatetime::{GetLocalTimeZone(),GetUtcTimeZone()} are also available. -NDatetime::TTimeZone msk = NDatetime::GetTimeZone("Europe/Moscow"); -TInstant now = TInstant::Now(); -NDatetime::TSimpleTM civil = NDatetime::ToCivilTime(now, msk); -Cout << "Local time in Moscow is " << civil.ToString() << Endl; -TInstant absolute = NDatetime::ToAbsoluteTime(civil, msk); -Cout << "The current UNIX time is " << absolute.Seconds() << Endl; + +// NDatetime::{GetLocalTimeZone(),GetUtcTimeZone()} are also available. +NDatetime::TTimeZone msk = NDatetime::GetTimeZone("Europe/Moscow"); +TInstant now = TInstant::Now(); +NDatetime::TSimpleTM civil = NDatetime::ToCivilTime(now, msk); +Cout << "Local time in Moscow is " << civil.ToString() << Endl; +TInstant absolute = NDatetime::ToAbsoluteTime(civil, msk); +Cout << "The current UNIX time is " << absolute.Seconds() << Endl; ``` [cctz-fundamental-concepts]: https://github.com/google/cctz#fundamental-concepts diff --git a/library/cpp/timezone_conversion/convert.cpp b/library/cpp/timezone_conversion/convert.cpp index 490bb4e270..5f489a2222 100644 --- a/library/cpp/timezone_conversion/convert.cpp +++ b/library/cpp/timezone_conversion/convert.cpp @@ -1,16 +1,16 @@ -#include "convert.h" - +#include "convert.h" + #include <contrib/libs/cctz/include/cctz/civil_time.h> -#include <util/generic/yexception.h> - -#include <chrono> - -namespace NDatetime { - static constexpr i64 TM_YEAR_OFFSET = 1900; - using TSystemClock = std::chrono::system_clock; +#include <util/generic/yexception.h> + +#include <chrono> + +namespace NDatetime { + static constexpr i64 TM_YEAR_OFFSET = 1900; + using TSystemClock = std::chrono::system_clock; using TTimePoint = std::chrono::time_point<TSystemClock>; - + static TSimpleTM CivilToTM(const cctz::civil_second& cs, const cctz::time_zone::absolute_lookup& al) { cctz::civil_day cd(cs); TSimpleTM tm; @@ -54,33 +54,33 @@ namespace NDatetime { /* TTimeZone GetTimeZone(const TString& name) { - TTimeZone result; + TTimeZone result; if (!cctz::load_time_zone(name, &result)) { ythrow yexception() << "Failed to load time zone " << name << ", " << result.name(); - } - return result; - } + } + return result; + } */ - - TTimeZone GetUtcTimeZone() { + + TTimeZone GetUtcTimeZone() { return cctz::utc_time_zone(); - } - - TTimeZone GetLocalTimeZone() { + } + + TTimeZone GetLocalTimeZone() { return cctz::local_time_zone(); - } - - TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz) { + } + + TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz) { TTimePoint tp = TSystemClock::from_time_t(absoluteTime.TimeT()); return CivilToTM(cctz::convert(tp, tz), tz.lookup(tp)); } - + TSimpleTM CreateCivilTime(const TTimeZone& tz, ui32 year, ui32 mon, ui32 day, ui32 h, ui32 m, ui32 s) { cctz::civil_second cs(year, mon, day, h, m, s); return CivilToTM(cs, tz.lookup(tz.lookup(cs).pre)); - } - - TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz) { + } + + TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz) { cctz::civil_second cs( civilTime.Year + TM_YEAR_OFFSET, civilTime.Mon + 1, @@ -89,5 +89,5 @@ namespace NDatetime { civilTime.Min, civilTime.Sec); return TInstant::Seconds(TSystemClock::to_time_t(tz.lookup(cs).pre)); - } -} + } +} diff --git a/library/cpp/timezone_conversion/convert.h b/library/cpp/timezone_conversion/convert.h index 768a9e110f..404650817c 100644 --- a/library/cpp/timezone_conversion/convert.h +++ b/library/cpp/timezone_conversion/convert.h @@ -1,36 +1,36 @@ -#pragma once - +#pragma once + #include "civil.h" #include <contrib/libs/cctz/include/cctz/time_zone.h> -#include <util/datetime/base.h> -#include <util/draft/datetime.h> - -namespace NDatetime { - /** - * @return The mother of all time zones. - * @see https://en.wikipedia.org/wiki/Coordinated_Universal_Time - */ - TTimeZone GetUtcTimeZone(); - - /** - * @return The time zone that is curently set on your machine. - */ - TTimeZone GetLocalTimeZone(); - - /** - * @param absoluteTime A TInstant representing a number of seconds elapsed - * since The Epoch (the microsecond part is ignored). - * @param tz The time zone to use for conversion. - * @return The civil time corresponding to absoluteTime. - * @note This conversion is always well-defined (i.e., there - * is exactly one civil time which corresponds to - * absoluteTime). - * @see https://en.wikipedia.org/wiki/Unix_time - */ - TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz); - - /** +#include <util/datetime/base.h> +#include <util/draft/datetime.h> + +namespace NDatetime { + /** + * @return The mother of all time zones. + * @see https://en.wikipedia.org/wiki/Coordinated_Universal_Time + */ + TTimeZone GetUtcTimeZone(); + + /** + * @return The time zone that is curently set on your machine. + */ + TTimeZone GetLocalTimeZone(); + + /** + * @param absoluteTime A TInstant representing a number of seconds elapsed + * since The Epoch (the microsecond part is ignored). + * @param tz The time zone to use for conversion. + * @return The civil time corresponding to absoluteTime. + * @note This conversion is always well-defined (i.e., there + * is exactly one civil time which corresponds to + * absoluteTime). + * @see https://en.wikipedia.org/wiki/Unix_time + */ + TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz); + + /** * Creates civil time in place with respect of given timezone. * @param[in] tz The time zone to use for creation. * @param[in] year The year of the creation time. @@ -44,17 +44,17 @@ namespace NDatetime { TSimpleTM CreateCivilTime(const TTimeZone& tz, ui32 year, ui32 mon, ui32 day, ui32 h = 0, ui32 m = 0, ui32 s = 0); /** - * @param civilTime A human-readable date and time (the following fields - * are used by this function: {Year,Mon,MDay,Hour,Min,Sec}). - * @param tz The time zone to use for conversion. - * @return Some absolute time corresponding to civilTime. - * @note If multiple absolute times match civilTime, the earliest - * if returned. - * If civilTime doesn't exist due to discontinuity in time - * (e.g., DST happened) we pretend the discontinuity isn't - * there (i.e., if we skipped from 1:59AM to 3:00AM then - * ToAbsoluteTime(2:30AM) == ToAbsoluteTime(3:30AM)). - * @see https://en.wikipedia.org/wiki/Daylight_saving_time - */ - TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz); -} + * @param civilTime A human-readable date and time (the following fields + * are used by this function: {Year,Mon,MDay,Hour,Min,Sec}). + * @param tz The time zone to use for conversion. + * @return Some absolute time corresponding to civilTime. + * @note If multiple absolute times match civilTime, the earliest + * if returned. + * If civilTime doesn't exist due to discontinuity in time + * (e.g., DST happened) we pretend the discontinuity isn't + * there (i.e., if we skipped from 1:59AM to 3:00AM then + * ToAbsoluteTime(2:30AM) == ToAbsoluteTime(3:30AM)). + * @see https://en.wikipedia.org/wiki/Daylight_saving_time + */ + TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz); +} diff --git a/library/cpp/timezone_conversion/ut/convert_ut.cpp b/library/cpp/timezone_conversion/ut/convert_ut.cpp index bbf9e9b826..91ad67673f 100644 --- a/library/cpp/timezone_conversion/ut/convert_ut.cpp +++ b/library/cpp/timezone_conversion/ut/convert_ut.cpp @@ -1,139 +1,139 @@ #include <library/cpp/timezone_conversion/convert.h> #include <library/cpp/testing/unittest/gtest.h> - -using namespace NDatetime; - -template <> + +using namespace NDatetime; + +template <> void Out<TSimpleTM>(IOutputStream& os, TTypeTraits<TSimpleTM>::TFuncParam value) { - os << value.ToString() << ", dst: " << int(value.IsDst); -} - -TSimpleTM ZonedTm(i32 utcHours, bool isDst, ui32 year, ui32 mon, ui32 day, ui32 h, ui32 m, ui32 s) { - TSimpleTM res(year, mon, day, h, m, s); - res.GMTOff = utcHours * 60 * 60; - res.IsDst = isDst; - return res; -} - -void CompareCivilTimes(const TSimpleTM& expected, const TSimpleTM& actual) { - EXPECT_EQ(expected.GMTOff, actual.GMTOff); - EXPECT_EQ(expected.Year, actual.Year); - EXPECT_EQ(expected.Mon, actual.Mon); - EXPECT_EQ(expected.MDay, actual.MDay); - EXPECT_EQ(expected.WDay, actual.WDay); - EXPECT_EQ(expected.Hour, actual.Hour); - EXPECT_EQ(expected.Min, actual.Min); - EXPECT_EQ(expected.Sec, actual.Sec); - EXPECT_EQ(expected.IsDst, actual.IsDst); - EXPECT_EQ(expected.IsLeap, actual.IsLeap); -} - -#define CHECK_ROUND_TRIP(tz, unixTime, civil) \ + os << value.ToString() << ", dst: " << int(value.IsDst); +} + +TSimpleTM ZonedTm(i32 utcHours, bool isDst, ui32 year, ui32 mon, ui32 day, ui32 h, ui32 m, ui32 s) { + TSimpleTM res(year, mon, day, h, m, s); + res.GMTOff = utcHours * 60 * 60; + res.IsDst = isDst; + return res; +} + +void CompareCivilTimes(const TSimpleTM& expected, const TSimpleTM& actual) { + EXPECT_EQ(expected.GMTOff, actual.GMTOff); + EXPECT_EQ(expected.Year, actual.Year); + EXPECT_EQ(expected.Mon, actual.Mon); + EXPECT_EQ(expected.MDay, actual.MDay); + EXPECT_EQ(expected.WDay, actual.WDay); + EXPECT_EQ(expected.Hour, actual.Hour); + EXPECT_EQ(expected.Min, actual.Min); + EXPECT_EQ(expected.Sec, actual.Sec); + EXPECT_EQ(expected.IsDst, actual.IsDst); + EXPECT_EQ(expected.IsLeap, actual.IsLeap); +} + +#define CHECK_ROUND_TRIP(tz, unixTime, civil) \ EXPECT_EQ( \ TInstant::Seconds(unixTime), \ ToAbsoluteTime(civil, tz)); \ - CompareCivilTimes( \ + CompareCivilTimes( \ civil, \ - ToCivilTime(TInstant::Seconds(unixTime), tz)); - -// Tests only unambiguous civil times (i.e., those that occurred exactly once). -TEST(TimeZoneConversion, Simple) { - TTimeZone msk = GetTimeZone("Europe/Moscow"); - // Before and after the temporary switch to UTC+3 in 2010. - CHECK_ROUND_TRIP( + ToCivilTime(TInstant::Seconds(unixTime), tz)); + +// Tests only unambiguous civil times (i.e., those that occurred exactly once). +TEST(TimeZoneConversion, Simple) { + TTimeZone msk = GetTimeZone("Europe/Moscow"); + // Before and after the temporary switch to UTC+3 in 2010. + CHECK_ROUND_TRIP( msk, 1288475999, ZonedTm(+4, true, 2010, 10, 31, 1, 59, 59)); - CHECK_ROUND_TRIP( + CHECK_ROUND_TRIP( msk, 1288475999 + 3 * 60 * 60, ZonedTm(+3, false, 2010, 10, 31, 3, 59, 59)); - - // Before and after the permanent switch to UTC+4 in 2011. - CHECK_ROUND_TRIP( + + // Before and after the permanent switch to UTC+4 in 2011. + CHECK_ROUND_TRIP( msk, 1301180399, ZonedTm(+3, false, 2011, 3, 27, 1, 59, 59)); - CHECK_ROUND_TRIP( + CHECK_ROUND_TRIP( msk, 1301180399 + 60 * 60, ZonedTm(+4, false, 2011, 3, 27, 3, 59, 59)); - - // Some random moment between 2011 and 2014 when UTC+4 (no DST) was in place. - CHECK_ROUND_TRIP( + + // Some random moment between 2011 and 2014 when UTC+4 (no DST) was in place. + CHECK_ROUND_TRIP( msk, 1378901234, ZonedTm(+4, false, 2013, 9, 11, 16, 7, 14)); - - // As of right now (i.e., as I'm writing this) Moscow is in UTC+3 (no DST). - CHECK_ROUND_TRIP( + + // As of right now (i.e., as I'm writing this) Moscow is in UTC+3 (no DST). + CHECK_ROUND_TRIP( msk, 1458513396, ZonedTm(+3, false, 2016, 3, 21, 1, 36, 36)); - - // Please add a new test if the current president moves Moscow back to UTC+4 - // or introduces DST again. -} - -TEST(TimeZoneConversion, TestRepeatedDate) { - TTimeZone ekb = GetTimeZone("Asia/Yekaterinburg"); - - CompareCivilTimes( - ZonedTm(+6, true, 2010, 10, 31, 2, 30, 0), - ToCivilTime(TInstant::Seconds(1288470600), ekb)); - - CompareCivilTimes( - ZonedTm(+5, false, 2010, 10, 31, 2, 30, 0), - ToCivilTime(TInstant::Seconds(1288474200), ekb)); - - CompareCivilTimes( + + // Please add a new test if the current president moves Moscow back to UTC+4 + // or introduces DST again. +} + +TEST(TimeZoneConversion, TestRepeatedDate) { + TTimeZone ekb = GetTimeZone("Asia/Yekaterinburg"); + + CompareCivilTimes( + ZonedTm(+6, true, 2010, 10, 31, 2, 30, 0), + ToCivilTime(TInstant::Seconds(1288470600), ekb)); + + CompareCivilTimes( + ZonedTm(+5, false, 2010, 10, 31, 2, 30, 0), + ToCivilTime(TInstant::Seconds(1288474200), ekb)); + + CompareCivilTimes( ZonedTm(+5, false, 2016, 5, 10, 9, 8, 7), CreateCivilTime(ekb, 2016, 5, 10, 9, 8, 7)); - CompareCivilTimes( + CompareCivilTimes( ZonedTm(+6, true, 2010, 10, 31, 2, 30, 0), CreateCivilTime(ekb, 2010, 10, 31, 2, 30, 0)); - // The earlier timestamp should be chosen. - EXPECT_EQ( - TInstant::Seconds(1288470600), - ToAbsoluteTime(TSimpleTM(2010, 10, 31, 2, 30, 0), ekb)); -} - -TEST(TimeZoneConversion, TestSkippedDate) { - TTimeZone nsk = GetTimeZone("Asia/Novosibirsk"); - - CompareCivilTimes( - ZonedTm(+6, false, 2011, 3, 27, 1, 30, 0), - ToCivilTime(TInstant::Seconds(1301167800), nsk)); - - CompareCivilTimes( - ZonedTm(+7, false, 2011, 3, 27, 3, 30, 0), - ToCivilTime(TInstant::Seconds(1301171400), nsk)); - - EXPECT_EQ( - TInstant::Seconds(1301171400), - ToAbsoluteTime(TSimpleTM(2011, 3, 27, 2, 30, 0), nsk)); - - EXPECT_EQ( - TInstant::Seconds(1301171400), - ToAbsoluteTime(TSimpleTM(2011, 3, 27, 3, 30, 0), nsk)); -} - -TEST(TimeZoneConversion, Utc) { - CHECK_ROUND_TRIP( + // The earlier timestamp should be chosen. + EXPECT_EQ( + TInstant::Seconds(1288470600), + ToAbsoluteTime(TSimpleTM(2010, 10, 31, 2, 30, 0), ekb)); +} + +TEST(TimeZoneConversion, TestSkippedDate) { + TTimeZone nsk = GetTimeZone("Asia/Novosibirsk"); + + CompareCivilTimes( + ZonedTm(+6, false, 2011, 3, 27, 1, 30, 0), + ToCivilTime(TInstant::Seconds(1301167800), nsk)); + + CompareCivilTimes( + ZonedTm(+7, false, 2011, 3, 27, 3, 30, 0), + ToCivilTime(TInstant::Seconds(1301171400), nsk)); + + EXPECT_EQ( + TInstant::Seconds(1301171400), + ToAbsoluteTime(TSimpleTM(2011, 3, 27, 2, 30, 0), nsk)); + + EXPECT_EQ( + TInstant::Seconds(1301171400), + ToAbsoluteTime(TSimpleTM(2011, 3, 27, 3, 30, 0), nsk)); +} + +TEST(TimeZoneConversion, Utc) { + CHECK_ROUND_TRIP( GetUtcTimeZone(), 1451703845, ZonedTm(0, false, 2016, 1, 2, 3, 4, 5)); -} - -TEST(TimeZoneConversion, Local) { - TTimeZone local = GetLocalTimeZone(); - auto nowAbsolute = TInstant::Now(); - auto nowCivilLocal = ToCivilTime(nowAbsolute, local); - EXPECT_EQ(nowAbsolute.Seconds(), ToAbsoluteTime(nowCivilLocal, local).Seconds()); -} - +} + +TEST(TimeZoneConversion, Local) { + TTimeZone local = GetLocalTimeZone(); + auto nowAbsolute = TInstant::Now(); + auto nowCivilLocal = ToCivilTime(nowAbsolute, local); + EXPECT_EQ(nowAbsolute.Seconds(), ToAbsoluteTime(nowCivilLocal, local).Seconds()); +} + TEST(TimeZoneConversion, BeforeEpoch) { { //NOTE: This test will not work because NDatetime::Convert() with TInstant does not work properly for dates before 1/1/1970 @@ -150,42 +150,42 @@ TEST(TimeZoneConversion, BeforeEpoch) { } -TEST(TimeZoneConversion, InvalidTimeZone) { - EXPECT_THROW(GetTimeZone("Europe/Mscow"), yexception); - EXPECT_THROW(GetTimeZone(""), yexception); -} - -TEST(TimeZoneConversion, TestSaratov) { - TTimeZone saratov = GetTimeZone("Europe/Saratov"); - - CompareCivilTimes( - ZonedTm(+4, false, 2016, 12, 5, 1, 55, 35), - ToCivilTime(TInstant::Seconds(1480888535), saratov)); - - CompareCivilTimes( - ZonedTm(+3, false, 2016, 12, 1, 0, 55, 35), - ToCivilTime(TInstant::Seconds(1480542935), saratov)); -} - -TEST(TimeZoneConversion, TestFutureDstChanges) { - TTimeZone london = GetTimeZone("Europe/London"); - - // This test assumes the British won't cancel DST before 2025. - // I don't think they will, but then again, nobody really expected Brexit. - - // DST is still in effect in early October 2025, meaning we are in UTC+1. - CHECK_ROUND_TRIP( - london, - 1760124660, - ZonedTm(+1, true, 2025, 10, 10, 20, 31, 0)); - - // 31 days later we're back to UTC+0 again. - CHECK_ROUND_TRIP( - london, +TEST(TimeZoneConversion, InvalidTimeZone) { + EXPECT_THROW(GetTimeZone("Europe/Mscow"), yexception); + EXPECT_THROW(GetTimeZone(""), yexception); +} + +TEST(TimeZoneConversion, TestSaratov) { + TTimeZone saratov = GetTimeZone("Europe/Saratov"); + + CompareCivilTimes( + ZonedTm(+4, false, 2016, 12, 5, 1, 55, 35), + ToCivilTime(TInstant::Seconds(1480888535), saratov)); + + CompareCivilTimes( + ZonedTm(+3, false, 2016, 12, 1, 0, 55, 35), + ToCivilTime(TInstant::Seconds(1480542935), saratov)); +} + +TEST(TimeZoneConversion, TestFutureDstChanges) { + TTimeZone london = GetTimeZone("Europe/London"); + + // This test assumes the British won't cancel DST before 2025. + // I don't think they will, but then again, nobody really expected Brexit. + + // DST is still in effect in early October 2025, meaning we are in UTC+1. + CHECK_ROUND_TRIP( + london, + 1760124660, + ZonedTm(+1, true, 2025, 10, 10, 20, 31, 0)); + + // 31 days later we're back to UTC+0 again. + CHECK_ROUND_TRIP( + london, 1760124660 + 31 * 24 * 60 * 60, - ZonedTm(+0, false, 2025, 11, 10, 19, 31, 0)); -} - + ZonedTm(+0, false, 2025, 11, 10, 19, 31, 0)); +} + TEST(TimeZoneConversion, TWDay) { TTimeZone nsk = GetTimeZone("Asia/Novosibirsk"); @@ -193,12 +193,12 @@ TEST(TimeZoneConversion, TWDay) { EXPECT_EQ(dow, ToCivilTime(TInstant::Seconds(e), nsk).WDay); } } - -TEST(TimeZoneConversion, TestBaikonur) { - // Yes, the Baikonur spaceport is located in Kyzylorda Region. - const auto baikonur = GetTimeZone("Asia/Qyzylorda"); - - CompareCivilTimes( - ZonedTm(+5, false, 2019, 1, 11, 23, 55, 23), - ToCivilTime(TInstant::Seconds(1547232923), baikonur)); -} + +TEST(TimeZoneConversion, TestBaikonur) { + // Yes, the Baikonur spaceport is located in Kyzylorda Region. + const auto baikonur = GetTimeZone("Asia/Qyzylorda"); + + CompareCivilTimes( + ZonedTm(+5, false, 2019, 1, 11, 23, 55, 23), + ToCivilTime(TInstant::Seconds(1547232923), baikonur)); +} diff --git a/library/cpp/timezone_conversion/ut/ya.make b/library/cpp/timezone_conversion/ut/ya.make index 781a57da9f..02862ae62b 100644 --- a/library/cpp/timezone_conversion/ut/ya.make +++ b/library/cpp/timezone_conversion/ut/ya.make @@ -1,15 +1,15 @@ -UNITTEST() - -OWNER(dfyz) - -PEERDIR( +UNITTEST() + +OWNER(dfyz) + +PEERDIR( library/cpp/testing/unittest library/cpp/timezone_conversion -) - -SRCS( - convert_ut.cpp +) + +SRCS( + convert_ut.cpp civil_ut.cpp -) - -END() +) + +END() diff --git a/library/cpp/timezone_conversion/ya.make b/library/cpp/timezone_conversion/ya.make index f99ebe73ee..c40e45d044 100644 --- a/library/cpp/timezone_conversion/ya.make +++ b/library/cpp/timezone_conversion/ya.make @@ -1,22 +1,22 @@ -LIBRARY() - +LIBRARY() + OWNER( dfyz petrk ) - -PEERDIR( - contrib/libs/cctz/tzdata - util/draft -) - -SRCS( - convert.cpp + +PEERDIR( + contrib/libs/cctz/tzdata + util/draft +) + +SRCS( + convert.cpp civil.cpp -) - +) + GENERATE_ENUM_SERIALIZATION(civil.h) -END() +END() RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/uri/uri_ut.cpp b/library/cpp/uri/uri_ut.cpp index 2ebd83fc93..8e0c682a4f 100644 --- a/library/cpp/uri/uri_ut.cpp +++ b/library/cpp/uri/uri_ut.cpp @@ -127,7 +127,7 @@ namespace NUri { {"http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8", "http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8/1024", "http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8/1024", TUri::LinkIsLocal}, {nullptr, nullptr, nullptr, TUri::LinkIsBad}, }; - + Y_UNIT_TEST(test_httpURLNormalize) { TUri normalizedLink; |