Implement datediff(a, b)

Parsed its arguments correctly but had an empty body (a literal
"// TODO: Implement DATEDIFF." comment), never setting a result - isNumber
was left uninitialized on this path.

Matches MySQL's own DATEDIFF(expr1, expr2): expr1 - expr2 expressed as a
whole number of days, ignoring time-of-day. Dates parse as YYYY-MM-DD via
strptime (a longer "YYYY-MM-DD HH:MM:SS" value parses fine too, since
strptime only consumes what the format string asks for) and are
interpreted as UTC via timegm() rather than mktime(), so the result
doesn't shift with the server's own timezone. An unparseable date throws
a clear, specific error instead of producing garbage.

Verified via real jet-2.0 runs: datediff('2026-08-26','2026-08-20') -> 6,
the reverse -> -6, same date -> 0, a full non-leap year -> 365, and an
invalid date string throws cleanly rather than crashing or silently
returning nonsense. Full 9-script regression suite still passes.
This commit is contained in:
Brad Arant committed 2026-08-26 10:50:57 -07:00
1 parent 5c703f5620
commit 8b2391b289
1 file changed
+20 -3
+20 -3
View File
@@ -404,9 +404,26 @@ namespace jet {
throw coreutils::Exception("Expecting , in DATEDIFF expression.");
Operand parm2(in, tag);
if(in.ifNext(")")) {
// TODO: Implement DATEDIFF.
// Matches MySQL's DATEDIFF(expr1, expr2): expr1 - expr2 expressed
// as a whole number of days, ignoring any time-of-day component.
// Dates are parsed as YYYY-MM-DD (a leading date portion of a
// longer "YYYY-MM-DD HH:MM:SS" value parses fine too, since
// strptime only consumes what the format string asks for) and
// interpreted as UTC via timegm() (not mktime(), which is
// local-timezone-dependent) so the result doesn't shift with the
// server's own timezone setting.
struct tm tm1 = {};
struct tm tm2 = {};
if(!strptime(parm1.string.c_str(), "%Y-%m-%d", &tm1))
throw coreutils::Exception("DATEDIFF: first argument is not a valid date (expected YYYY-MM-DD).");
if(!strptime(parm2.string.c_str(), "%Y-%m-%d", &tm2))
throw coreutils::Exception("DATEDIFF: second argument is not a valid date (expected YYYY-MM-DD).");
time_t t1 = timegm(&tm1);
time_t t2 = timegm(&tm2);
doubleValue = difftime(t1, t2) / 86400.0;
isNumber = true;
string = std::format("{:.12f}", doubleValue);
string.removeTrailingZeros();
} else
throw coreutils::Exception("Expecting ) at end of DATEDIFF expression.");
} else if(in.ifNextIgnoreCase("true")) {