datetime.cpp 6.6 KB

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