civil_ut.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #include <library/cpp/timezone_conversion/civil.h>
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <library/cpp/testing/unittest/tests_data.h>
  4. #include <util/stream/str.h>
  5. namespace NDatetime {
  6. inline bool operator==(const NDatetime::TCivilDiff& x, const NDatetime::TCivilDiff& y) {
  7. return x.Unit == y.Unit && x.Value == y.Value;
  8. }
  9. }
  10. template <>
  11. inline void Out<NDatetime::TCivilDiff>(IOutputStream& out, const NDatetime::TCivilDiff& diff) {
  12. out << "(" << diff.Value << "," << diff.Unit << ")";
  13. }
  14. Y_UNIT_TEST_SUITE(DateTime) {
  15. Y_UNIT_TEST(Calc) {
  16. NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
  17. UNIT_ASSERT_VALUES_EQUAL(NDatetime::Calc<NDatetime::TCivilDay>(s, 2), NDatetime::TCivilDay(2017, 2, 3));
  18. UNIT_ASSERT_VALUES_EQUAL(NDatetime::Calc<NDatetime::TCivilDay>(s, -2), NDatetime::TCivilDay(2017, 1, 30));
  19. }
  20. Y_UNIT_TEST(Adds) {
  21. NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
  22. UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddDays(s, 2), NDatetime::TCivilSecond(2017, 2, 3, 10, 12, 9));
  23. UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddMonths(s, -2), NDatetime::TCivilSecond(2016, 12, 1, 10, 12, 9));
  24. UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddYears(s, -55), NDatetime::TCivilSecond(1962, 2, 1, 10, 12, 9));
  25. UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddHours(s, 40), NDatetime::TCivilSecond(2017, 2, 3, 2, 12, 9));
  26. }
  27. Y_UNIT_TEST(Convert) {
  28. TInstant absTime = TInstant::Seconds(1500299239);
  29. NDatetime::TTimeZone lax = NDatetime::GetTimeZone("America/Los_Angeles");
  30. NDatetime::TCivilSecond dt1 = NDatetime::Convert(absTime, lax);
  31. NDatetime::TCivilSecond dt2(2017, 7, 17, 6, 47, 19);
  32. UNIT_ASSERT_VALUES_EQUAL(dt1, dt2);
  33. UNIT_ASSERT_VALUES_EQUAL(absTime, NDatetime::Convert(dt2, lax));
  34. UNIT_ASSERT_EXCEPTION(NDatetime::Convert(absTime, "Unknown time zone"), NDatetime::TInvalidTimezone);
  35. }
  36. Y_UNIT_TEST(UTCOffsetTimezone) {
  37. NDatetime::TTimeZone lax = NDatetime::GetTimeZone("UTC+12");
  38. auto lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  39. UNIT_ASSERT_VALUES_EQUAL(12 * 60 * 60, lookup.offset);
  40. lax = NDatetime::GetTimeZone("UTC-10");
  41. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  42. UNIT_ASSERT_VALUES_EQUAL(-10 * 60 * 60, lookup.offset);
  43. lax = NDatetime::GetTimeZone("UTC");
  44. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  45. UNIT_ASSERT_VALUES_EQUAL(0, lookup.offset);
  46. lax = NDatetime::GetTimeZone("UTC+0");
  47. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  48. UNIT_ASSERT_VALUES_EQUAL(0, lookup.offset);
  49. lax = NDatetime::GetTimeZone("UTC-2");
  50. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  51. UNIT_ASSERT_VALUES_EQUAL(-2 * 60 * 60, lookup.offset);
  52. lax = NDatetime::GetTimeZone("UTC-00:30");
  53. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  54. UNIT_ASSERT_VALUES_EQUAL(-30 * 60, lookup.offset);
  55. lax = NDatetime::GetTimeZone("UTC-0241");
  56. lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
  57. UNIT_ASSERT_VALUES_EQUAL(-(2 * 60 + 41) * 60, lookup.offset);
  58. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTCUnknown"), NDatetime::TInvalidTimezone);
  59. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+:"), NDatetime::TInvalidTimezone);
  60. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+24:01"), NDatetime::TInvalidTimezone);
  61. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:"), NDatetime::TInvalidTimezone);
  62. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:60"), NDatetime::TInvalidTimezone);
  63. UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:30:"), NDatetime::TInvalidTimezone);
  64. }
  65. Y_UNIT_TEST(ParseOffset) {
  66. int offset;
  67. UNIT_ASSERT(!NDatetime::TryParseOffset("Unknown", offset));
  68. UNIT_ASSERT(!NDatetime::TryParseOffset("+:", offset));
  69. UNIT_ASSERT(!NDatetime::TryParseOffset("+24:01", offset));
  70. UNIT_ASSERT(!NDatetime::TryParseOffset("+20:", offset));
  71. UNIT_ASSERT(!NDatetime::TryParseOffset("+20:60", offset));
  72. UNIT_ASSERT(!NDatetime::TryParseOffset("+20:30:", offset));
  73. UNIT_ASSERT(NDatetime::TryParseOffset("+03", offset));
  74. UNIT_ASSERT_VALUES_EQUAL(offset, 10800);
  75. UNIT_ASSERT(NDatetime::TryParseOffset("-10", offset));
  76. UNIT_ASSERT_VALUES_EQUAL(offset, -36000);
  77. UNIT_ASSERT(NDatetime::TryParseOffset("+01:00", offset));
  78. UNIT_ASSERT_VALUES_EQUAL(offset, 3600);
  79. UNIT_ASSERT(NDatetime::TryParseOffset("-11:30", offset));
  80. UNIT_ASSERT_VALUES_EQUAL(offset, -41400);
  81. UNIT_ASSERT(NDatetime::TryParseOffset("+0130", offset));
  82. UNIT_ASSERT_VALUES_EQUAL(offset, 5400);
  83. UNIT_ASSERT(NDatetime::TryParseOffset("-0200", offset));
  84. UNIT_ASSERT_VALUES_EQUAL(offset, -7200);
  85. }
  86. Y_UNIT_TEST(Format) {
  87. NDatetime::TTimeZone lax = NDatetime::GetTimeZone("America/Los_Angeles");
  88. NDatetime::TCivilSecond tp(2013, 1, 2, 3, 4, 5);
  89. UNIT_ASSERT_VALUES_EQUAL(NDatetime::Format("%H:%M:%S", tp, lax), "03:04:05");
  90. UNIT_ASSERT_VALUES_EQUAL(NDatetime::Format("%H:%M:%E3S", tp, lax), "03:04:05.000");
  91. }
  92. Y_UNIT_TEST(Weekday) {
  93. NDatetime::TCivilDay d(2013, 1, 2);
  94. NDatetime::TWeekday wd = NDatetime::GetWeekday(d);
  95. UNIT_ASSERT_VALUES_EQUAL(wd, NDatetime::TWeekday::wednesday);
  96. UNIT_ASSERT_VALUES_EQUAL(NDatetime::NextWeekday(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2013, 1, 7));
  97. UNIT_ASSERT_VALUES_EQUAL(NDatetime::PrevWeekday(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2012, 12, 31));
  98. UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2012, 12, 31));
  99. UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::wednesday), NDatetime::TCivilDay(2013, 1, 2));
  100. UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::friday), NDatetime::TCivilDay(2013, 1, 4));
  101. }
  102. Y_UNIT_TEST(WeekdayFromCivilSecond) {
  103. NDatetime::TCivilSecond s(2013, 1, 2, 10, 12, 9);
  104. NDatetime::TWeekday wd = NDatetime::GetWeekday(s);
  105. UNIT_ASSERT_VALUES_EQUAL(wd, NDatetime::TWeekday::wednesday);
  106. }
  107. Y_UNIT_TEST(CivilUnit) {
  108. using namespace NDatetime;
  109. UNIT_ASSERT_VALUES_EQUAL(GetCivilUnit<TCivilMonth>(), ECivilUnit::Month);
  110. UNIT_ASSERT_VALUES_EQUAL(GetCivilUnit(TCivilHour{}), ECivilUnit::Hour);
  111. UNIT_ASSERT_VALUES_EQUAL(TCivilTime<ECivilUnit::Day>(2017, 1, 11), TCivilDay(2017, 1, 11));
  112. NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
  113. UNIT_ASSERT_VALUES_EQUAL(
  114. NDatetime::AddCivil(s, TCivilDiff{2, ECivilUnit::Day}),
  115. NDatetime::AddDays(s, 2));
  116. UNIT_ASSERT_VALUES_EQUAL(
  117. NDatetime::AddCivil(s, TCivilDiff{-2, ECivilUnit::Month}),
  118. NDatetime::AddMonths(s, -2));
  119. UNIT_ASSERT_VALUES_EQUAL(
  120. NDatetime::AddCivil(s, TCivilDiff{-55, ECivilUnit::Year}),
  121. NDatetime::AddYears(s, -55));
  122. UNIT_ASSERT_VALUES_EQUAL(
  123. NDatetime::AddCivil(s, TCivilDiff{40, ECivilUnit::Hour}),
  124. NDatetime::AddHours(s, 40));
  125. UNIT_ASSERT_VALUES_EQUAL(
  126. GetCivilDiff(TCivilSecond(2017, 10), TCivilSecond(2017, 7), ECivilUnit::Month),
  127. TCivilDiff(3, ECivilUnit::Month));
  128. UNIT_ASSERT_VALUES_EQUAL(
  129. GetCivilDiff(TCivilSecond(2017, 10, 1), TCivilSecond(2017, 9, 30), ECivilUnit::Month),
  130. TCivilDiff(1, ECivilUnit::Month));
  131. UNIT_ASSERT_VALUES_EQUAL(
  132. GetCivilDiff(TCivilSecond(2017, 10, 1), TCivilSecond(2017, 9, 31), ECivilUnit::Month),
  133. TCivilDiff(0, ECivilUnit::Month));
  134. }
  135. Y_UNIT_TEST(TestYearWeekNmb) {
  136. // YEAR 2021 - start from Friday, first dates (1-3) will have week# 0
  137. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 1}), 0);
  138. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 2}), 0);
  139. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 3}), 0);
  140. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 4}), 1);
  141. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 1}, true), 53);
  142. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 2}, true), 53);
  143. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 3}, true), 53);
  144. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 4}, true), 54);
  145. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 2, 28}), 8);
  146. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 2, 29}), 9); // <- this is invalid date, should be normalized to March 1
  147. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 3, 1}), 9);
  148. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 26}), 51);
  149. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 27}), 52);
  150. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 31}), 52);
  151. // YEAR 2020 - start from Wednesday, all dates start from week# 1
  152. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 1}), 1);
  153. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 5}), 1);
  154. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 6}), 2);
  155. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 2, 28}), 9);
  156. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 2, 29}), 9);
  157. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 3, 1}), 9);
  158. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 3, 2}), 10);
  159. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 12, 31}), 53);
  160. // Max possible delta - calcuate week # for 31 Dec 2021 from 1 Jan 2020
  161. UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 31}, true), 105);
  162. }
  163. }