datetime.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #pragma once
  2. #include <yql/essentials/public/udf/udf_value_builder.h>
  3. #include <yql/essentials/public/udf/tz/udf_tz.h>
  4. #include <yql/essentials/minikql/mkql_type_ops.h>
  5. #include <util/datetime/base.h>
  6. #include <util/string/printf.h>
  7. namespace NYql::DateTime {
  8. constexpr size_t MAX_TIMEZONE_NAME_LEN = 64;
  9. struct TTMStorage {
  10. unsigned int Year : 12;
  11. unsigned int DayOfYear : 9;
  12. unsigned int WeekOfYear : 6;
  13. unsigned int WeekOfYearIso8601 : 6;
  14. unsigned int DayOfWeek : 3;
  15. unsigned int Month : 4;
  16. unsigned int Day : 5;
  17. unsigned int Hour : 5;
  18. unsigned int Minute : 6;
  19. unsigned int Second : 6;
  20. unsigned int Microsecond : 20;
  21. unsigned int TimezoneId : 16;
  22. TTMStorage() {
  23. Zero(*this);
  24. }
  25. inline static bool IsUniversal(ui16 timezoneId) {
  26. return timezoneId == 0;
  27. }
  28. inline void MakeDefault() {
  29. Year = 1970;
  30. Month = 1;
  31. Day = 1;
  32. Hour = 0;
  33. Minute = 0;
  34. Second = 0;
  35. Microsecond = 0;
  36. TimezoneId = 0;
  37. }
  38. inline void FromDate(const NUdf::IDateBuilder& builder, ui16 value, ui16 timezoneId = 0) {
  39. ui32 year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
  40. if (!builder.FullSplitDate2(value, year, month, day, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) {
  41. ythrow yexception() << "Error in FullSplitDate";
  42. }
  43. TimezoneId = timezoneId;
  44. Year = year;
  45. Month = month;
  46. Day = day;
  47. DayOfYear = dayOfYear;
  48. WeekOfYear = weekOfYear;
  49. WeekOfYearIso8601 = weekOfYearIso8601;
  50. DayOfWeek = dayOfWeek;
  51. }
  52. inline ui16 ToDate(const NUdf::IDateBuilder& builder, bool local) const {
  53. if (!IsUniversal(TimezoneId)) {
  54. ui32 datetime;
  55. if (!builder.MakeDatetime(Year, Month, Day, local ? 0 : Hour, local ? 0 : Minute, local ? 0 : Second, datetime, TimezoneId)) {
  56. ythrow yexception() << "Error in MakeDatetime";
  57. }
  58. return datetime / 86400u;
  59. } else {
  60. ui16 date;
  61. if (!builder.MakeDate(Year, Month, Day, date)) {
  62. ythrow yexception() << "Error in MakeDate";
  63. }
  64. return date;
  65. }
  66. }
  67. inline void FromDatetime(const NUdf::IDateBuilder& builder, ui32 value, ui16 timezoneId = 0) {
  68. ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
  69. if (!builder.FullSplitDatetime2(value, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, timezoneId)) {
  70. ythrow yexception() << "Error in FullSplitDatetime";
  71. }
  72. TimezoneId = timezoneId;
  73. Year = year;
  74. Month = month;
  75. Day = day;
  76. Hour = hour;
  77. Minute = minute;
  78. Second = second;
  79. DayOfYear = dayOfYear;
  80. WeekOfYear = weekOfYear;
  81. WeekOfYearIso8601 = weekOfYearIso8601;
  82. DayOfWeek = dayOfWeek;
  83. }
  84. inline ui32 ToDatetime(const NUdf::IDateBuilder& builder) const {
  85. ui32 datetime = 0;
  86. if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) {
  87. ythrow yexception() << "Error in MakeDatetime";
  88. }
  89. return datetime;
  90. }
  91. inline void FromTimestamp(const NUdf::IDateBuilder& builder, ui64 value, ui16 timezoneId = 0) {
  92. const ui32 seconds = value / 1000000ull;
  93. FromDatetime(builder, seconds, timezoneId);
  94. Microsecond = value - seconds * 1000000ull;
  95. }
  96. inline ui64 ToTimestamp(const NUdf::IDateBuilder& builder) const {
  97. return ToDatetime(builder) * 1000000ull + Microsecond;
  98. }
  99. inline bool Validate(const NUdf::IDateBuilder& builder) {
  100. ui32 datetime;
  101. if (!builder.MakeDatetime(Year, Month, Day, Hour, Minute, Second, datetime, TimezoneId)) {
  102. return false;
  103. }
  104. ui32 year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek;
  105. if (!builder.FullSplitDatetime2(datetime, year, month, day, hour, minute, second, dayOfYear, weekOfYear, weekOfYearIso8601, dayOfWeek, TimezoneId)) {
  106. ythrow yexception() << "Error in FullSplitDatetime.";
  107. }
  108. DayOfYear = dayOfYear;
  109. WeekOfYear = weekOfYear;
  110. WeekOfYearIso8601 = weekOfYearIso8601;
  111. DayOfWeek = dayOfWeek;
  112. return true;
  113. }
  114. inline void FromTimeOfDay(ui64 value) {
  115. Hour = value / 3600000000ull;
  116. value -= Hour * 3600000000ull;
  117. Minute = value / 60000000ull;
  118. value -= Minute * 60000000ull;
  119. Second = value / 1000000ull;
  120. Microsecond = value - Second * 1000000ull;
  121. }
  122. inline ui64 ToTimeOfDay() const {
  123. return ((Hour * 60ull + Minute) * 60ull + Second) * 1000000ull + Microsecond;
  124. }
  125. const TString ToString() const {
  126. const auto& tzName = NUdf::GetTimezones()[TimezoneId];
  127. return Sprintf("%4d-%02d-%02dT%02d:%02d:%02d.%06d,%.*s",
  128. Year, Month, Day, Hour, Minute, Second, Microsecond,
  129. static_cast<int>(tzName.size()), tzName.data());
  130. }
  131. };
  132. static_assert(sizeof(TTMStorage) == 16, "TTMStorage size must be equal to TUnboxedValuePod size");
  133. template<typename TStorage>
  134. bool DoAddMonths(TStorage& storage, i64 months, const NUdf::IDateBuilder& builder) {
  135. i64 newMonth = months + storage.Month;
  136. storage.Year += (newMonth - 1) / 12;
  137. newMonth = 1 + (newMonth - 1) % 12;
  138. if (newMonth <= 0) {
  139. storage.Year--;
  140. newMonth += 12;
  141. }
  142. if (storage.Year == 0) {
  143. storage.Year += months > 0 ? 1 : -1;
  144. }
  145. storage.Month = newMonth;
  146. bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year);
  147. ui32 monthLength = NKikimr::NMiniKQL::GetMonthLength(storage.Month, isLeap);
  148. storage.Day = std::min(monthLength, storage.Day);
  149. return storage.Validate(builder);
  150. }
  151. template<typename TStorage>
  152. bool DoAddYears(TStorage& storage, i64 years, const NUdf::IDateBuilder& builder) {
  153. storage.Year += years;
  154. if (storage.Year == 0) {
  155. storage.Year += years > 0 ? 1 : -1;
  156. }
  157. if (storage.Month == 2 && storage.Day == 29) {
  158. bool isLeap = NKikimr::NMiniKQL::IsLeapYear(storage.Year);
  159. if (!isLeap) {
  160. storage.Day--;
  161. }
  162. }
  163. return storage.Validate(builder);
  164. }
  165. TInstant DoAddMonths(TInstant current, i64 months, const NUdf::IDateBuilder& builder);
  166. TInstant DoAddYears(TInstant current, i64 years, const NUdf::IDateBuilder& builder);
  167. }