From 8b2391b289238bcc1973e6833c8bd7108d3cd99a Mon Sep 17 00:00:00 2001 From: Brad Arant Date: Wed, 26 Aug 2026 10:50:57 -0700 Subject: [PATCH] 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. --- Operand.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Operand.cpp b/Operand.cpp index ca4c94f..db245c2 100644 --- a/Operand.cpp +++ b/Operand.cpp @@ -404,11 +404,28 @@ 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."); + throw coreutils::Exception("Expecting ) at end of DATEDIFF expression."); } else if(in.ifNextIgnoreCase("true")) { boolean = true; string = "true";