Bug #120789 TIMESTAMPDIFF/DAYOFYEAR/WEEKDAY ignore ALLOW_INVALID_DATES
Submitted: 26 Jun 11:14 Modified: 26 Jun 14:32
Reporter: Yakir Gibraltar (OCA) Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: DML Severity:S3 (Non-critical)
Version:9.7.0 OS:Any
Assigned to: CPU Architecture:Any

[26 Jun 11:14] Yakir Gibraltar
Description:
On MySQL 9.7.0 with sql_mode='ALLOW_INVALID_DATES', several date functions wrongly return NULL (with Warning 1292 'Incorrect datetime value') for a calendar-invalid but well-formed date such as '2024-02-30', even though ALLOW_INVALID_DATES is documented to accept month-in-1..12 / day-in-1..31 dates. 9.6.0 computes the correct values. Affected: TIMESTAMPDIFF, DAYOFYEAR, WEEKDAY, DAYOFWEEK, WEEK, YEARWEEK (and DAYNAME). Sibling functions TO_DAYS, DATEDIFF, DATE(), MONTH(), DAY() correctly accept the same value in the same session, which makes the result self-contradictory.

Regression introduced by WL#16895 "Refactor DATE handling in server" (commit 876fd7ffe0db, 2026-02-17). These functions pass the hardcoded flag constant TIME_ONLY_VALID_DATES to value extraction:
  sql/item_timefunc.cc:3865-3866  Item_func_timestamp_diff::val_int  -> val_datetime(..., TIME_ONLY_VALID_DATES)
  sql/item_timefunc.cc:1436       Item_func_dayofyear::val_int       -> val_arg0_date(..., TIME_ONLY_VALID_DATES)
  sql/item_timefunc.cc:1867       Item_func_weekday::val_int (also DAYOFWEEK)
  sql/item_timefunc.cc:1817       Item_func_week::val_int
  sql/item_timefunc.cc:1841       Item_func_yearweek::val_int
  sql/item_timefunc.cc:1888       Item_func_dayname::val_str
TIME_ONLY_VALID_DATES (include/my_time.h:111) bundles TIME_NO_INVALID_DATES, which forces check_date() (mysys/my_time.cc:204) to reject calendar-invalid dates regardless of sql_mode. The correct, sql_mode-gated idiom is used elsewhere, e.g. sql/item.cc:441, sql/sql_time.cc:202, sql/item_timefunc.cc:4059 (include TIME_NO_INVALID_DATES only when MODE_INVALID_DATES is NOT set). TO_DAYS/DATEDIFF still work because they use TIME_NO_ZERO_DATE|TIME_NO_ZERO_IN_DATE (no TIME_NO_INVALID_DATES), which is what exposes the contradiction.

WL#16895's own retained test mysql-test/r/type_date.result (Bug#20583945) asserts that under ALLOW_INVALID_DATES such dates are processed (DATE / DATE_FORMAT / +1 preserve '2014-02-31'), confirming the correct behavior is to compute, not NULL.

The buggy flags are still present at the current 9.7 branch HEAD, so this still ships in 9.7.1.

Thank you,
Yakir Gibraltar

How to repeat:
SET sql_mode='ALLOW_INVALID_DATES';
SELECT TIMESTAMPDIFF(DAY,'2024-02-30','2024-03-15') AS tsdiff,   -- 9.7.0: NULL    9.6.0: 14
       DAYOFYEAR('2024-02-30')                       AS doy,     -- 9.7.0: NULL    9.6.0: 61
       WEEKDAY('2024-02-30')                         AS wd,      -- 9.7.0: NULL    9.6.0: 4
       DATEDIFF('2024-03-15','2024-02-30')           AS ctrl_dd, -- both: 14      (control)
       TO_DAYS('2024-02-30')                         AS ctrl_td; -- both: 739311  (control)

-- Internal-consistency oracle (proves 9.7.0 is self-contradictory within one session/mode,
-- independent of comparing to 9.6.0): TO_DAYS, DATEDIFF, DATE('2024-02-30'), MONTH, DAY all
-- accept '2024-02-30', and the identity TIMESTAMPDIFF(DAY,b,a) = TO_DAYS(a)-TO_DAYS(b) = 14
-- must hold -- yet TIMESTAMPDIFF/DAYOFYEAR/WEEKDAY return NULL.

Suggested fix:
In these val_int/val_str functions, replace the hardcoded TIME_ONLY_VALID_DATES with the sql_mode-gated flag used at sql/item.cc:441 and sql/item_timefunc.cc:4059 -- i.e. include TIME_NO_INVALID_DATES only when MODE_INVALID_DATES is not set -- so ALLOW_INVALID_DATES is honored consistently with TO_DAYS / DATEDIFF / DATE().
[26 Jun 14:03] Roy Lyseng
Thank you for the bug report.
However, this is not a bug. Proper handling of invalid dates has been enforced
in release 9.7.

DAYOFYEAR against an invalid date makes no sense, hence NULL is returned.

WEEKDAY against an invalid date also makes no sense.

TIMESTAMPDIFF when one of the arguments is an invalid date also does not make sense and hence NULL is returned.

Notice also that for all three functions, the other invalid dates like 0000-00-00, 2000-01-00 and 2000-00-01 all return NULL.

TO_DAYS will currently return a non-NULL value for invalid dates.
I am not sure this is a good idea, since all days are consecutively numbered and it means that the return values for e.g 2024-02-30 and 2024-03-01 are the same.

DATEDIFF implementation is based on the same implementation as TO_DAYS and thus accepts invalid dates when ALLOW_INVALID_DATES is given.
[26 Jun 14:32] Yakir Gibraltar
Got it, 10x Roy!