fix(sql): DATEDIFF / DATE_DIFF / TIMESTAMPDIFF follow their vendors; DATE_TRUNC(…, WEEK) is the ISO Monday - #410
Merged
Merged
Conversation
…DATE_TRUNC(..., WEEK) is the ISO Monday Direction by argument layout: the dates-first forms (DATEDIFF(a, b[, unit]), DATE_DIFF(a, b[, unit])) return first - second, as MySQL's DATEDIFF and BigQuery's DATE_DIFF(end_date, start_date, granularity) do; the unit-first forms return last - middle, as SQL Server, Snowflake, Redshift, DuckDB, Trino, Elasticsearch SQL and MySQL's TIMESTAMPDIFF do. Counting by name: DATEDIFF and DATE_DIFF count the calendar boundaries crossed; TIMESTAMPDIFF counts the whole units elapsed between instants, with MySQL's month algorithm. Weeks are ISO 8601 (Monday), boundaries UTC. DATE_TRUNC(x, WEEK) returns the ISO Monday in every venue. One rendering serves row level, WHERE, per group, the HAVING alias route, the view calculation channel and the ingest processor. The sign spec no longer rests on a wrong reading of BigQuery's DATE_DIFF. Docs and help state the definition, rewrite the age / tenure examples and add the 0.24.0 change and migration notes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ES 6.8 hands scripts a JodaCompatibleZonedDateTime, which implements no java.time interface: TIMESTAMPDIFF's month count (getLong) and DATEDIFF / DATE_DIFF over a non-column operand such as COALESCE(ts, d) (LocalDate.from) failed there. Such operands are now brought to a real ZonedDateTime with withZoneSameInstant, which 6.8 allows and which reads the same instant on every major. DATEDIFF over COALESCE(ts, d) never worked on 6.8, v0.23.0 included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…h 6.8 From 6.8 the engine sends typeless mappings, and ES 6.x reads a mapping as typed unless the request says include_type_name=false. The REST client says it; the Jest client did not, so every CREATE TABLE (and every PARTITION BY template) failed on 6.8 with "Root mapping definition has unsupported parameters", v0.23.0 included. The Jest client now adds include_type_name=false on 6.8 when it creates an index with a mapping or a legacy template; 6.7.x and 7+ are unchanged. Template.Create gains a field (binary-incompatible: downstream projects rebuild). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fupelaqu
marked this pull request as ready for review
October 3, 2026 08:11
…FF over COALESCE on every major Six es6 Jest specs were pinned to ES 6.7.2 because CREATE TABLE failed through the Jest client on 6.8. The previous commit fixes that, so they run on 6.8.23 again (252 passed, 0 failed; the 5 cancelled tests are ES 6 platform gates: enrich policies, composable templates, regex flags before 7.0). The DateFunctionExecutionSpec population gains the 88 DATEDIFF / DATE_DIFF over COALESCE(ts, d) statements, so CI checks the 6.8 fix on every major. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
DATEDIFF, DATE_DIFF and TIMESTAMPDIFF follow their vendors' definitions, and
DATE_TRUNC(x, WEEK)is the ISO Monday.DATEDIFF(a, b),DATEDIFF(a, b, unit)andDATE_DIFF(a, b[, unit]), as MySQL'sDATEDIFFand BigQuery'sDATE_DIFF(end_date, start_date, granularity)do.DATEDIFF(unit, a, b),DATE_DIFF(unit, a, b)andTIMESTAMPDIFF(unit, a, b), as SQL Server, Snowflake, Redshift, DuckDB, Trino, Elasticsearch SQL and MySQL'sTIMESTAMPDIFFdo.DATEDIFF/DATE_DIFFcount the calendar boundaries crossed, as SQL Server, Snowflake, Redshift, BigQuery and DuckDB'sdate_diffdo.TIMESTAMPDIFFcounts the whole units elapsed between instants, with MySQL's month algorithm.DATE_TRUNC(x, WEEK)is the ISO Monday 00:00 UTC in every venue. The script path used to move a date forward to the Sunday ending its week; GROUP BY already used Monday.DATEDIFFsign assumed BigQuery'sDATE_DIFF(start, end, unit)is end − start. BigQuery documentsDATE_DIFF(end_date, start_date, granularity)=end_date − start_date.DateDiffSignSpecis rewritten accordingly.TIMESTAMPDIFF(YEAR, birthdate, CURRENT_DATE)andDATEDIFF(CURRENT_DATE, join_date, DAY);Measured (ES 8.18.3 through the gateway; oracles independent of the engine: vendor-documented examples and calendar arithmetic)
DateFunctionExecutionSpecpopulation (testkit, so CI runs every major): 4,896 statements = spellings × 8 units × edge pairs × 4 venues::DATETIMEoperands: 512 statements + 128 computed columnsDATE_TRUNC(…, WEEK)across venuesTIMESTAMPDIFF(…)The edge pairs:
Suites:
sql1788,es6bridge256,softclient4es8-sql-bridge263,core1148. ES 8.18.3 integration: 12 suites, 378/378. Lint is clean.Not run locally, left to CI: ES 6.8 / 7.17 / 9.0, and the Scala 2.12 cross-compile.
DATEDIFF(a, b[, unit]),DATE_DIFF(a, b[, unit])) returnsa − b; 0.23 returnedb − a. The unit-first forms keepb − a.DATEDIFF/DATE_DIFFcount calendar boundaries. FromWEEKup they counted the whole units elapsed between the calendar dates:DATE_DIFF(MONTH, '1992-09-15', '1992-11-14')was 1 and is 2, and aWEEKboundary is a Monday.HOUR/MINUTE/SECONDcount boundaries.DAYstill counts calendar days.DATE_TRUNC(x, WEEK)is the Monday. Outside GROUP BY it moved a date forward to the Sunday ending its week.SCRIPT AS) compute what a query computes. They counted elapsed time between instants for every unit (a DAY was 24 h), and a string literal operand failedCREATE TABLE.TIMESTAMPDIFF, theQUARTERunit,HOUR/MINUTE/SECONDover a column or an aggregate, and literal operands.ALTER TABLE … ADD COLUMN,SHOW CREATE, re-runningSHOW CREATE PIPELINE's text, view refreshes and restarts all leave it as it was.CREATE OR REPLACE MATERIALIZED VIEWwith an unchanged text keeps the old results;DROPandCREATEthe view to adopt the new definition.SHOW CREATEshows the stored text, which now means the new definition.DATE_DIFF(b, a, unit).TIMESTAMPDIFF(YEAR, birthdate, CURRENT_DATE)is the age thatDATE_DIFF(birthdate, CURRENT_DATE, YEAR)returned.TIMESTAMPDIFFrenders asTIMESTAMPDIFF: inSHOW CREATEand in persisted view text.Elasticsearch 6.8 (added after the first CI run)
The first CI run failed on ES 6.8 only. Two causes, both fixed, each in its own commit:
JodaCompatibleZonedDateTime, which implements nojava.timeinterface. That broke TIMESTAMPDIFF's month count, and DATEDIFF / DATE_DIFF overCOALESCE(ts, d). The latter never worked on 6.8, v0.23.0 included. Such operands are now brought to a realZonedDateTime, which reads the same instant on every major.CREATE TABLEon 6.8. EveryCREATE TABLE, and everyPARTITION BYtemplate, created through Jest failed on 6.8 with "Root mapping definition has unsupported parameters", v0.23.0 included. The fix: Jest now sendsinclude_type_name=falseon 6.8, as the REST client does. 6.7.x and 7+ are unchanged.Template.Create(softclient4es6-jest-client) gains a field. That is binary-incompatible, so downstream projects must rebuild.Measured locally:
Follow-up
The web docs (the
DATE_DIFFrow and the age / seniority examples) and two blog posts carry the old definition; a separate web PR updates them.🤖 Generated with Claude Code