DateTimeCommon.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/utils/DateTime.h>
  6. #include <aws/core/platform/Time.h>
  7. #include <aws/core/utils/memory/stl/AWSStringStream.h>
  8. #include <aws/core/utils/logging/LogMacros.h>
  9. #include <time.h>
  10. #include <cassert>
  11. #include <iostream>
  12. #include <cstring>
  13. static const char* CLASS_TAG = "DateTime";
  14. static const char* RFC822_DATE_FORMAT_STR_MINUS_Z = "%a, %d %b %Y %H:%M:%S";
  15. static const char* RFC822_DATE_FORMAT_STR_WITH_Z = "%a, %d %b %Y %H:%M:%S %Z";
  16. static const char* ISO_8601_LONG_DATE_FORMAT_STR = "%Y-%m-%dT%H:%M:%SZ";
  17. static const char* ISO_8601_LONG_BASIC_DATE_FORMAT_STR = "%Y%m%dT%H%M%SZ";
  18. using namespace Aws::Utils;
  19. std::tm CreateZeroedTm()
  20. {
  21. std::tm timeStruct;
  22. timeStruct.tm_hour = 0;
  23. timeStruct.tm_isdst = -1;
  24. timeStruct.tm_mday = 0;
  25. timeStruct.tm_min = 0;
  26. timeStruct.tm_mon = 0;
  27. timeStruct.tm_sec = 0;
  28. timeStruct.tm_wday = 0;
  29. timeStruct.tm_yday = 0;
  30. timeStruct.tm_year = 0;
  31. return timeStruct;
  32. }
  33. //Get the 0-6 week day number from a string representing WeekDay. Case insensitive and will stop on abbreviation
  34. static int GetWeekDayNumberFromStr(const char* timeString, size_t startIndex, size_t stopIndex)
  35. {
  36. if(stopIndex - startIndex < 3)
  37. {
  38. return -1;
  39. }
  40. size_t index = startIndex;
  41. char c = timeString[index];
  42. char next = 0;
  43. //it's ugly but this should compile down to EXACTLY 3 comparisons and no memory allocations
  44. switch(c)
  45. {
  46. case 'S':
  47. case 's':
  48. next = timeString[++index];
  49. switch(next)
  50. {
  51. case 'A':
  52. case 'a':
  53. next = timeString[++index];
  54. switch (next)
  55. {
  56. case 'T':
  57. case 't':
  58. return 6;
  59. default:
  60. return -1;
  61. }
  62. case 'U':
  63. case 'u':
  64. next = timeString[++index];
  65. switch (next)
  66. {
  67. case 'N':
  68. case 'n':
  69. return 0;
  70. default:
  71. return -1;
  72. }
  73. default:
  74. return -1;
  75. }
  76. case 'T':
  77. case 't':
  78. next = timeString[++index];
  79. switch (next)
  80. {
  81. case 'H':
  82. case 'h':
  83. next = timeString[++index];
  84. switch(next)
  85. {
  86. case 'U':
  87. case 'u':
  88. return 4;
  89. default:
  90. return -1;
  91. }
  92. case 'U':
  93. case 'u':
  94. next = timeString[++index];
  95. switch(next)
  96. {
  97. case 'E':
  98. case 'e':
  99. return 2;
  100. default:
  101. return -1;
  102. }
  103. default:
  104. return -1;
  105. }
  106. case 'M':
  107. case 'm':
  108. next = timeString[++index];
  109. switch(next)
  110. {
  111. case 'O':
  112. case 'o':
  113. next = timeString[++index];
  114. switch (next)
  115. {
  116. case 'N':
  117. case 'n':
  118. return 1;
  119. default:
  120. return -1;
  121. }
  122. default:
  123. return -1;
  124. }
  125. case 'W':
  126. case 'w':
  127. next = timeString[++index];
  128. switch (next)
  129. {
  130. case 'E':
  131. case 'e':
  132. next = timeString[++index];
  133. switch (next)
  134. {
  135. case 'D':
  136. case 'd':
  137. return 3;
  138. default:
  139. return -1;
  140. }
  141. default:
  142. return -1;
  143. }
  144. case 'F':
  145. case 'f':
  146. next = timeString[++index];
  147. switch (next)
  148. {
  149. case 'R':
  150. case 'r':
  151. next = timeString[++index];
  152. switch (next)
  153. {
  154. case 'I':
  155. case 'i':
  156. return 5;
  157. default:
  158. return -1;
  159. }
  160. default:
  161. return -1;
  162. }
  163. default:
  164. return -1;
  165. }
  166. }
  167. //Get the 0-11 monthly number from a string representing Month. Case insensitive and will stop on abbreviation
  168. static int GetMonthNumberFromStr(const char* timeString, size_t startIndex, size_t stopIndex)
  169. {
  170. if (stopIndex - startIndex < 3)
  171. {
  172. return -1;
  173. }
  174. size_t index = startIndex;
  175. char c = timeString[index];
  176. char next = 0;
  177. //it's ugly but this should compile down to EXACTLY 3 comparisons and no memory allocations
  178. switch (c)
  179. {
  180. case 'M':
  181. case 'm':
  182. next = timeString[++index];
  183. switch (next)
  184. {
  185. case 'A':
  186. case 'a':
  187. next = timeString[++index];
  188. switch (next)
  189. {
  190. case 'Y':
  191. case 'y':
  192. return 4;
  193. case 'R':
  194. case 'r':
  195. return 2;
  196. default:
  197. return -1;
  198. }
  199. default:
  200. return -1;
  201. }
  202. case 'A':
  203. case 'a':
  204. next = timeString[++index];
  205. switch (next)
  206. {
  207. case 'P':
  208. case 'p':
  209. next = timeString[++index];
  210. switch (next)
  211. {
  212. case 'R':
  213. case 'r':
  214. return 3;
  215. default:
  216. return -1;
  217. }
  218. case 'U':
  219. case 'u':
  220. next = timeString[++index];
  221. switch (next)
  222. {
  223. case 'G':
  224. case 'g':
  225. return 7;
  226. default:
  227. return -1;
  228. }
  229. default:
  230. return -1;
  231. }
  232. case 'J':
  233. case 'j':
  234. next = timeString[++index];
  235. switch (next)
  236. {
  237. case 'A':
  238. case 'a':
  239. next = timeString[++index];
  240. switch (next)
  241. {
  242. case 'N':
  243. case 'n':
  244. return 0;
  245. default:
  246. return -1;
  247. }
  248. case 'U':
  249. case 'u':
  250. next = timeString[++index];
  251. switch (next)
  252. {
  253. case 'N':
  254. case 'n':
  255. return 5;
  256. case 'L':
  257. case 'l':
  258. return 6;
  259. default:
  260. return -1;
  261. }
  262. default:
  263. return -1;
  264. }
  265. case 'F':
  266. case 'f':
  267. next = timeString[++index];
  268. switch (next)
  269. {
  270. case 'E':
  271. case 'e':
  272. next = timeString[++index];
  273. switch (next)
  274. {
  275. case 'B':
  276. case 'b':
  277. return 1;
  278. default:
  279. return -1;
  280. }
  281. default:
  282. return -1;
  283. }
  284. case 'S':
  285. case 's':
  286. next = timeString[++index];
  287. switch (next)
  288. {
  289. case 'E':
  290. case 'e':
  291. next = timeString[++index];
  292. switch (next)
  293. {
  294. case 'P':
  295. case 'p':
  296. return 8;
  297. default:
  298. return -1;
  299. }
  300. default:
  301. return -1;
  302. }
  303. case 'O':
  304. case 'o':
  305. next = timeString[++index];
  306. switch (next)
  307. {
  308. case 'C':
  309. case 'c':
  310. next = timeString[++index];
  311. switch (next)
  312. {
  313. case 'T':
  314. case 't':
  315. return 9;
  316. default:
  317. return -1;
  318. }
  319. default:
  320. return -1;
  321. }
  322. case 'N':
  323. case 'n':
  324. next = timeString[++index];
  325. switch (next)
  326. {
  327. case 'O':
  328. case 'o':
  329. next = timeString[++index];
  330. switch (next)
  331. {
  332. case 'V':
  333. case 'v':
  334. return 10;
  335. default:
  336. return -1;
  337. }
  338. default:
  339. return -1;
  340. }
  341. case 'D':
  342. case 'd':
  343. next = timeString[++index];
  344. switch (next)
  345. {
  346. case 'E':
  347. case 'e':
  348. next = timeString[++index];
  349. switch (next)
  350. {
  351. case 'C':
  352. case 'c':
  353. return 11;
  354. default:
  355. return -1;
  356. }
  357. default:
  358. return -1;
  359. }
  360. default:
  361. return -1;
  362. }
  363. }
  364. // Ensure local classes with generic names have internal linkage
  365. namespace {
  366. class DateParser
  367. {
  368. public:
  369. DateParser(const char* toParse) : m_error(false), m_toParse(toParse), m_utcAssumed(true)
  370. {
  371. m_parsedTimestamp = CreateZeroedTm();
  372. memset(m_tz, 0, 7);
  373. }
  374. virtual ~DateParser() = default;
  375. virtual void Parse() = 0;
  376. bool WasParseSuccessful() const { return !m_error; }
  377. std::tm& GetParsedTimestamp() { return m_parsedTimestamp; }
  378. bool ShouldIAssumeThisIsUTC() const { return m_utcAssumed; }
  379. const char* GetParsedTimezone() const { return m_tz; }
  380. protected:
  381. bool m_error;
  382. const char* m_toParse;
  383. std::tm m_parsedTimestamp;
  384. bool m_utcAssumed;
  385. // The size should be at least one byte greater than the maximum possible size so that we could use the last char to indicate the end of the string.
  386. char m_tz[7];
  387. };
  388. static const int MAX_LEN = 100;
  389. //Before you send me hate mail because I'm doing this manually, I encourage you to try using std::get_time on all platforms and getting
  390. //uniform results. Timezone information doesn't parse on Windows and it hardly even works on GCC 4.9.x. This is the only way to make sure
  391. //the standard is parsed correctly. strptime isn't available one Windows. This code gets hit pretty hard during http serialization/deserialization
  392. //as a result I'm going for no dynamic allocations and linear complexity
  393. class RFC822DateParser : public DateParser
  394. {
  395. public:
  396. RFC822DateParser(const char* toParse) : DateParser(toParse), m_state(0)
  397. {
  398. }
  399. /**
  400. * Really simple state machine for the format %a, %d %b %Y %H:%M:%S %Z
  401. */
  402. void Parse() override
  403. {
  404. size_t len = strlen(m_toParse);
  405. //DOS check
  406. if (len > MAX_LEN)
  407. {
  408. AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len)
  409. m_error = true;
  410. return;
  411. }
  412. size_t index = 0;
  413. size_t stateStartIndex = 0;
  414. int finalState = 8;
  415. while(m_state <= finalState && !m_error && index < len)
  416. {
  417. char c = m_toParse[index];
  418. switch (m_state)
  419. {
  420. case 0:
  421. if(c == ',')
  422. {
  423. int weekNumber = GetWeekDayNumberFromStr(m_toParse, stateStartIndex, index + 1);
  424. if (weekNumber > -1)
  425. {
  426. m_state = 1;
  427. stateStartIndex = index + 1;
  428. m_parsedTimestamp.tm_wday = weekNumber;
  429. }
  430. else
  431. {
  432. m_error = true;
  433. }
  434. }
  435. else if(!isalpha(c))
  436. {
  437. m_error = true;
  438. }
  439. break;
  440. case 1:
  441. if (isspace(c))
  442. {
  443. m_state = 2;
  444. stateStartIndex = index + 1;
  445. }
  446. else
  447. {
  448. m_error = true;
  449. }
  450. break;
  451. case 2:
  452. if (isdigit(c))
  453. {
  454. m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0');
  455. }
  456. else if(isspace(c))
  457. {
  458. m_state = 3;
  459. stateStartIndex = index + 1;
  460. }
  461. else
  462. {
  463. m_error = true;
  464. }
  465. break;
  466. case 3:
  467. if (isspace(c))
  468. {
  469. int monthNumber = GetMonthNumberFromStr(m_toParse, stateStartIndex, index + 1);
  470. if (monthNumber > -1)
  471. {
  472. m_state = 4;
  473. stateStartIndex = index + 1;
  474. m_parsedTimestamp.tm_mon = monthNumber;
  475. }
  476. else
  477. {
  478. m_error = true;
  479. }
  480. }
  481. else if (!isalpha(c))
  482. {
  483. m_error = true;
  484. }
  485. break;
  486. case 4:
  487. if (isspace(c) && index - stateStartIndex == 4)
  488. {
  489. m_state = 5;
  490. stateStartIndex = index + 1;
  491. m_parsedTimestamp.tm_year -= 1900;
  492. }
  493. else if (isspace(c) && index - stateStartIndex == 2)
  494. {
  495. m_state = 5;
  496. stateStartIndex = index + 1;
  497. m_parsedTimestamp.tm_year += 2000 - 1900;
  498. }
  499. else if (isdigit(c))
  500. {
  501. m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0');
  502. }
  503. else
  504. {
  505. m_error = true;
  506. }
  507. break;
  508. case 5:
  509. if(c == ':' && index - stateStartIndex == 2)
  510. {
  511. m_state = 6;
  512. stateStartIndex = index + 1;
  513. }
  514. else if (isdigit(c))
  515. {
  516. m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0');
  517. }
  518. else
  519. {
  520. m_error = true;
  521. }
  522. break;
  523. case 6:
  524. if (c == ':' && index - stateStartIndex == 2)
  525. {
  526. m_state = 7;
  527. stateStartIndex = index + 1;
  528. }
  529. else if (isdigit(c))
  530. {
  531. m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0');
  532. }
  533. else
  534. {
  535. m_error = true;
  536. }
  537. break;
  538. case 7:
  539. if (isspace(c) && index - stateStartIndex == 2)
  540. {
  541. m_state = 8;
  542. stateStartIndex = index + 1;
  543. }
  544. else if (isdigit(c))
  545. {
  546. m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0');
  547. }
  548. else
  549. {
  550. m_error = true;
  551. }
  552. break;
  553. case 8:
  554. if ((isalnum(c) || c == '+' || c == '-') && (index - stateStartIndex < 5))
  555. {
  556. m_tz[index - stateStartIndex] = c;
  557. }
  558. else
  559. {
  560. m_error = true;
  561. }
  562. break;
  563. default:
  564. m_error = true;
  565. break;
  566. }
  567. index++;
  568. }
  569. if (m_tz[0] != 0)
  570. {
  571. m_utcAssumed = IsUTCTimeZoneDesignator(m_tz);
  572. }
  573. m_error = (m_error || m_state != finalState);
  574. }
  575. int GetState() const { return m_state; }
  576. private:
  577. //Detects whether or not the passed in timezone string is a UTC zone.
  578. static bool IsUTCTimeZoneDesignator(const char* str)
  579. {
  580. size_t len = strlen(str);
  581. if (len < 3)
  582. {
  583. return false;
  584. }
  585. int index = 0;
  586. char c = str[index];
  587. switch (c)
  588. {
  589. case 'U':
  590. case 'u':
  591. c = str[++index];
  592. switch(c)
  593. {
  594. case 'T':
  595. case 't':
  596. c = str[++index];
  597. switch(c)
  598. {
  599. case 'C':
  600. case 'c':
  601. return true;
  602. default:
  603. return false;
  604. }
  605. case 'C':
  606. case 'c':
  607. c = str[++index];
  608. switch (c)
  609. {
  610. case 'T':
  611. case 't':
  612. return true;
  613. default:
  614. return false;
  615. }
  616. default:
  617. return false;
  618. }
  619. case 'G':
  620. case 'g':
  621. c = str[++index];
  622. switch (c)
  623. {
  624. case 'M':
  625. case 'm':
  626. c = str[++index];
  627. switch (c)
  628. {
  629. case 'T':
  630. case 't':
  631. return true;
  632. default:
  633. return false;
  634. }
  635. default:
  636. return false;
  637. }
  638. case '+':
  639. case '-':
  640. c = str[++index];
  641. switch (c)
  642. {
  643. case '0':
  644. c = str[++index];
  645. switch (c)
  646. {
  647. case '0':
  648. c = str[++index];
  649. switch (c)
  650. {
  651. case '0':
  652. return true;
  653. default:
  654. return false;
  655. }
  656. default:
  657. return false;
  658. }
  659. default:
  660. return false;
  661. }
  662. case 'Z':
  663. return true;
  664. default:
  665. return false;
  666. }
  667. }
  668. int m_state;
  669. };
  670. //Before you send me hate mail because I'm doing this manually, I encourage you to try using std::get_time on all platforms and getting
  671. //uniform results. Timezone information doesn't parse on Windows and it hardly even works on GCC 4.9.x. This is the only way to make sure
  672. //the standard is parsed correctly. strptime isn't available one Windows. This code gets hit pretty hard during http serialization/deserialization
  673. //as a result I'm going for no dynamic allocations and linear complexity
  674. class ISO_8601DateParser : public DateParser
  675. {
  676. public:
  677. ISO_8601DateParser(const char* stringToParse) : DateParser(stringToParse), m_state(0)
  678. {
  679. }
  680. //parses "%Y-%m-%dT%H:%M:%SZ or "%Y-%m-%dT%H:%M:%S.000Z"
  681. void Parse() override
  682. {
  683. size_t len = strlen(m_toParse);
  684. //DOS check
  685. if (len > MAX_LEN)
  686. {
  687. AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len)
  688. m_error = true;
  689. return;
  690. }
  691. size_t index = 0;
  692. size_t stateStartIndex = 0;
  693. const int finalState = 7;
  694. while (m_state <= finalState && !m_error && index < len)
  695. {
  696. char c = m_toParse[index];
  697. switch (m_state)
  698. {
  699. case 0:
  700. if (c == '-' && index - stateStartIndex == 4)
  701. {
  702. m_state = 1;
  703. stateStartIndex = index + 1;
  704. m_parsedTimestamp.tm_year -= 1900;
  705. }
  706. else if (isdigit(c))
  707. {
  708. m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0');
  709. }
  710. else
  711. {
  712. m_error = true;
  713. }
  714. break;
  715. case 1:
  716. if (c == '-' && index - stateStartIndex == 2)
  717. {
  718. m_state = 2;
  719. stateStartIndex = index + 1;
  720. m_parsedTimestamp.tm_mon -= 1;
  721. }
  722. else if (isdigit(c))
  723. {
  724. m_parsedTimestamp.tm_mon = m_parsedTimestamp.tm_mon * 10 + (c - '0');
  725. }
  726. else
  727. {
  728. m_error = true;
  729. }
  730. break;
  731. case 2:
  732. if (c == 'T' && index - stateStartIndex == 2)
  733. {
  734. m_state = 3;
  735. stateStartIndex = index + 1;
  736. }
  737. else if (isdigit(c))
  738. {
  739. m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0');
  740. }
  741. else
  742. {
  743. m_error = true;
  744. }
  745. break;
  746. case 3:
  747. if (c == ':' && index - stateStartIndex == 2)
  748. {
  749. m_state = 4;
  750. stateStartIndex = index + 1;
  751. }
  752. else if (isdigit(c))
  753. {
  754. m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0');
  755. }
  756. else
  757. {
  758. m_error = true;
  759. }
  760. break;
  761. case 4:
  762. if (c == ':' && index - stateStartIndex == 2)
  763. {
  764. m_state = 5;
  765. stateStartIndex = index + 1;
  766. }
  767. else if (isdigit(c))
  768. {
  769. m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0');
  770. }
  771. else
  772. {
  773. m_error = true;
  774. }
  775. break;
  776. case 5:
  777. if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 2))
  778. {
  779. m_tz[0] = c;
  780. m_state = 7;
  781. stateStartIndex = index + 1;
  782. }
  783. else if (c == '.' && index - stateStartIndex == 2)
  784. {
  785. m_state = 6;
  786. stateStartIndex = index + 1;
  787. }
  788. else if (isdigit(c))
  789. {
  790. m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0');
  791. }
  792. else
  793. {
  794. m_error = true;
  795. }
  796. break;
  797. case 6:
  798. if ((c == 'Z' || c == '+' || c == '-' ) &&
  799. (index - stateStartIndex >= 3) &&
  800. (index - stateStartIndex <= 9))
  801. {
  802. m_tz[0] = c;
  803. m_state = 7;
  804. stateStartIndex = index + 1;
  805. }
  806. else if(!isdigit(c))
  807. {
  808. m_error = true;
  809. }
  810. break;
  811. case 7:
  812. if ((isdigit(c) || c == ':') && (index - stateStartIndex < 5))
  813. {
  814. m_tz[1 + index - stateStartIndex] = c;
  815. }
  816. else
  817. {
  818. m_error = true;
  819. }
  820. break;
  821. default:
  822. m_error = true;
  823. break;
  824. }
  825. index++;
  826. }
  827. if (m_tz[0] != 0)
  828. {
  829. m_utcAssumed = IsUTCTimeZoneDesignator(m_tz);
  830. }
  831. m_error = (m_error || m_state != finalState);
  832. }
  833. private:
  834. //Detects whether or not the passed in timezone string is a UTC zone.
  835. static bool IsUTCTimeZoneDesignator(const char* str)
  836. {
  837. size_t len = strlen(str);
  838. if (len > 0)
  839. {
  840. if (len == 1 && str[0] == 'Z')
  841. {
  842. return true;
  843. }
  844. if (len == 6 && str[0] == '+'
  845. && str[1] == '0'
  846. && str[2] == '0'
  847. && str[3] == ':'
  848. && str[4] == '0'
  849. && str[5] == '0')
  850. {
  851. return true;
  852. }
  853. return false;
  854. }
  855. return false;
  856. }
  857. int m_state;
  858. };
  859. class ISO_8601BasicDateParser : public DateParser
  860. {
  861. public:
  862. ISO_8601BasicDateParser(const char* stringToParse) : DateParser(stringToParse), m_state(0)
  863. {
  864. }
  865. //parses "%Y%m%dT%H%M%SZ or "%Y%m%dT%H%M%S000Z"
  866. void Parse() override
  867. {
  868. size_t len = strlen(m_toParse);
  869. //DOS check
  870. if (len > MAX_LEN)
  871. {
  872. AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len)
  873. m_error = true;
  874. return;
  875. }
  876. size_t index = 0;
  877. size_t stateStartIndex = 0;
  878. const int finalState = 7;
  879. while (m_state <= finalState && !m_error && index < len)
  880. {
  881. char c = m_toParse[index];
  882. switch (m_state)
  883. {
  884. // On year: %Y
  885. case 0:
  886. if (isdigit(c))
  887. {
  888. m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0');
  889. if (index - stateStartIndex == 3)
  890. {
  891. m_state = 1;
  892. stateStartIndex = index + 1;
  893. m_parsedTimestamp.tm_year -= 1900;
  894. }
  895. }
  896. else
  897. {
  898. m_error = true;
  899. }
  900. break;
  901. // On month: %m
  902. case 1:
  903. if (isdigit(c))
  904. {
  905. m_parsedTimestamp.tm_mon = m_parsedTimestamp.tm_mon * 10 + (c - '0');
  906. if (index - stateStartIndex == 1)
  907. {
  908. m_state = 2;
  909. stateStartIndex = index + 1;
  910. m_parsedTimestamp.tm_mon -= 1;
  911. }
  912. }
  913. else
  914. {
  915. m_error = true;
  916. }
  917. break;
  918. // On month day: %d
  919. case 2:
  920. if (c == 'T' && index - stateStartIndex == 2)
  921. {
  922. m_state = 3;
  923. stateStartIndex = index + 1;
  924. }
  925. else if (isdigit(c))
  926. {
  927. m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0');
  928. }
  929. else
  930. {
  931. m_error = true;
  932. }
  933. break;
  934. // On hour: %H
  935. case 3:
  936. if (isdigit(c))
  937. {
  938. m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0');
  939. if (index - stateStartIndex == 1)
  940. {
  941. m_state = 4;
  942. stateStartIndex = index + 1;
  943. }
  944. }
  945. else
  946. {
  947. m_error = true;
  948. }
  949. break;
  950. // On minute: %M
  951. case 4:
  952. if (isdigit(c))
  953. {
  954. m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0');
  955. if (index - stateStartIndex == 1)
  956. {
  957. m_state = 5;
  958. stateStartIndex = index + 1;
  959. }
  960. }
  961. else
  962. {
  963. m_error = true;
  964. }
  965. break;
  966. // On second: %S
  967. case 5:
  968. if (isdigit(c))
  969. {
  970. m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0');
  971. if (index - stateStartIndex == 1)
  972. {
  973. m_state = 6;
  974. stateStartIndex = index + 1;
  975. }
  976. }
  977. else
  978. {
  979. m_error = true;
  980. }
  981. break;
  982. // On TZ: Z or 000Z
  983. case 6:
  984. if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 0 || index - stateStartIndex == 3))
  985. {
  986. m_tz[0] = c;
  987. m_state = 7;
  988. stateStartIndex = index + 1;
  989. }
  990. else if (!isdigit(c) || index - stateStartIndex > 3)
  991. {
  992. m_error = true;
  993. }
  994. break;
  995. case 7:
  996. if ((isdigit(c) || c == ':') && (index - stateStartIndex < 5))
  997. {
  998. m_tz[1 + index - stateStartIndex] = c;
  999. }
  1000. else
  1001. {
  1002. m_error = true;
  1003. }
  1004. break;
  1005. default:
  1006. m_error = true;
  1007. break;
  1008. }
  1009. index++;
  1010. }
  1011. if (m_tz[0] != 0)
  1012. {
  1013. m_utcAssumed = IsUTCTimeZoneDesignator(m_tz);
  1014. }
  1015. m_error = (m_error || m_state != finalState);
  1016. }
  1017. private:
  1018. //Detects whether or not the passed in timezone string is a UTC zone.
  1019. static bool IsUTCTimeZoneDesignator(const char* str)
  1020. {
  1021. size_t len = strlen(str);
  1022. if (len > 0)
  1023. {
  1024. if (len == 1 && str[0] == 'Z')
  1025. {
  1026. return true;
  1027. }
  1028. if (len == 5 && str[0] == '+'
  1029. && str[1] == '0'
  1030. && str[2] == '0'
  1031. && str[3] == '0'
  1032. && str[4] == '0')
  1033. {
  1034. return true;
  1035. }
  1036. return false;
  1037. }
  1038. return false;
  1039. }
  1040. int m_state;
  1041. };
  1042. } // namespace
  1043. DateTime::DateTime(const std::chrono::system_clock::time_point& timepointToAssign) : m_time(timepointToAssign), m_valid(true)
  1044. {
  1045. }
  1046. DateTime::DateTime(int64_t millisSinceEpoch) : m_valid(true)
  1047. {
  1048. std::chrono::duration<int64_t, std::chrono::milliseconds::period> timestamp(millisSinceEpoch);
  1049. m_time = std::chrono::system_clock::time_point(timestamp);
  1050. }
  1051. DateTime::DateTime(double epoch_millis) : m_valid(true)
  1052. {
  1053. std::chrono::duration<double, std::chrono::seconds::period> timestamp(epoch_millis);
  1054. m_time = std::chrono::system_clock::time_point(std::chrono::duration_cast<std::chrono::milliseconds>(timestamp));
  1055. }
  1056. DateTime::DateTime(const Aws::String& timestamp, DateFormat format) : m_valid(true)
  1057. {
  1058. ConvertTimestampStringToTimePoint(timestamp.c_str(), format);
  1059. }
  1060. DateTime::DateTime(const char* timestamp, DateFormat format) : m_valid(true)
  1061. {
  1062. ConvertTimestampStringToTimePoint(timestamp, format);
  1063. }
  1064. DateTime::DateTime() : m_valid(true)
  1065. {
  1066. //init time_point to default by doing nothing.
  1067. }
  1068. DateTime& DateTime::operator=(const Aws::String& timestamp)
  1069. {
  1070. *this = DateTime(timestamp, DateFormat::AutoDetect);
  1071. return *this;
  1072. }
  1073. DateTime& DateTime::operator=(double secondsMillis)
  1074. {
  1075. *this = DateTime(secondsMillis);
  1076. return *this;
  1077. }
  1078. DateTime& DateTime::operator=(int64_t millisSinceEpoch)
  1079. {
  1080. *this = DateTime(millisSinceEpoch);
  1081. return *this;
  1082. }
  1083. DateTime& DateTime::operator=(const std::chrono::system_clock::time_point& timepointToAssign)
  1084. {
  1085. *this = DateTime(timepointToAssign);
  1086. return *this;
  1087. }
  1088. bool DateTime::operator == (const DateTime& other) const
  1089. {
  1090. return m_time == other.m_time;
  1091. }
  1092. bool DateTime::operator < (const DateTime& other) const
  1093. {
  1094. return m_time < other.m_time;
  1095. }
  1096. bool DateTime::operator > (const DateTime& other) const
  1097. {
  1098. return m_time > other.m_time;
  1099. }
  1100. bool DateTime::operator != (const DateTime& other) const
  1101. {
  1102. return m_time != other.m_time;
  1103. }
  1104. bool DateTime::operator <= (const DateTime& other) const
  1105. {
  1106. return m_time <= other.m_time;
  1107. }
  1108. bool DateTime::operator >= (const DateTime& other) const
  1109. {
  1110. return m_time >= other.m_time;
  1111. }
  1112. DateTime DateTime::operator +(const std::chrono::milliseconds& a) const
  1113. {
  1114. auto timepointCpy = m_time;
  1115. timepointCpy += a;
  1116. return DateTime(timepointCpy);
  1117. }
  1118. DateTime DateTime::operator -(const std::chrono::milliseconds& a) const
  1119. {
  1120. auto timepointCpy = m_time;
  1121. timepointCpy -= a;
  1122. return DateTime(timepointCpy);
  1123. }
  1124. Aws::String DateTime::ToLocalTimeString(DateFormat format) const
  1125. {
  1126. switch (format)
  1127. {
  1128. case DateFormat::ISO_8601:
  1129. return ToLocalTimeString(ISO_8601_LONG_DATE_FORMAT_STR);
  1130. case DateFormat::ISO_8601_BASIC:
  1131. return ToLocalTimeString(ISO_8601_LONG_BASIC_DATE_FORMAT_STR);
  1132. case DateFormat::RFC822:
  1133. return ToLocalTimeString(RFC822_DATE_FORMAT_STR_WITH_Z);
  1134. default:
  1135. assert(0);
  1136. return "";
  1137. }
  1138. }
  1139. Aws::String DateTime::ToLocalTimeString(const char* formatStr) const
  1140. {
  1141. struct tm localTimeStamp = ConvertTimestampToLocalTimeStruct();
  1142. char formattedString[100];
  1143. std::strftime(formattedString, sizeof(formattedString), formatStr, &localTimeStamp);
  1144. return formattedString;
  1145. }
  1146. Aws::String DateTime::ToGmtString(DateFormat format) const
  1147. {
  1148. switch (format)
  1149. {
  1150. case DateFormat::ISO_8601:
  1151. return ToGmtString(ISO_8601_LONG_DATE_FORMAT_STR);
  1152. case DateFormat::ISO_8601_BASIC:
  1153. return ToGmtString(ISO_8601_LONG_BASIC_DATE_FORMAT_STR);
  1154. case DateFormat::RFC822:
  1155. {
  1156. //Windows erroneously drops the local timezone in for %Z
  1157. Aws::String rfc822GmtString = ToGmtString(RFC822_DATE_FORMAT_STR_MINUS_Z);
  1158. rfc822GmtString += " GMT";
  1159. return rfc822GmtString;
  1160. }
  1161. default:
  1162. assert(0);
  1163. return "";
  1164. }
  1165. }
  1166. Aws::String DateTime::ToGmtString(const char* formatStr) const
  1167. {
  1168. struct tm gmtTimeStamp = ConvertTimestampToGmtStruct();
  1169. char formattedString[100];
  1170. std::strftime(formattedString, sizeof(formattedString), formatStr, &gmtTimeStamp);
  1171. return formattedString;
  1172. }
  1173. double DateTime::SecondsWithMSPrecision() const
  1174. {
  1175. std::chrono::duration<double, std::chrono::seconds::period> timestamp(m_time.time_since_epoch());
  1176. return timestamp.count();
  1177. }
  1178. int64_t DateTime::Seconds() const
  1179. {
  1180. auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(m_time.time_since_epoch());
  1181. return timestamp.count();
  1182. }
  1183. int64_t DateTime::Millis() const
  1184. {
  1185. auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch());
  1186. return timestamp.count();
  1187. }
  1188. std::chrono::system_clock::time_point DateTime::UnderlyingTimestamp() const
  1189. {
  1190. return m_time;
  1191. }
  1192. int DateTime::GetYear(bool localTime) const
  1193. {
  1194. return GetTimeStruct(localTime).tm_year + 1900;
  1195. }
  1196. Month DateTime::GetMonth(bool localTime) const
  1197. {
  1198. return static_cast<Aws::Utils::Month>(GetTimeStruct(localTime).tm_mon);
  1199. }
  1200. int DateTime::GetDay(bool localTime) const
  1201. {
  1202. return GetTimeStruct(localTime).tm_mday;
  1203. }
  1204. DayOfWeek DateTime::GetDayOfWeek(bool localTime) const
  1205. {
  1206. return static_cast<Aws::Utils::DayOfWeek>(GetTimeStruct(localTime).tm_wday);
  1207. }
  1208. int DateTime::GetHour(bool localTime) const
  1209. {
  1210. return GetTimeStruct(localTime).tm_hour;
  1211. }
  1212. int DateTime::GetMinute(bool localTime) const
  1213. {
  1214. return GetTimeStruct(localTime).tm_min;
  1215. }
  1216. int DateTime::GetSecond(bool localTime) const
  1217. {
  1218. return GetTimeStruct(localTime).tm_sec;
  1219. }
  1220. bool DateTime::IsDST(bool localTime) const
  1221. {
  1222. return GetTimeStruct(localTime).tm_isdst == 0 ? false : true;
  1223. }
  1224. DateTime DateTime::Now()
  1225. {
  1226. DateTime dateTime;
  1227. dateTime.m_time = std::chrono::system_clock::now();
  1228. return dateTime;
  1229. }
  1230. int64_t DateTime::CurrentTimeMillis()
  1231. {
  1232. return Now().Millis();
  1233. }
  1234. Aws::String DateTime::CalculateLocalTimestampAsString(const char* formatStr)
  1235. {
  1236. DateTime now = Now();
  1237. return now.ToLocalTimeString(formatStr);
  1238. }
  1239. Aws::String DateTime::CalculateGmtTimestampAsString(const char* formatStr)
  1240. {
  1241. DateTime now = Now();
  1242. return now.ToGmtString(formatStr);
  1243. }
  1244. Aws::String DateTime::CalculateGmtTimeWithMsPrecision()
  1245. {
  1246. auto now = DateTime::Now();
  1247. struct tm gmtTimeStamp = now.ConvertTimestampToGmtStruct();
  1248. char formattedString[100];
  1249. auto len = std::strftime(formattedString, sizeof(formattedString), "%Y-%m-%d %H:%M:%S", &gmtTimeStamp);
  1250. if (len)
  1251. {
  1252. auto ms = now.Millis();
  1253. ms = ms - ms / 1000 * 1000; // calculate the milliseconds as fraction.
  1254. formattedString[len++] = '.';
  1255. int divisor = 100;
  1256. while(divisor)
  1257. {
  1258. auto digit = ms / divisor;
  1259. formattedString[len++] = char('0' + digit);
  1260. ms = ms - divisor * digit;
  1261. divisor /= 10;
  1262. }
  1263. formattedString[len] = '\0';
  1264. }
  1265. return formattedString;
  1266. }
  1267. int DateTime::CalculateCurrentHour()
  1268. {
  1269. return Now().GetHour(true);
  1270. }
  1271. double DateTime::ComputeCurrentTimestampInAmazonFormat()
  1272. {
  1273. return Now().SecondsWithMSPrecision();
  1274. }
  1275. std::chrono::milliseconds DateTime::Diff(const DateTime& a, const DateTime& b)
  1276. {
  1277. auto diff = a.m_time - b.m_time;
  1278. return std::chrono::duration_cast<std::chrono::milliseconds>(diff);
  1279. }
  1280. std::chrono::milliseconds DateTime::operator-(const DateTime& other) const
  1281. {
  1282. auto diff = this->m_time - other.m_time;
  1283. return std::chrono::duration_cast<std::chrono::milliseconds>(diff);
  1284. }
  1285. void DateTime::ConvertTimestampStringToTimePoint(const char* timestamp, DateFormat format)
  1286. {
  1287. std::tm timeStruct;
  1288. bool isUtc = true;
  1289. switch (format)
  1290. {
  1291. case DateFormat::RFC822:
  1292. {
  1293. RFC822DateParser parser(timestamp);
  1294. parser.Parse();
  1295. m_valid = parser.WasParseSuccessful();
  1296. isUtc = parser.ShouldIAssumeThisIsUTC();
  1297. timeStruct = parser.GetParsedTimestamp();
  1298. break;
  1299. }
  1300. case DateFormat::ISO_8601:
  1301. {
  1302. ISO_8601DateParser parser(timestamp);
  1303. parser.Parse();
  1304. m_valid = parser.WasParseSuccessful();
  1305. isUtc = parser.ShouldIAssumeThisIsUTC();
  1306. timeStruct = parser.GetParsedTimestamp();
  1307. break;
  1308. }
  1309. case DateFormat::ISO_8601_BASIC:
  1310. {
  1311. ISO_8601BasicDateParser parser(timestamp);
  1312. parser.Parse();
  1313. m_valid = parser.WasParseSuccessful();
  1314. isUtc = parser.ShouldIAssumeThisIsUTC();
  1315. timeStruct = parser.GetParsedTimestamp();
  1316. break;
  1317. }
  1318. case DateFormat::AutoDetect:
  1319. {
  1320. RFC822DateParser rfcParser(timestamp);
  1321. rfcParser.Parse();
  1322. if(rfcParser.WasParseSuccessful())
  1323. {
  1324. m_valid = true;
  1325. isUtc = rfcParser.ShouldIAssumeThisIsUTC();
  1326. timeStruct = rfcParser.GetParsedTimestamp();
  1327. break;
  1328. }
  1329. ISO_8601DateParser isoParser(timestamp);
  1330. isoParser.Parse();
  1331. if (isoParser.WasParseSuccessful())
  1332. {
  1333. m_valid = true;
  1334. isUtc = isoParser.ShouldIAssumeThisIsUTC();
  1335. timeStruct = isoParser.GetParsedTimestamp();
  1336. break;
  1337. }
  1338. ISO_8601BasicDateParser isoBasicParser(timestamp);
  1339. isoBasicParser.Parse();
  1340. if (isoBasicParser.WasParseSuccessful())
  1341. {
  1342. m_valid = true;
  1343. isUtc = isoBasicParser.ShouldIAssumeThisIsUTC();
  1344. timeStruct = isoBasicParser.GetParsedTimestamp();
  1345. break;
  1346. }
  1347. m_valid = false;
  1348. break;
  1349. }
  1350. default:
  1351. assert(0);
  1352. }
  1353. if (m_valid)
  1354. {
  1355. std::time_t tt;
  1356. if(isUtc)
  1357. {
  1358. tt = Aws::Time::TimeGM(&timeStruct);
  1359. }
  1360. else
  1361. {
  1362. assert(0);
  1363. AWS_LOGSTREAM_WARN(CLASS_TAG, "Non-UTC timestamp detected. This is always a bug. Make the world a better place and fix whatever sent you this timestamp: " << timestamp)
  1364. tt = std::mktime(&timeStruct);
  1365. }
  1366. m_time = std::chrono::system_clock::from_time_t(tt);
  1367. }
  1368. }
  1369. tm DateTime::GetTimeStruct(bool localTime) const
  1370. {
  1371. return localTime ? ConvertTimestampToLocalTimeStruct() : ConvertTimestampToGmtStruct();
  1372. }
  1373. tm DateTime::ConvertTimestampToLocalTimeStruct() const
  1374. {
  1375. std::time_t time = std::chrono::system_clock::to_time_t(m_time);
  1376. struct tm localTimeStamp;
  1377. Aws::Time::LocalTime(&localTimeStamp, time);
  1378. return localTimeStamp;
  1379. }
  1380. tm DateTime::ConvertTimestampToGmtStruct() const
  1381. {
  1382. std::time_t time = std::chrono::system_clock::to_time_t(m_time);
  1383. struct tm gmtTimeStamp;
  1384. Aws::Time::GMTime(&gmtTimeStamp, time);
  1385. return gmtTimeStamp;
  1386. }