parser.rl6 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <ctime>
  6. #include <numeric>
  7. #include <util/datetime/parser.h>
  8. #include <util/generic/ymath.h>
  9. %%{
  10. machine DateTimeParserCommon;
  11. sp = ' ';
  12. action clear_int {
  13. I = 0;
  14. Dc = 0;
  15. }
  16. action update_int {
  17. I = I * 10 + (fc - '0');
  18. ++Dc;
  19. }
  20. int = (digit+)
  21. >clear_int
  22. $update_int;
  23. int1 = digit
  24. >clear_int
  25. $update_int;
  26. int2 = (digit digit)
  27. >clear_int
  28. $update_int;
  29. int3 = (digit digit digit)
  30. >clear_int
  31. $update_int;
  32. int4 = (digit digit digit digit)
  33. >clear_int
  34. $update_int;
  35. int12 = (digit digit?)
  36. >clear_int
  37. $update_int;
  38. int24 = ( digit digit ( digit digit )? )
  39. >clear_int
  40. $update_int;
  41. # According to both RFC2822 and RFC2616 dates MUST be case-sensitive,
  42. # but Andrey fomichev@ wants relaxed parser
  43. month3 =
  44. 'Jan'i %{ DateTimeFields.Month = 1; }
  45. | 'Feb'i %{ DateTimeFields.Month = 2; }
  46. | 'Mar'i %{ DateTimeFields.Month = 3; }
  47. | 'Apr'i %{ DateTimeFields.Month = 4; }
  48. | 'May'i %{ DateTimeFields.Month = 5; }
  49. | 'Jun'i %{ DateTimeFields.Month = 6; }
  50. | 'Jul'i %{ DateTimeFields.Month = 7; }
  51. | 'Aug'i %{ DateTimeFields.Month = 8; }
  52. | 'Sep'i %{ DateTimeFields.Month = 9; }
  53. | 'Oct'i %{ DateTimeFields.Month = 10; }
  54. | 'Nov'i %{ DateTimeFields.Month = 11; }
  55. | 'Dec'i %{ DateTimeFields.Month = 12; };
  56. wkday = 'Mon'i | 'Tue'i | 'Wed'i | 'Thu'i | 'Fri'i | 'Sat'i | 'Sun'i;
  57. weekday = 'Monday'i | 'Tuesday'i | 'Wednesday'i | 'Thursday'i
  58. | 'Friday'i | 'Saturday'i | 'Sunday'i;
  59. action set_second { DateTimeFields.Second = I; }
  60. action set_minute { DateTimeFields.Minute = I; }
  61. action set_hour { DateTimeFields.Hour = I; }
  62. action set_day { DateTimeFields.Day = I; }
  63. action set_month { DateTimeFields.Month = I; }
  64. action set_year { DateTimeFields.SetLooseYear(I); }
  65. action set_precise_year { DateTimeFields.Year = I; }
  66. action set_zone_utc { DateTimeFields.ZoneOffsetMinutes = 0; }
  67. }%%
  68. %%{
  69. machine RFC822DateParser;
  70. ################# RFC 2822 3.3 Full Date ###################
  71. include DateTimeParserCommon;
  72. ws1 = (space+);
  73. ws0 = (space*);
  74. dow_spec = ( wkday ',' )?;
  75. day = int12 %set_day;
  76. year = int24 %set_year;
  77. # actually it must be from 0 to 23
  78. hour = int2 %set_hour;
  79. # actually it must be from 0 to 59
  80. min = int2 %set_minute;
  81. # actually it must be from 0 to 59
  82. sec = int2 %set_second;
  83. sec_spec = ( ':' . sec )?;
  84. # so called "military zone offset". I hardly believe someone uses it now, but we MUST respect RFc822
  85. action set_mil_offset {
  86. char c = (char)toupper(fc);
  87. if (c == 'Z')
  88. DateTimeFields.ZoneOffsetMinutes = 0;
  89. else {
  90. if (c <= 'M') {
  91. // ['A'..'M'] \ 'J'
  92. if (c < 'J')
  93. DateTimeFields.ZoneOffsetMinutes = (i32)TDuration::Hours(c - 'A' + 1).Minutes();
  94. else
  95. DateTimeFields.ZoneOffsetMinutes = (i32)TDuration::Hours(c - 'A').Minutes();
  96. } else {
  97. // ['N'..'Y']
  98. DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(c - 'N' + 1).Minutes();
  99. }
  100. }
  101. }
  102. action set_digit_offset {
  103. DateTimeFields.ZoneOffsetMinutes = Sign * (i32)(TDuration::Hours(I / 100) + TDuration::Minutes(I % 100)).Minutes();
  104. }
  105. mil_zone = /[A-IK-Za-ik-z]/ $set_mil_offset;
  106. # actions % were replaced with @ (when the script was migrated to ragel 5.24)
  107. # because ragel 5.24 does not call to the % action if it be called at the very end of string.
  108. # it is a bug in ragel 5 because ragel 6.2 works correctly with % at the end of string.
  109. # see http://www.complang.org/ragel/ChangeLog.
  110. zone = 'UT' @{ DateTimeFields.ZoneOffsetMinutes = 0; }
  111. | 'GMT' @{ DateTimeFields.ZoneOffsetMinutes = 0; }
  112. | 'EST' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(5).Minutes();}
  113. | 'EDT' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(4).Minutes(); }
  114. | 'CST' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(6).Minutes();}
  115. | 'CDT' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(5).Minutes(); }
  116. | 'MST' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(7).Minutes();}
  117. | 'MDT' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(6).Minutes(); }
  118. | 'PST' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(8).Minutes();}
  119. | 'PDT' @{ DateTimeFields.ZoneOffsetMinutes = -(i32)TDuration::Hours(7).Minutes(); };
  120. digit_offset = ('+' | '-') > { Sign = fc == '+' ? 1 : -1; } . int4 @set_digit_offset;
  121. offset = ( zone | mil_zone | digit_offset );
  122. rfc822datetime = ws0 . dow_spec . ws0 . day . ws1 . month3 . ws1 . year . ws1 . hour . ':' . min . sec_spec . ws1 . offset . ws0;
  123. main := rfc822datetime;
  124. write data noerror;
  125. }%%
  126. TRfc822DateTimeParserDeprecated::TRfc822DateTimeParserDeprecated() {
  127. %% write init;
  128. }
  129. bool TRfc822DateTimeParserDeprecated::ParsePart(const char* input, size_t len) {
  130. const char* p = input;
  131. const char* pe = input + len;
  132. %% write exec;
  133. return cs != %%{ write error; }%%;
  134. }
  135. TRfc822DateTimeParser::TRfc822DateTimeParser() {
  136. %% write init;
  137. }
  138. bool TRfc822DateTimeParser::ParsePart(const char* input, size_t len) {
  139. const char* p = input;
  140. const char* pe = input + len;
  141. %% write exec;
  142. return cs != %%{ write error; }%%;
  143. }
  144. %%{
  145. machine ISO8601DateTimeParser;
  146. include DateTimeParserCommon;
  147. year = int4 @set_precise_year;
  148. month = int2 @set_month;
  149. day = int2 @set_day;
  150. hour = int2 @set_hour;
  151. minute = int2 @set_minute;
  152. second = int2 @set_second;
  153. secondFrac = digit {1,6} >clear_int $update_int @{
  154. ui32 us = I;
  155. for (int k = Dc; k < 6; ++k) {
  156. us *= 10;
  157. }
  158. DateTimeFields.MicroSecond = us;
  159. };
  160. secondFracTail = (digit*);
  161. zoneZ = [Zz] @set_zone_utc;
  162. zoneOffset = space? . ('+' | '-') >{ Sign = fc == '+' ? 1 : -1; } . int2 @{ DateTimeFields.ZoneOffsetMinutes = Sign * (i32)TDuration::Hours(I).Minutes(); } . (':')? . (int2 @{ DateTimeFields.ZoneOffsetMinutes += I * Sign; })?;
  163. zone = zoneZ | zoneOffset;
  164. iso8601date = (year . '-' . month . '-' . day) | (year . month . day);
  165. iso8601time = (hour . ':' . minute . (':' . second ('.' secondFrac secondFracTail)?)?) | (hour . minute . second?);
  166. iso8601datetime = iso8601date . ([Tt ] . iso8601time . zone?)?;
  167. main := iso8601datetime;
  168. write data noerror;
  169. }%%
  170. TIso8601DateTimeParserDeprecated::TIso8601DateTimeParserDeprecated() {
  171. %% write init;
  172. }
  173. bool TIso8601DateTimeParserDeprecated::ParsePart(const char* input, size_t len) {
  174. const char* p = input;
  175. const char* pe = input + len;
  176. %% write exec;
  177. return cs != %%{ write error; }%%;
  178. }
  179. TIso8601DateTimeParser::TIso8601DateTimeParser() {
  180. %% write init;
  181. }
  182. bool TIso8601DateTimeParser::ParsePart(const char* input, size_t len) {
  183. const char* p = input;
  184. const char* pe = input + len;
  185. %% write exec;
  186. return cs != %%{ write error; }%%;
  187. }
  188. %%{
  189. machine HttpDateTimeParser;
  190. include DateTimeParserCommon;
  191. ################# RFC 2616 3.3.1 Full Date #################
  192. time = int2 %set_hour ':' int2 %set_minute ':' int2 %set_second;
  193. date1 = int2 %set_day ' ' month3 ' ' int4 %set_year;
  194. date2 = int2 %set_day '-' month3 '-' int2 %set_year;
  195. date3 = month3 sp (int2 | sp int1) %set_day;
  196. rfc1123_date = wkday ',' sp date1 sp time sp 'GMT'i;
  197. rfc850_date = weekday ',' sp date2 sp time sp 'GMT'i;
  198. asctime_date = wkday sp date3 sp time sp int4 @set_year;
  199. http_date = (rfc1123_date | rfc850_date | asctime_date) @set_zone_utc;
  200. }%%
  201. %%{
  202. machine HttpDateTimeParserStandalone;
  203. include HttpDateTimeParser;
  204. main := http_date;
  205. write data noerror;
  206. }%%
  207. THttpDateTimeParserDeprecated::THttpDateTimeParserDeprecated() {
  208. %% write init;
  209. }
  210. bool THttpDateTimeParserDeprecated::ParsePart(const char* input, size_t len) {
  211. const char* p = input;
  212. const char* pe = input + len;
  213. %% write exec;
  214. return cs != %%{ write error; }%%;
  215. }
  216. THttpDateTimeParser::THttpDateTimeParser() {
  217. %% write init;
  218. }
  219. bool THttpDateTimeParser::ParsePart(const char* input, size_t len) {
  220. const char* p = input;
  221. const char* pe = input + len;
  222. %% write exec;
  223. return cs != %%{ write error; }%%;
  224. }
  225. %%{
  226. machine X509ValidityDateTimeParser;
  227. include DateTimeParserCommon;
  228. ################# X.509 certificate validity time (see rfc5280 4.1.2.5.*) #################
  229. year = int2 @{ DateTimeFields.Year = (I < 50 ? I + 2000 : I + 1900); };
  230. month = int2 @set_month;
  231. day = int2 @set_day;
  232. hour = int2 @set_hour;
  233. minute = int2 @set_minute;
  234. second = int2 @set_second;
  235. zone = 'Z' @set_zone_utc;
  236. main := year . month . day . hour . minute . second . zone;
  237. write data noerror;
  238. }%%
  239. TX509ValidityDateTimeParserDeprecated::TX509ValidityDateTimeParserDeprecated() {
  240. %% write init;
  241. }
  242. bool TX509ValidityDateTimeParserDeprecated::ParsePart(const char *input, size_t len) {
  243. const char *p = input;
  244. const char *pe = input + len;
  245. %% write exec;
  246. return cs != %%{ write error; }%%;
  247. }
  248. TX509ValidityDateTimeParser::TX509ValidityDateTimeParser() {
  249. %% write init;
  250. }
  251. bool TX509ValidityDateTimeParser::ParsePart(const char *input, size_t len) {
  252. const char *p = input;
  253. const char *pe = input + len;
  254. %% write exec;
  255. return cs != %%{ write error; }%%;
  256. }
  257. %%{
  258. machine X509Validity4yDateTimeParser;
  259. include DateTimeParserCommon;
  260. year = int4 @{ DateTimeFields.Year = I; };
  261. month = int2 @set_month;
  262. day = int2 @set_day;
  263. hour = int2 @set_hour;
  264. minute = int2 @set_minute;
  265. second = int2 @set_second;
  266. zone = 'Z' @set_zone_utc;
  267. main := year . month . day . hour . minute . second . zone;
  268. write data noerror;
  269. }%%
  270. TX509Validity4yDateTimeParserDeprecated::TX509Validity4yDateTimeParserDeprecated() {
  271. %% write init;
  272. }
  273. bool TX509Validity4yDateTimeParserDeprecated::ParsePart(const char *input, size_t len) {
  274. const char *p = input;
  275. const char *pe = input + len;
  276. %% write exec;
  277. return cs != %%{ write error; }%%;
  278. }
  279. TX509Validity4yDateTimeParser::TX509Validity4yDateTimeParser() {
  280. %% write init;
  281. }
  282. bool TX509Validity4yDateTimeParser::ParsePart(const char *input, size_t len) {
  283. const char *p = input;
  284. const char *pe = input + len;
  285. %% write exec;
  286. return cs != %%{ write error; }%%;
  287. }
  288. TInstant TIso8601DateTimeParserDeprecated::GetResult(TInstant defaultValue) const {
  289. Y_UNUSED(ISO8601DateTimeParser_en_main);
  290. return TDateTimeParserBaseDeprecated::GetResult(ISO8601DateTimeParser_first_final, defaultValue);
  291. }
  292. TInstant TRfc822DateTimeParserDeprecated::GetResult(TInstant defaultValue) const {
  293. Y_UNUSED(RFC822DateParser_en_main);
  294. return TDateTimeParserBaseDeprecated::GetResult(RFC822DateParser_first_final, defaultValue);
  295. }
  296. TInstant THttpDateTimeParserDeprecated::GetResult(TInstant defaultValue) const {
  297. Y_UNUSED(HttpDateTimeParserStandalone_en_main);
  298. return TDateTimeParserBaseDeprecated::GetResult(HttpDateTimeParserStandalone_first_final, defaultValue);
  299. }
  300. TInstant TX509ValidityDateTimeParserDeprecated::GetResult(TInstant defaultValue) const {
  301. Y_UNUSED(X509ValidityDateTimeParser_en_main);
  302. return TDateTimeParserBaseDeprecated::GetResult(X509ValidityDateTimeParser_first_final, defaultValue);
  303. }
  304. TInstant TX509Validity4yDateTimeParserDeprecated::GetResult(TInstant defaultValue) const {
  305. Y_UNUSED(X509Validity4yDateTimeParser_en_main);
  306. return TDateTimeParserBaseDeprecated::GetResult(X509Validity4yDateTimeParser_first_final, defaultValue);
  307. }
  308. TInstant TIso8601DateTimeParser::GetResult(TInstant defaultValue) const {
  309. Y_UNUSED(ISO8601DateTimeParser_en_main);
  310. return TDateTimeParserBase::GetResult(ISO8601DateTimeParser_first_final, defaultValue);
  311. }
  312. TInstant TRfc822DateTimeParser::GetResult(TInstant defaultValue) const {
  313. Y_UNUSED(RFC822DateParser_en_main);
  314. return TDateTimeParserBase::GetResult(RFC822DateParser_first_final, defaultValue);
  315. }
  316. TInstant THttpDateTimeParser::GetResult(TInstant defaultValue) const {
  317. Y_UNUSED(HttpDateTimeParserStandalone_en_main);
  318. return TDateTimeParserBase::GetResult(HttpDateTimeParserStandalone_first_final, defaultValue);
  319. }
  320. TInstant TX509ValidityDateTimeParser::GetResult(TInstant defaultValue) const {
  321. Y_UNUSED(X509ValidityDateTimeParser_en_main);
  322. return TDateTimeParserBase::GetResult(X509ValidityDateTimeParser_first_final, defaultValue);
  323. }
  324. TInstant TX509Validity4yDateTimeParser::GetResult(TInstant defaultValue) const {
  325. Y_UNUSED(X509Validity4yDateTimeParser_en_main);
  326. return TDateTimeParserBase::GetResult(X509Validity4yDateTimeParser_first_final, defaultValue);
  327. }
  328. template<class TParser, class TResult>
  329. static inline TResult Parse(const char* input, size_t len, TResult defaultValue) {
  330. TParser parser;
  331. if (!parser.ParsePart(input, len))
  332. return defaultValue;
  333. return parser.GetResult(defaultValue);
  334. }
  335. template<class TParser, class TResult, bool ThrowExceptionOnFailure = true>
  336. static inline TResult ParseUnsafe(const char* input, size_t len) {
  337. TResult r = Parse<TParser, TResult>(input, len, TResult::Max());
  338. if (ThrowExceptionOnFailure && r == TResult::Max())
  339. ythrow TDateTimeParseException() << "error in datetime parsing. Input data: " << TStringBuf(input, len);
  340. return r;
  341. }
  342. TInstant TInstant::ParseIso8601Deprecated(const TStringBuf input) {
  343. return ParseUnsafe<TIso8601DateTimeParserDeprecated, TInstant>(input.data(), input.size());
  344. }
  345. TInstant TInstant::ParseRfc822Deprecated(const TStringBuf input) {
  346. return ParseUnsafe<TRfc822DateTimeParserDeprecated, TInstant>(input.data(), input.size());
  347. }
  348. TInstant TInstant::ParseHttpDeprecated(const TStringBuf input) {
  349. return ParseUnsafe<THttpDateTimeParserDeprecated, TInstant>(input.data(), input.size());
  350. }
  351. TInstant TInstant::ParseX509ValidityDeprecated(const TStringBuf input) {
  352. switch (input.size()) {
  353. case 13:
  354. return ParseUnsafe<TX509ValidityDateTimeParserDeprecated, TInstant>(input.data(), 13);
  355. case 15:
  356. return ParseUnsafe<TX509Validity4yDateTimeParserDeprecated, TInstant>(input.data(), 15);
  357. default:
  358. ythrow TDateTimeParseException();
  359. }
  360. }
  361. bool TInstant::TryParseIso8601Deprecated(const TStringBuf input, TInstant& instant) {
  362. const auto parsed = ParseUnsafe<TIso8601DateTimeParserDeprecated, TInstant, false>(input.data(), input.size());
  363. if (TInstant::Max() == parsed) {
  364. return false;
  365. }
  366. instant = parsed;
  367. return true;
  368. }
  369. bool TInstant::TryParseRfc822Deprecated(const TStringBuf input, TInstant& instant) {
  370. const auto parsed = ParseUnsafe<TRfc822DateTimeParserDeprecated, TInstant, false>(input.data(), input.size());
  371. if (TInstant::Max() == parsed) {
  372. return false;
  373. }
  374. instant = parsed;
  375. return true;
  376. }
  377. bool TInstant::TryParseHttpDeprecated(const TStringBuf input, TInstant& instant) {
  378. const auto parsed = ParseUnsafe<THttpDateTimeParserDeprecated, TInstant, false>(input.data(), input.size());
  379. if (TInstant::Max() == parsed) {
  380. return false;
  381. }
  382. instant = parsed;
  383. return true;
  384. }
  385. bool TInstant::TryParseX509Deprecated(const TStringBuf input, TInstant& instant) {
  386. TInstant parsed;
  387. switch (input.size()) {
  388. case 13:
  389. parsed = ParseUnsafe<TX509ValidityDateTimeParserDeprecated, TInstant, false>(input.data(), 13);
  390. break;
  391. case 15:
  392. parsed = ParseUnsafe<TX509Validity4yDateTimeParserDeprecated, TInstant, false>(input.data(), 15);
  393. break;
  394. default:
  395. return false;
  396. }
  397. if (TInstant::Max() == parsed) {
  398. return false;
  399. }
  400. instant = parsed;
  401. return true;
  402. }
  403. TInstant TInstant::ParseIso8601(const TStringBuf input) {
  404. return ParseUnsafe<TIso8601DateTimeParser, TInstant>(input.data(), input.size());
  405. }
  406. TInstant TInstant::ParseRfc822(const TStringBuf input) {
  407. return ParseUnsafe<TRfc822DateTimeParser, TInstant>(input.data(), input.size());
  408. }
  409. TInstant TInstant::ParseHttp(const TStringBuf input) {
  410. return ParseUnsafe<THttpDateTimeParser, TInstant>(input.data(), input.size());
  411. }
  412. TInstant TInstant::ParseX509Validity(const TStringBuf input) {
  413. switch (input.size()) {
  414. case 13:
  415. return ParseUnsafe<TX509ValidityDateTimeParser, TInstant>(input.data(), 13);
  416. case 15:
  417. return ParseUnsafe<TX509Validity4yDateTimeParser, TInstant>(input.data(), 15);
  418. default:
  419. ythrow TDateTimeParseException();
  420. }
  421. }
  422. bool TInstant::TryParseIso8601(const TStringBuf input, TInstant& instant) {
  423. const auto parsed = ParseUnsafe<TIso8601DateTimeParser, TInstant, false>(input.data(), input.size());
  424. if (TInstant::Max() == parsed) {
  425. return false;
  426. }
  427. instant = parsed;
  428. return true;
  429. }
  430. bool TInstant::TryParseRfc822(const TStringBuf input, TInstant& instant) {
  431. const auto parsed = ParseUnsafe<TRfc822DateTimeParser, TInstant, false>(input.data(), input.size());
  432. if (TInstant::Max() == parsed) {
  433. return false;
  434. }
  435. instant = parsed;
  436. return true;
  437. }
  438. bool TInstant::TryParseHttp(const TStringBuf input, TInstant& instant) {
  439. const auto parsed = ParseUnsafe<THttpDateTimeParser, TInstant, false>(input.data(), input.size());
  440. if (TInstant::Max() == parsed) {
  441. return false;
  442. }
  443. instant = parsed;
  444. return true;
  445. }
  446. bool TInstant::TryParseX509(const TStringBuf input, TInstant& instant) {
  447. TInstant parsed;
  448. switch (input.size()) {
  449. case 13:
  450. parsed = ParseUnsafe<TX509ValidityDateTimeParser, TInstant, false>(input.data(), 13);
  451. break;
  452. case 15:
  453. parsed = ParseUnsafe<TX509Validity4yDateTimeParser, TInstant, false>(input.data(), 15);
  454. break;
  455. default:
  456. return false;
  457. }
  458. if (TInstant::Max() == parsed) {
  459. return false;
  460. }
  461. instant = parsed;
  462. return true;
  463. }
  464. bool ParseRFC822DateTimeDeprecated(const char* input, time_t& utcTime) {
  465. return ParseRFC822DateTimeDeprecated(input, strlen(input), utcTime);
  466. }
  467. bool ParseISO8601DateTimeDeprecated(const char* input, time_t& utcTime) {
  468. return ParseISO8601DateTimeDeprecated(input, strlen(input), utcTime);
  469. }
  470. bool ParseHTTPDateTimeDeprecated(const char* input, time_t& utcTime) {
  471. return ParseHTTPDateTimeDeprecated(input, strlen(input), utcTime);
  472. }
  473. bool ParseX509ValidityDateTimeDeprecated(const char* input, time_t& utcTime) {
  474. return ParseX509ValidityDateTimeDeprecated(input, strlen(input), utcTime);
  475. }
  476. bool ParseRFC822DateTimeDeprecated(const char* input, size_t inputLen, time_t& utcTime) {
  477. try {
  478. utcTime = ParseUnsafe<TRfc822DateTimeParserDeprecated, TInstant>(input, inputLen).TimeT();
  479. return true;
  480. } catch (const TDateTimeParseException&) {
  481. return false;
  482. }
  483. }
  484. bool ParseISO8601DateTimeDeprecated(const char* input, size_t inputLen, time_t& utcTime) {
  485. try {
  486. utcTime = ParseUnsafe<TIso8601DateTimeParserDeprecated, TInstant>(input, inputLen).TimeT();
  487. return true;
  488. } catch (const TDateTimeParseException&) {
  489. return false;
  490. }
  491. }
  492. bool ParseHTTPDateTimeDeprecated(const char* input, size_t inputLen, time_t& utcTime) {
  493. try {
  494. utcTime = ParseUnsafe<THttpDateTimeParserDeprecated, TInstant>(input, inputLen).TimeT();
  495. return true;
  496. } catch (const TDateTimeParseException&) {
  497. return false;
  498. }
  499. }
  500. bool ParseX509ValidityDateTimeDeprecated(const char* input, size_t inputLen, time_t& utcTime) {
  501. TInstant r;
  502. switch (inputLen) {
  503. case 13:
  504. r = Parse<TX509ValidityDateTimeParserDeprecated, TInstant>(input, 13, TInstant::Max());
  505. break;
  506. case 15:
  507. r = Parse<TX509Validity4yDateTimeParserDeprecated, TInstant>(input, 15, TInstant::Max());
  508. break;
  509. default:
  510. return false;
  511. }
  512. if (r == TInstant::Max())
  513. return false;
  514. utcTime = r.TimeT();
  515. return true;
  516. }
  517. bool ParseRFC822DateTime(const char* input, time_t& utcTime) {
  518. return ParseRFC822DateTime(input, strlen(input), utcTime);
  519. }
  520. bool ParseISO8601DateTime(const char* input, time_t& utcTime) {
  521. return ParseISO8601DateTime(input, strlen(input), utcTime);
  522. }
  523. bool ParseHTTPDateTime(const char* input, time_t& utcTime) {
  524. return ParseHTTPDateTime(input, strlen(input), utcTime);
  525. }
  526. bool ParseX509ValidityDateTime(const char* input, time_t& utcTime) {
  527. return ParseX509ValidityDateTime(input, strlen(input), utcTime);
  528. }
  529. bool ParseRFC822DateTime(const char* input, size_t inputLen, time_t& utcTime) {
  530. try {
  531. utcTime = ParseUnsafe<TRfc822DateTimeParser, TInstant>(input, inputLen).TimeT();
  532. return true;
  533. } catch (const TDateTimeParseException&) {
  534. return false;
  535. }
  536. }
  537. bool ParseISO8601DateTime(const char* input, size_t inputLen, time_t& utcTime) {
  538. try {
  539. utcTime = ParseUnsafe<TIso8601DateTimeParser, TInstant>(input, inputLen).TimeT();
  540. return true;
  541. } catch (const TDateTimeParseException&) {
  542. return false;
  543. }
  544. }
  545. bool ParseHTTPDateTime(const char* input, size_t inputLen, time_t& utcTime) {
  546. try {
  547. utcTime = ParseUnsafe<THttpDateTimeParser, TInstant>(input, inputLen).TimeT();
  548. return true;
  549. } catch (const TDateTimeParseException&) {
  550. return false;
  551. }
  552. }
  553. bool ParseX509ValidityDateTime(const char* input, size_t inputLen, time_t& utcTime) {
  554. TInstant r;
  555. switch (inputLen) {
  556. case 13:
  557. r = Parse<TX509ValidityDateTimeParser, TInstant>(input, 13, TInstant::Max());
  558. break;
  559. case 15:
  560. r = Parse<TX509Validity4yDateTimeParser, TInstant>(input, 15, TInstant::Max());
  561. break;
  562. default:
  563. return false;
  564. }
  565. if (r == TInstant::Max())
  566. return false;
  567. utcTime = r.TimeT();
  568. return true;
  569. }
  570. %%{
  571. machine TDurationParser;
  572. include DateTimeParserCommon;
  573. multiplier
  574. = '' # >{ MultiplierPower = 6; } # work around Ragel bugs
  575. | 'w' @{ MultiplierPower = 6; Multiplier = 604800; }
  576. | 'd' @{ MultiplierPower = 6; Multiplier = 86400; }
  577. | 'h' @{ MultiplierPower = 6; Multiplier = 3600; }
  578. | 'm' @{ MultiplierPower = 6; Multiplier = 60; }
  579. | 's' @{ MultiplierPower = 6; Multiplier = 1; }
  580. | 'ms' @{ MultiplierPower = 3; Multiplier = 1; }
  581. | 'us' @{ MultiplierPower = 0; Multiplier = 1; }
  582. | 'ns' @{ MultiplierPower = -3; Multiplier = 1; }
  583. ;
  584. integer = int @{ IntegerPart = I; };
  585. fraction = '.' digit {1,6} >clear_int $update_int @{ FractionPart = I; FractionDigits = Dc; } digit*;
  586. duration = integer fraction? multiplier;
  587. main := duration;
  588. write data noerror;
  589. }%%
  590. TDurationParser::TDurationParser()
  591. : cs(0)
  592. , I(0)
  593. , Dc(0)
  594. , MultiplierPower(6)
  595. , Multiplier(1)
  596. , IntegerPart(0)
  597. , FractionPart(0)
  598. , FractionDigits(0)
  599. {
  600. Y_UNUSED(TDurationParser_en_main);
  601. %% write init;
  602. }
  603. bool TDurationParser::ParsePart(const char* input, size_t len) {
  604. const char* p = input;
  605. const char* pe = input + len;
  606. %% write exec;
  607. return cs != %%{ write error; }%%;
  608. }
  609. static inline ui64 DecPower(ui64 part, i32 power) {
  610. if (power >= 0)
  611. return part * Power(10, power);
  612. return part / Power(10, -power);
  613. }
  614. TDuration TDurationParser::GetResult(TDuration defaultValue) const {
  615. if (cs < TDurationParser_first_final)
  616. return defaultValue;
  617. ui64 us = 0;
  618. us += Multiplier * DecPower(IntegerPart, MultiplierPower);
  619. us += Multiplier * DecPower(FractionPart, MultiplierPower - FractionDigits);
  620. return TDuration::MicroSeconds(us);
  621. }
  622. bool TDuration::TryParse(const TStringBuf input, TDuration& result) {
  623. TDuration r = ::Parse<TDurationParser, TDuration>(input.data(), input.size(), TDuration::Max());
  624. if (r == TDuration::Max())
  625. return false;
  626. result = r;
  627. return true;
  628. }
  629. TDuration TDuration::Parse(const TStringBuf input) {
  630. return ParseUnsafe<TDurationParser, TDuration>(input.data(), input.size());
  631. }