Visitar URL original
SQL dates: invalid dates such as 2021-02-30 are silently moved to a valid day, and a DATE equals a DATETIME of the same day · Issue #10206 · ArcadeData/arcadedb · GitHub
Skip to content

SQL dates: invalid dates such as 2021-02-30 are silently moved to a valid day, and a DATE equals a DATETIME of the same day #10206

Closed

Description

@tae898

Date and time handling in ArcadeDB SQL differs from DuckDB (and from SQL) in ways that change data silently:

  1. Invalid dates are moved to a valid one instead of rejected: '2021-02-30'.asDate('yyyy-MM-dd') and .asDate() give 2021-02-28, '2021-04-31' gives 2021-04-30, and WHERE d1 = '2021-02-30' matches the record dated 2021-02-28; '2021-02-03 24:00:00'.asDateTime('yyyy-MM-dd HH:mm:ss') gives the next day. DuckDB answers NULL (or refuses the literal). This looks like the lenient (SMART) resolver of java.time; a strict one would refuse these.
  2. A DATE compares equal to a DATETIME of the same day: with d1 = 2021-02-03 and t1 = 2021-02-03 12:00, d1 = t1 and d1 >= t1 are true and d1 < t1 false; SQL compares the date as midnight.
  3. Smaller ones: d1.format('HH') (any time pattern) on a DATE throws UnsupportedTemporalTypeException instead of formatting midnight; d1 - t3 with a DATETIME_NANOS operand throws long overflow for a 321-year gap that DATETIME_MICROS handles; and '0000-01-01'.asDate() parses while .asDate('yyyy-MM-dd') returns null.

Identical on main (a759246daa) and 26.10.2 (e5040d0339), JDK 25 (-XX:+UseCompactObjectHeaders) and JDK 21, timezone UTC; with an index on the date properties the answers are the same. Rows: id 1 (d1 2021-02-03, t1/t2 2021-02-03T12:00, s '2021-02-03'), id 2 (d1 2021-02-28, s '2021-02-30'), id 3 (s '2021-04-31'), id 4 (s '2021-02-03 24:00:00'), id 5 (s '0000-01-01'), id 6 (d1 2021-02-03, t2 1700-03-01T00:00, t3 1700-03-01T00:00:00.000000001).

statement ArcadeDB DuckDB
SELECT id FROM E WHERE d1 >= t1 [1] []
SELECT id FROM E WHERE d1 = t1 [1] []
SELECT id FROM E WHERE d1 < t1 [] [1]
SELECT id FROM E WHERE d1 >= t2 [1, 6] [6]
SELECT s.asDate('yyyy-MM-dd') AS v FROM E WHERE id = 2 [2021-02-28] [null]
SELECT s.asDate('yyyy-MM-dd') AS v FROM E WHERE id = 3 [2021-04-30] [null]
SELECT s.asDate() AS v FROM E WHERE id = 2 [2021-02-28] [null]
SELECT id FROM E WHERE d1 = '2021-02-30' [2] error: ConversionException: Conversion Error: date field value out of range:
SELECT s.asDateTime('yyyy-MM-dd HH:mm:ss') AS v FROM E WHERE id = 4 [2021-02-04T00:00] [null]
SELECT s.asDate() AS v FROM E WHERE id = 5 [0000-01-01] [0001-01-01 (BC)]
SELECT s.asDate('yyyy-MM-dd') AS v FROM E WHERE id = 5 [null] [0001-01-01 (BC)]
SELECT d1.format('HH') AS v FROM E WHERE id = 1 error UnsupportedTemporalTypeException: Unsupported field: HourOfDay [00]
SELECT d1.format('yyyy-MM-dd HH:mm:ss') AS v FROM E WHERE id = 1 error UnsupportedTemporalTypeException: Unsupported field: HourOfDay [2021-02-03 00:00:00]
SELECT d1.format('yyyy-MM-dd') AS v FROM E WHERE id = 1 [2021-02-03] [2021-02-03]
SELECT (d1 - t3) AS v FROM E WHERE id = 6 error ArithmeticErrorException: long overflow [10127548799999999999]
SELECT (d1 - t2) AS v FROM E WHERE id = 6 [PT2813208H] [10127548800000000000]

Found by a differential of SQL date handling against DuckDB (4,000 generated queries over DATE, DATETIME_SECOND, DATETIME, DATETIME_MICROS and DATETIME_NANOS; filtering, ordering, grouping, asLong and the other formats agreed). DuckDB's 0001-01-01 (BC) for year 0000 is its own notation, not a difference.

Activity

  1. added
    severity:majorA feature is broken or returns wrong results, with no practical workaround
    on Oct 17, 2026
  2. added this to the 26.11.1 milestone on Oct 17, 2026
  3. added
    in progressThe team is actively working on this issue
    on Oct 17, 2026
  4. self-assigned this
    on Oct 17, 2026
  5. added 3 commits that reference this issue on Oct 18, 2026
  6. lvca commented on Oct 18, 2026

    @lvca
    Member

    Fixed in #10259 (26.11.1).

    • Impossible dates such as 2021-02-30 are now refused instead of being silently moved to another day.
    • A DATE compared with a DATETIME is treated as midnight of that day, in =, <, <=, >, >= and BETWEEN, and index lookups on DATE properties follow the same rule.
    • Subtracting two dates gives the exact difference.

    ❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.

  7. removed
    in progressThe team is actively working on this issue
    on Oct 18, 2026
  8. added a commit that references this issue on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugseverity:majorA feature is broken or returns wrong results, with no practical workaroundsql

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions