datetime.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #include "datetime.h"
  2. #include <util/ysaveload.h>
  3. #include <util/system/fasttime.h>
  4. #include <util/datetime/base.h>
  5. #include <util/datetime/systime.h>
  6. #include <util/stream/output.h>
  7. #include <util/stream/mem.h>
  8. #include <util/string/cast.h>
  9. #include <util/string/printf.h>
  10. namespace NDatetime {
  11. const ui32 MonthDays[2][12] = {
  12. {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, //nleap
  13. {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} //leap
  14. };
  15. const ui32 MonthDaysNewYear[2][13] = {
  16. {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, //nleap
  17. {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} //leap
  18. };
  19. void YDayToMonthAndDay(ui32 yday, bool isleap, ui32* month, ui32* mday) {
  20. const ui32* begin = MonthDaysNewYear[isleap] + 1;
  21. const ui32* end = begin + 12;
  22. // [31, ..., 365] or [31, ..., 366] (12 elements)
  23. const ui32* pos = UpperBound(begin, end, yday);
  24. Y_ENSURE(pos != end, "day no. " << yday << " does not exist in " << (isleap ? "leap" : "non-leap") << " year");
  25. *month = pos - begin;
  26. *mday = yday - *(pos - 1) + 1;
  27. Y_ASSERT((*month < 12) && (1 <= *mday) && (*mday <= MonthDays[isleap][*month]));
  28. }
  29. struct TTimeData {
  30. i32 IsDst = 0;
  31. i32 GMTOff = 0;
  32. TTimeData(time_t t) {
  33. struct ::tm tt;
  34. ::localtime_r(&t, &tt);
  35. #ifndef _win_
  36. GMTOff = tt.tm_gmtoff;
  37. #else
  38. TIME_ZONE_INFORMATION tz;
  39. switch (GetTimeZoneInformation(&tz)) {
  40. case TIME_ZONE_ID_UNKNOWN:
  41. GMTOff = tz.Bias * -60;
  42. break;
  43. case TIME_ZONE_ID_STANDARD:
  44. GMTOff = (tz.Bias + tz.StandardBias) * -60;
  45. break;
  46. case TIME_ZONE_ID_DAYLIGHT:
  47. GMTOff = (tz.Bias + tz.DaylightBias) * -60;
  48. break;
  49. default:
  50. break;
  51. }
  52. #endif
  53. IsDst = tt.tm_isdst;
  54. }
  55. };
  56. TSimpleTM TSimpleTM::CurrentUTC() {
  57. return New((time_t)TInstant::MicroSeconds(InterpolatedMicroSeconds()).Seconds());
  58. }
  59. TSimpleTM TSimpleTM::New(time_t t, i32 gmtoff, i8 isdst) {
  60. time_t tt = t + gmtoff + isdst * 3600;
  61. struct tm tmSys;
  62. Zero(tmSys);
  63. GmTimeR(&tt, &tmSys);
  64. tmSys.tm_isdst = isdst;
  65. #ifndef _win_
  66. tmSys.tm_gmtoff = gmtoff;
  67. #endif
  68. return New(tmSys);
  69. }
  70. TSimpleTM TSimpleTM::NewLocal(time_t t) {
  71. TTimeData d(t);
  72. return New(t, d.GMTOff, d.IsDst);
  73. }
  74. TSimpleTM TSimpleTM::New(const struct tm& t) {
  75. TSimpleTM res;
  76. res.IsDst = t.tm_isdst;
  77. res.Sec = t.tm_sec;
  78. res.Min = t.tm_min;
  79. res.Hour = t.tm_hour;
  80. res.WDay = t.tm_wday;
  81. res.Mon = t.tm_mon;
  82. res.MDay = t.tm_mday;
  83. res.Year = t.tm_year;
  84. res.YDay = t.tm_yday;
  85. res.IsLeap = LeapYearAD(res.Year + 1900);
  86. #ifndef _win_
  87. res.GMTOff = t.tm_gmtoff;
  88. #endif
  89. return res;
  90. }
  91. TSimpleTM& TSimpleTM::SetRealDate(ui32 year, ui32 mon, ui32 mday, ui32 hour, ui32 min, ui32 sec, i32 isdst) {
  92. mday = ::Max<ui32>(mday, 1);
  93. mon = ::Min<ui32>(::Max<ui32>(mon, 1), 12);
  94. year = ::Max<ui32>(year, 1900);
  95. IsLeap = LeapYearAD(year);
  96. Year = year - 1900;
  97. Mon = mon - 1;
  98. MDay = ::Min<ui32>(mday, MonthDays[IsLeap][Mon]);
  99. Hour = Max<ui32>() == hour ? Hour : ::Min<ui32>(hour, 23);
  100. Min = Max<ui32>() == min ? Min : ::Min<ui32>(min, 59);
  101. Sec = Max<ui32>() == sec ? Sec : ::Min<ui32>(sec, 60);
  102. IsDst = isdst;
  103. return RegenerateFields();
  104. }
  105. TSimpleTM& TSimpleTM::RegenerateFields() {
  106. return *this = New(AsTimeT(), GMTOff, IsDst);
  107. }
  108. TSimpleTM& TSimpleTM::Add(EField f, i32 amount) {
  109. if (!amount) {
  110. return *this;
  111. }
  112. switch (f) {
  113. default:
  114. return *this;
  115. case F_DAY:
  116. amount *= 24;
  117. [[fallthrough]];
  118. case F_HOUR:
  119. amount *= 60;
  120. [[fallthrough]];
  121. case F_MIN:
  122. amount *= 60;
  123. [[fallthrough]];
  124. case F_SEC: {
  125. return *this = New(AsTimeT() + amount, GMTOff, IsDst);
  126. }
  127. case F_YEAR: {
  128. i32 y = amount + (i32)Year;
  129. y = ::Min<i32>(Max<i32>(y, 0), 255 /*max year*/);
  130. // YDay may correspond to different MDay if it's March or greater and the years have different leap status
  131. if (Mon > 1) {
  132. YDay += (i32)LeapYearAD(RealYear()) - (i32)LeapYearAD(RealYear());
  133. }
  134. Year = y;
  135. IsLeap = LeapYearAD(RealYear());
  136. return RegenerateFields();
  137. }
  138. case F_MON: {
  139. i32 m = amount + Mon;
  140. i32 y = (m < 0 ? (-12 + m) : m) / 12;
  141. m = m - y * 12;
  142. if (y) {
  143. Add(F_YEAR, y);
  144. }
  145. if (m >= 0 && m < 12) {
  146. MDay = ::Min<ui32>(MonthDays[IsLeap][m], MDay);
  147. Mon = m;
  148. }
  149. return RegenerateFields();
  150. }
  151. }
  152. }
  153. TString TSimpleTM::ToString(const char* fmt) const {
  154. struct tm t = *this;
  155. return Strftime(fmt, &t);
  156. }
  157. time_t TSimpleTM::AsTimeT() const {
  158. struct tm t = AsStructTmLocal();
  159. return TimeGM(&t) - GMTOff - IsDst * 3600;
  160. }
  161. struct tm TSimpleTM::AsStructTmUTC() const {
  162. struct tm res;
  163. Zero(res);
  164. time_t t = AsTimeT();
  165. return *GmTimeR(&t, &res);
  166. }
  167. struct tm TSimpleTM::AsStructTmLocal() const {
  168. struct tm t;
  169. Zero(t);
  170. t.tm_isdst = IsDst;
  171. t.tm_sec = Sec;
  172. t.tm_min = Min;
  173. t.tm_hour = Hour;
  174. t.tm_wday = WDay;
  175. t.tm_mon = Mon;
  176. t.tm_mday = MDay;
  177. t.tm_year = Year;
  178. t.tm_yday = YDay;
  179. #ifndef _win_
  180. t.tm_gmtoff = GMTOff;
  181. #endif
  182. return t;
  183. }
  184. }
  185. template <>
  186. void In<TMonth>(IInputStream& in, TMonth& t) {
  187. char buf[4];
  188. LoadPodArray(&in, buf, 4);
  189. t.Year = FromString<ui16>(buf, 4);
  190. LoadPodArray(&in, buf, 2);
  191. t.Month = ui8(FromString<ui16>(buf, 2)) - 1;
  192. }
  193. template <>
  194. void Out<TMonth>(IOutputStream& o, const TMonth& t) {
  195. o << t.Year << Sprintf("%.2hu", (ui16)(t.Month + 1));
  196. }
  197. template <>
  198. TMonth FromStringImpl<TMonth, char>(const char* s, size_t len) {
  199. TMonth res;
  200. TMemoryInput in(s, len);
  201. in >> res;
  202. return res;
  203. }