base.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "base.h"
  2. #include <util/string/cast.h>
  3. #include <util/stream/output.h>
  4. #include <util/stream/mem.h>
  5. #include <util/system/compat.h>
  6. #include <util/memory/tempbuf.h>
  7. #include <util/generic/string.h>
  8. #include <util/generic/yexception.h>
  9. TString Strftime(const char* format, const struct tm* tm) {
  10. size_t size = Max<size_t>(strlen(format) * 2 + 1, 107);
  11. for (;;) {
  12. TTempBuf buf(size);
  13. int r = strftime(buf.Data(), buf.Size(), format, tm);
  14. if (r != 0) {
  15. return TString(buf.Data(), r);
  16. }
  17. size *= 2;
  18. }
  19. }
  20. template <>
  21. TDuration FromStringImpl<TDuration, char>(const char* s, size_t len) {
  22. return TDuration::Parse(TStringBuf(s, len));
  23. }
  24. template <>
  25. bool TryFromStringImpl<TDuration, char>(const char* s, size_t len, TDuration& result) {
  26. return TDuration::TryParse(TStringBuf(s, len), result);
  27. }
  28. namespace {
  29. template <size_t N>
  30. struct TPad {
  31. int I;
  32. };
  33. template <size_t N>
  34. inline TPad<N> Pad(int i) {
  35. return {i};
  36. }
  37. inline IOutputStream& operator<<(IOutputStream& o, const TPad<2>& p) {
  38. if (p.I < 10) {
  39. if (p.I >= 0) {
  40. o << '0';
  41. }
  42. }
  43. return o << p.I;
  44. }
  45. inline IOutputStream& operator<<(IOutputStream& o, const TPad<4>& p) {
  46. if (p.I < 1000) {
  47. if (p.I >= 0) {
  48. if (p.I < 10) {
  49. o << '0' << '0' << '0';
  50. } else if (p.I < 100) {
  51. o << '0' << '0';
  52. } else {
  53. o << '0';
  54. }
  55. }
  56. }
  57. return o << p.I;
  58. }
  59. inline IOutputStream& operator<<(IOutputStream& o, const TPad<6>& p) {
  60. if (p.I < 100000) {
  61. if (p.I >= 0) {
  62. if (p.I < 10) {
  63. o << '0' << '0' << '0' << '0' << '0';
  64. } else if (p.I < 100) {
  65. o << '0' << '0' << '0' << '0';
  66. } else if (p.I < 1000) {
  67. o << '0' << '0' << '0';
  68. } else if (p.I < 10000) {
  69. o << '0' << '0';
  70. } else {
  71. o << '0';
  72. }
  73. }
  74. }
  75. return o << p.I;
  76. }
  77. void WriteMicroSecondsToStream(IOutputStream& os, ui32 microSeconds) {
  78. os << '.' << Pad<6>(microSeconds);
  79. }
  80. void WriteTmToStream(IOutputStream& os, const struct tm& theTm) {
  81. os << Pad<4>(theTm.tm_year + 1900) << '-' << Pad<2>(theTm.tm_mon + 1) << '-' << Pad<2>(theTm.tm_mday) << 'T'
  82. << Pad<2>(theTm.tm_hour) << ':' << Pad<2>(theTm.tm_min) << ':' << Pad<2>(theTm.tm_sec);
  83. }
  84. template <bool PrintUpToSeconds, bool iso>
  85. void WritePrintableLocalTimeToStream(IOutputStream& os, const ::NPrivate::TPrintableLocalTime<PrintUpToSeconds, iso>& timeToPrint) {
  86. const TInstant& momentToPrint = timeToPrint.MomentToPrint;
  87. struct tm localTime;
  88. momentToPrint.LocalTime(&localTime);
  89. WriteTmToStream(os, localTime);
  90. if (!PrintUpToSeconds) {
  91. WriteMicroSecondsToStream(os, momentToPrint.MicroSecondsOfSecond());
  92. }
  93. #ifndef _win_
  94. i64 utcOffsetInMinutes = localTime.tm_gmtoff / 60;
  95. #else
  96. TIME_ZONE_INFORMATION tz;
  97. if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_INVALID) {
  98. ythrow TSystemError() << "Failed to get the system time zone";
  99. }
  100. i64 utcOffsetInMinutes = -tz.Bias;
  101. #endif
  102. if (utcOffsetInMinutes == 0) {
  103. os << 'Z';
  104. } else {
  105. if (utcOffsetInMinutes < 0) {
  106. os << '-';
  107. utcOffsetInMinutes = -utcOffsetInMinutes;
  108. } else {
  109. os << '+';
  110. }
  111. os << Pad<2>(utcOffsetInMinutes / 60);
  112. if (iso) {
  113. os << ':';
  114. }
  115. os << Pad<2>(utcOffsetInMinutes % 60);
  116. }
  117. }
  118. }
  119. template <>
  120. void Out<TDuration>(IOutputStream& os, TTypeTraits<TDuration>::TFuncParam duration) {
  121. os << duration.Seconds();
  122. WriteMicroSecondsToStream(os, duration.MicroSecondsOfSecond());
  123. os << 's';
  124. }
  125. template <>
  126. void Out<TInstant>(IOutputStream& os, TTypeTraits<TInstant>::TFuncParam instant) {
  127. char buf[64];
  128. auto len = FormatDate8601(buf, sizeof(buf), instant.TimeT());
  129. // shouldn't happen due to current implementation of FormatDate8601() and GmTimeR()
  130. Y_ENSURE(len, TStringBuf("Out<TInstant>: year does not fit into an integer"));
  131. os.Write(buf, len - 1 /* 'Z' */);
  132. WriteMicroSecondsToStream(os, instant.MicroSecondsOfSecond());
  133. os << 'Z';
  134. }
  135. template <>
  136. void Out<::NPrivate::TPrintableLocalTime<false, false>>(IOutputStream& os, TTypeTraits<::NPrivate::TPrintableLocalTime<false, false>>::TFuncParam localTime) {
  137. WritePrintableLocalTimeToStream(os, localTime);
  138. }
  139. template <>
  140. void Out<::NPrivate::TPrintableLocalTime<false, true>>(IOutputStream& os, TTypeTraits<::NPrivate::TPrintableLocalTime<false, true>>::TFuncParam localTime) {
  141. WritePrintableLocalTimeToStream(os, localTime);
  142. }
  143. template <>
  144. void Out<::NPrivate::TPrintableLocalTime<true, false>>(IOutputStream& os, TTypeTraits<::NPrivate::TPrintableLocalTime<true, false>>::TFuncParam localTime) {
  145. WritePrintableLocalTimeToStream(os, localTime);
  146. }
  147. template <>
  148. void Out<::NPrivate::TPrintableLocalTime<true, true>>(IOutputStream& os, TTypeTraits<::NPrivate::TPrintableLocalTime<true, true>>::TFuncParam localTime) {
  149. WritePrintableLocalTimeToStream(os, localTime);
  150. }
  151. TString TDuration::ToString() const {
  152. return ::ToString(*this);
  153. }
  154. TString TInstant::ToString() const {
  155. return ::ToString(*this);
  156. }
  157. TString TInstant::ToRfc822String() const {
  158. return FormatGmTime("%a, %d %b %Y %H:%M:%S GMT");
  159. }
  160. TString TInstant::ToStringUpToSeconds() const {
  161. char buf[64];
  162. auto len = FormatDate8601(buf, sizeof(buf), TimeT());
  163. if (!len) {
  164. ythrow yexception() << "TInstant::ToStringUpToSeconds: year does not fit into an integer";
  165. }
  166. return TString(buf, len);
  167. }
  168. TString TInstant::ToIsoStringLocal() const {
  169. return ::ToString(FormatIsoLocal(*this));
  170. }
  171. TString TInstant::ToStringLocal() const {
  172. return ::ToString(FormatLocal(*this));
  173. }
  174. TString TInstant::ToRfc822StringLocal() const {
  175. return FormatLocalTime("%a, %d %b %Y %H:%M:%S %Z");
  176. }
  177. TString TInstant::ToIsoStringLocalUpToSeconds() const {
  178. return ::ToString(FormatIsoLocalUpToSeconds(*this));
  179. }
  180. TString TInstant::ToStringLocalUpToSeconds() const {
  181. return ::ToString(FormatLocalUpToSeconds(*this));
  182. }
  183. TString TInstant::FormatLocalTime(const char* format) const noexcept {
  184. struct tm theTm;
  185. LocalTime(&theTm);
  186. return Strftime(format, &theTm);
  187. }
  188. TString TInstant::FormatGmTime(const char* format) const noexcept {
  189. struct tm theTm;
  190. GmTime(&theTm);
  191. return Strftime(format, &theTm);
  192. }
  193. ::NPrivate::TPrintableLocalTime<false, true> FormatIsoLocal(TInstant instant) {
  194. return ::NPrivate::TPrintableLocalTime<false, true>(instant);
  195. }
  196. ::NPrivate::TPrintableLocalTime<false, false> FormatLocal(TInstant instant) {
  197. return ::NPrivate::TPrintableLocalTime<false, false>(instant);
  198. }
  199. ::NPrivate::TPrintableLocalTime<true, true> FormatIsoLocalUpToSeconds(TInstant instant) {
  200. return ::NPrivate::TPrintableLocalTime<true, true>(instant);
  201. }
  202. ::NPrivate::TPrintableLocalTime<true, false> FormatLocalUpToSeconds(TInstant instant) {
  203. return ::NPrivate::TPrintableLocalTime<true, false>(instant);
  204. }
  205. void Sleep(TDuration duration) {
  206. NanoSleep(duration.NanoSeconds());
  207. }
  208. void sprint_gm_date(char* buf, time_t when, long* sec) {
  209. struct tm theTm;
  210. ::Zero(theTm);
  211. GmTimeR(&when, &theTm);
  212. DateToString(buf, theTm);
  213. if (sec) {
  214. *sec = seconds(theTm);
  215. }
  216. }
  217. void DateToString(char* buf, const struct tm& theTm) {
  218. Y_ENSURE(0 <= theTm.tm_year + 1900 && theTm.tm_year + 1900 <= 9999, "invalid year " + ToString(theTm.tm_year + 1900) + ", year should be in range [0, 9999]");
  219. snprintf(buf, DATE_BUF_LEN, "%04d%02d%02d", theTm.tm_year + 1900, theTm.tm_mon + 1, theTm.tm_mday);
  220. }
  221. void DateToString(char* buf, time_t when, long* sec) {
  222. struct tm theTm;
  223. localtime_r(&when, &theTm);
  224. DateToString(buf, theTm);
  225. if (sec) {
  226. *sec = seconds(theTm);
  227. }
  228. }
  229. TString DateToString(const struct tm& theTm) {
  230. char buf[DATE_BUF_LEN];
  231. DateToString(buf, theTm);
  232. return buf;
  233. }
  234. TString DateToString(time_t when, long* sec) {
  235. char buf[DATE_BUF_LEN];
  236. DateToString(buf, when, sec);
  237. return buf;
  238. }
  239. TString YearToString(const struct tm& theTm) {
  240. Y_ENSURE(0 <= theTm.tm_year + 1900 && theTm.tm_year + 1900 <= 9999, "invalid year " + ToString(theTm.tm_year + 1900) + ", year should be in range [0, 9999]");
  241. char buf[16];
  242. snprintf(buf, 16, "%04d", theTm.tm_year + 1900);
  243. return buf;
  244. }
  245. TString YearToString(time_t when) {
  246. struct tm theTm;
  247. localtime_r(&when, &theTm);
  248. return YearToString(theTm);
  249. }
  250. bool sscan_date(const char* date, struct tm& theTm) {
  251. int year, mon, mday;
  252. if (sscanf(date, "%4d%2d%2d", &year, &mon, &mday) != 3) {
  253. return false;
  254. }
  255. theTm.tm_year = year - 1900;
  256. theTm.tm_mon = mon - 1;
  257. theTm.tm_mday = mday;
  258. return true;
  259. }
  260. size_t FormatDate8601(char* buf, size_t len, time_t when) {
  261. struct tm theTm;
  262. struct tm* ret = GmTimeR(&when, &theTm);
  263. if (ret) {
  264. TMemoryOutput out(buf, len);
  265. WriteTmToStream(out, theTm);
  266. out << 'Z';
  267. return out.Buf() - buf;
  268. }
  269. return 0;
  270. }
  271. void SleepUntil(TInstant instant) {
  272. TInstant now = TInstant::Now();
  273. if (instant <= now) {
  274. return;
  275. }
  276. TDuration duration = instant - now;
  277. Sleep(duration);
  278. }