@@ -10,48 +10,73 @@ auto to_milliseconds(T time_point) -> std::chrono::milliseconds {
1010 return std::chrono::duration_cast<std::chrono::milliseconds>(time_point.time_since_epoch ());
1111}
1212
13- TEST_CASE (" testing the iso8601 parsing " ) {
13+ TEST_CASE (" Basic ISO 8601 Parsing " ) {
1414 using std::chrono::milliseconds;
1515
1616 CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2023-04-30T16:22:18" )) == milliseconds (1682871738000 ));
17+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2022-12-31T23:59:59" )) == milliseconds (1672531199000 ));
18+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2023-01-01T00:00:00" )) == milliseconds (1672531200000 ));
19+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2023-05-01T00:00:00" )) == milliseconds (1682899200000 ));
20+ }
21+
22+ TEST_CASE (" Timezone Offset Handling" ) {
23+ using std::chrono::milliseconds;
24+
1725 CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2023-04-30T16:22:18Z" )) == milliseconds (1682871738000 ));
1826 CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2023-04-30T18:22:18+0200" )) == milliseconds (1682871738000 ));
1927 CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2023-04-30T16:22:18-0200" )) == milliseconds (1682878938000 ));
20- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18.500" )) == milliseconds (1682871738500 ));
21- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f%z}" , " 2023-04-30T16:22:18.500+0100" )) == milliseconds (1682868138500 ));
22-
23- REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T" , " 2023-04-30T16:22:18" ));
24- REQUIRE_THROWS (mgutility::chrono::parse (" %FT%T}" , " 2023-04-30T16:22:18" ));
25- REQUIRE_THROWS (mgutility::chrono::parse (" {%F %T}" , " 2023-04-30T16:22:18" ));
26- REQUIRE_THROWS (mgutility::chrono::parse (" {:%F %T}" , " 2023-04-30T16:22:18" ));
27-
28+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2016-02-29T05:00:00-0000" )) == milliseconds (1456722000000 ));
29+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2016-02-29T23:59:59+0000" )) == milliseconds (1456790399000 ));
30+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z}" , " 2016-02-29T12:00:00-1200" )) == milliseconds (1456790400000 ));
31+ }
2832
29- // Leap year: Feb 29 should work in a leap year
30- CHECK ( to_milliseconds ( mgutility ::chrono::parse ( " {:%FT%T} " , " 2020-02-29T12:00:00 " )) == milliseconds ( 1582977600000 )) ;
33+ TEST_CASE ( " AM/PM Handling " ) {
34+ using std ::chrono::milliseconds;
3135
32- // Non-leap year: Feb 29 should not exist
33- REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T}" , " 2021-02-29T12:00:00" ));
36+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T12:00:00 AM" )) == milliseconds (1682812800000 ));
37+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T12:00:00 PM" )) == milliseconds (1682856000000 ));
38+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T11:59:59 PM" )) == milliseconds (1682899199000 ));
39+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T01:00:00 AM" )) == milliseconds (1682816400000 ));
40+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T01:00:00 PM" )) == milliseconds (1682859600000 ));
41+ }
3442
35- // Leap year, with timezone offset: UTC should equal local time with -0000
36- CHECK ( to_milliseconds ( mgutility ::chrono::parse ( " {:%FT%T%z} " , " 2016-02-29T05:00:00-0000 " )) == milliseconds ( 1456722000000 )) ;
43+ TEST_CASE ( " Fractional Seconds " ) {
44+ using std ::chrono::milliseconds;
3745
38- // February 28 + 1 day (should rollover to Mar 1 on non-leap year)
39- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2021-03-01T00:00:00" )) == milliseconds (1614556800000 ));
46+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18.1" )) == milliseconds (1682871738100 )); // 100ms
47+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18.123" )) == milliseconds (1682871738123 )); // 123ms
48+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18.123456" )) == milliseconds (1682871738123 )); // 123ms (truncated)
49+ }
4050
41- // Year rollover: Dec 31 to Jan 1
42- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2022-12-31T23:59:59" )) == milliseconds (1672531199000 ));
43- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2023-01-01T00:00:00" )) == milliseconds (1672531200000 ));
51+ TEST_CASE (" Combined AM/PM, Fractional Seconds, and Timezone" ) {
52+ using std::chrono::milliseconds;
4453
45- // Month boundary rollover: Apr 30 + 1 day == May 1
46- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2023-05-01T00:00:00" )) == milliseconds (1682899200000 ));
54+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f %p}" , " 2023-04-30T11:59:59.500 PM" )) == milliseconds (1682899199500 ));
55+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f %p}" , " 2023-04-30T01:20:00.123 AM" )) == milliseconds (1682817600123 ));
56+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f %p %z}" , " 2023-04-30T11:59:59.500 PM +0100" )) == milliseconds (1682895599500 ));
57+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T.%f %p %z}" , " 2023-04-30T01:20:00.123 AM -0200" )) == milliseconds (1682824800123 ));
58+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T %p %z}" , " 2023-04-30T01:20:00 PM +0200" )) == milliseconds (1682853600000 ));
59+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T %p %z}" , " 2023-04-30T01:20:00 AM -0200" )) == milliseconds (1682824800000 ));
60+ }
4761
48- // Invalid date: April 31
49- REQUIRE_THROWS ( mgutility ::chrono::parse ( " {:%FT%T} " , " 2023-04-31T12:00:00 " )) ;
62+ TEST_CASE ( " Leap Year and Date Boundaries " ) {
63+ using std ::chrono::milliseconds ;
5064
51- // Edge timezone: Feb 29 with offset
52- CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T%z }" , " 2016-02-29T23:59:59+0000 " )) == milliseconds (1456790399000 ));
53- CHECK ( to_milliseconds ( mgutility::chrono::parse ( " {:%FT%T%z} " , " 2016-02-29T12:00:00-1200 " )) == milliseconds ( 1456790400000 ));
65+ CHECK ( to_milliseconds ( mgutility::chrono::parse ( " {:%FT%T} " , " 2020-02-29T12:00:00 " )) == milliseconds ( 1582977600000 )); // Leap year
66+ CHECK (to_milliseconds (mgutility::chrono::parse (" {:%FT%T}" , " 2021-03-01T00:00:00 " )) == milliseconds (1614556800000 )); // Feb 28 + 1 day
67+ }
5468
55- // Invalid date/time format
56- REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T}" , " not-a-date" ));
69+ TEST_CASE (" Error Handling" ) {
70+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T" , " 2023-04-30T16:22:18" )); // Malformed format
71+ REQUIRE_THROWS (mgutility::chrono::parse (" %FT%T}" , " 2023-04-30T16:22:18" )); // Malformed format
72+ REQUIRE_THROWS (mgutility::chrono::parse (" {%F %T}" , " 2023-04-30T16:22:18" )); // Malformed format
73+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%F %T}" , " 2023-04-30T16:22:18" )); // Format mismatch
74+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T}" , " 2021-02-29T12:00:00" )); // Invalid date (non-leap year)
75+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T}" , " 2023-04-31T12:00:00" )); // Invalid date (April 31)
76+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T}" , " not-a-date" )); // Invalid format
77+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T13:00:00 AM" )); // Hour > 12
78+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T12:00:00 XM" )); // Invalid AM/PM
79+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%H:%M:%S %p}" , " 2023-04-30T12:00:00" )); // Missing AM/PM
80+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18." )); // No digits after decimal
81+ REQUIRE_THROWS (mgutility::chrono::parse (" {:%FT%T.%f}" , " 2023-04-30T16:22:18.A" )); // Invalid fraction
5782}
0 commit comments