Skip to content

Commit 4786345

Browse files
add ambigious handling + add tests
Signed-off-by: hamzah <hamzah.chaudhry@proton.me>
1 parent 38c7d8b commit 4786345

3 files changed

Lines changed: 52 additions & 3 deletions

File tree

src/Datetime.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ bool Datetime::parse (
166166
return true;
167167
}
168168

169-
if (parse_formatted (pig, format))
169+
bool ambiguous {false};
170+
if (parse_formatted (pig, format, ambiguous))
170171
{
171172
// Check the values and determine time_t.
172173
if (validate ())
@@ -176,6 +177,10 @@ bool Datetime::parse (
176177
return true;
177178
}
178179
}
180+
else if (ambiguous)
181+
{
182+
return false;
183+
}
179184

180185
// Allow parse_date_time and parse_date_time_ext regardless of
181186
// Datetime::isoEnabled setting, because these formats are relied upon by
@@ -232,7 +237,7 @@ void Datetime::clear ()
232237
}
233238

234239
////////////////////////////////////////////////////////////////////////////////
235-
bool Datetime::parse_formatted (Pig& pig, const std::string& format)
240+
bool Datetime::parse_formatted (Pig& pig, const std::string& format, bool& ambiguous)
236241
{
237242
// Short-circuit on missing format.
238243
if (format.empty ())
@@ -247,6 +252,7 @@ bool Datetime::parse_formatted (Pig& pig, const std::string& format)
247252
int minute {-1};
248253
int second {-1};
249254
int meridiem {-1};
255+
bool twelveHourTime {false};
250256

251257
// For parsing, unused.
252258
int wday {-1};
@@ -355,6 +361,7 @@ bool Datetime::parse_formatted (Pig& pig, const std::string& format)
355361
break;
356362

357363
case 'i':
364+
twelveHourTime = true;
358365
if (pig.getDigit (hour))
359366
{
360367
if (hour == 0)
@@ -381,6 +388,7 @@ bool Datetime::parse_formatted (Pig& pig, const std::string& format)
381388
break;
382389

383390
case 'I':
391+
twelveHourTime = true;
384392
if (! pig.getDigit2 (hour) || hour < 1 || hour > 12)
385393
{
386394
pig.restoreTo (checkpoint);
@@ -592,6 +600,13 @@ bool Datetime::parse_formatted (Pig& pig, const std::string& format)
592600
if (minute == -1) minute = 0;
593601
if (second == -1) second = 0;
594602

603+
if (twelveHourTime && meridiem == -1)
604+
{
605+
ambiguous = true;
606+
pig.restoreTo (checkpoint);
607+
return false;
608+
}
609+
595610
if (meridiem != -1)
596611
{
597612
if (hour < 1 || hour > 12)

src/Datetime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class Datetime
116116

117117
private:
118118
void clear ();
119-
bool parse_formatted (Pig&, const std::string&);
119+
bool parse_formatted (Pig&, const std::string&, bool& ambiguous);
120120
bool parse_named (Pig&);
121121
bool parse_epoch (Pig&);
122122
bool parse_date_time_ext (Pig&);

test/datetime.t.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,9 @@ int main (int, char**)
10701070
t.is (Datetime::length ("V"), 2, "length 'V' --> 2");
10711071
t.is (Datetime::length ("h"), 2, "length 'h' --> 2");
10721072
t.is (Datetime::length ("H"), 2, "length 'H' --> 2");
1073+
t.is (Datetime::length ("i"), 2, "length 'i' --> 2");
1074+
t.is (Datetime::length ("I"), 2, "length 'I' --> 2");
1075+
t.is (Datetime::length ("p"), 2, "length 'p' --> 2");
10731076
t.is (Datetime::length ("n"), 2, "length 'n' --> 2");
10741077
t.is (Datetime::length ("N"), 2, "length 'N' --> 2");
10751078
t.is (Datetime::length ("s"), 2, "length 's' --> 2");
@@ -1095,6 +1098,9 @@ int main (int, char**)
10951098
t.is (r32.toString ("d"), "28", "2015-10-28T12:55:01 -> d -> 28");
10961099
t.is (r32.toString ("H"), "12", "2015-10-28T12:55:01 -> H -> 12");
10971100
t.is (r32.toString ("h"), "12", "2015-10-28T12:55:01 -> h -> 12");
1101+
t.is (r32.toString ("I"), "12", "2015-10-28T12:55:01 -> I -> 12");
1102+
t.is (r32.toString ("i"), "12", "2015-10-28T12:55:01 -> i -> 12");
1103+
t.is (r32.toString ("p"), "PM", "2015-10-28T12:55:01 -> p -> PM");
10981104
t.is (r32.toString ("N"), "55", "2015-10-28T12:55:01 -> N -> 55");
10991105
t.is (r32.toString ("n"), "55", "2015-10-28T12:55:01 -> n -> 55");
11001106
t.is (r32.toString ("S"), "00", "2015-10-28T12:55:01 -> S -> 01");
@@ -1109,6 +1115,16 @@ int main (int, char**)
11091115
t.is (r32.toString ("j"), "301", "2015-10-28T12:55:01 -> j -> 301");
11101116
t.is (r32.toString ("w"), "3", "2015-10-28T12:55:01 -> w -> 3");
11111117

1118+
Datetime r32a ("2015-10-28T00:05:00");
1119+
t.is (r32a.toString ("I"), "12", "2015-10-28T00:05:00 -> I -> 12");
1120+
t.is (r32a.toString ("i"), "12", "2015-10-28T00:05:00 -> i -> 12");
1121+
t.is (r32a.toString ("p"), "AM", "2015-10-28T00:05:00 -> p -> AM");
1122+
1123+
Datetime r32b ("2015-10-28T13:05:00");
1124+
t.is (r32b.toString ("I"), "01", "2015-10-28T13:05:00 -> I -> 01");
1125+
t.is (r32b.toString ("i"), "1", "2015-10-28T13:05:00 -> i -> 1");
1126+
t.is (r32b.toString ("p"), "PM", "2015-10-28T13:05:00 -> p -> PM");
1127+
11121128
// Test all parse options.
11131129
Datetime r33 ("2015 10 28 19 28 01", "Y M D H N S");
11141130
t.is(r33.year (), 2015, "Y works");
@@ -1126,6 +1142,24 @@ int main (int, char**)
11261142
t.is(r34.minute (), 2, "n works");
11271143
t.is(r34.second (), 1, "s works");
11281144

1145+
Datetime r34a ("2015 10 28 12 00 AM", "Y M D I N p");
1146+
t.is(r34a.hour (), 0, "12 AM parses as hour 0");
1147+
t.is(r34a.minute (), 0, "12 AM minute works");
1148+
1149+
Datetime r34b ("2015 10 28 12 00 PM", "Y M D I N p");
1150+
t.is(r34b.hour (), 12, "12 PM parses as hour 12");
1151+
t.is(r34b.minute (), 0, "12 PM minute works");
1152+
1153+
Datetime r34c ("2015 10 28 1 30 PM", "Y M D i N p");
1154+
t.is(r34c.hour (), 13, "1 PM parses as hour 13");
1155+
t.is(r34c.minute (), 30, "1 PM minute works");
1156+
1157+
Datetime r34d ("2015 10 28 11 45 pm", "Y M D i N p");
1158+
t.is(r34d.hour (), 23, "lowercase pm parses as hour 23");
1159+
t.is(r34d.minute (), 45, "lowercase pm minute works");
1160+
1161+
t.notok (Datetime::valid ("2015_10_28_1_30", "Y_M_D_i_N"), "ambiguous 12-hour time without AM/PM is invalid");
1162+
11291163
Datetime r35 ("Wednesday October 28 2015", "A B D Y");
11301164
t.is(r35.year (), 2015, "Y works");
11311165
t.is(r35.month (), 10, "B works");

0 commit comments

Comments
 (0)