Skip to content

fix(mysql,trino,singlestoredb): translate minutes token in strftime#12027

Draft
deepyaman wants to merge 1 commit into
ibis-project:mainfrom
deepyaman:fix/strftime-format-mysql-trino
Draft

fix(mysql,trino,singlestoredb): translate minutes token in strftime#12027
deepyaman wants to merge 1 commit into
ibis-project:mainfrom
deepyaman:fix/strftime-format-mysql-trino

Conversation

@deepyaman

Copy link
Copy Markdown
Collaborator

Note

Draft — companion to #12025 (same root cause, the format direction instead of parse). I don't have local MySQL/Trino/SingleStoreDB servers, so this is compile-validated; CI is the execution check. Markers beyond druid/exasol may need adding once CI runs.

Description

strftime with a time component silently emits the wrong value on MySQL/Trino/SingleStoreDB:

con.execute(ibis.timestamp("2021-01-02 03:04:05").strftime("%Y-%m-%d %H:%M:%S"))
# -> "2021-01-02 03:January:05"   (the month, in the minutes position)

Root cause (same as #12025, opposite direction)

ops.Strftime was routed through self.f.date_format(arg, fmt, dialect=…) via SIMPLE_OPS. Passing dialect= makes sqlglot re-parse the format string as if it were dialect-native, so Python's %M (minutes) is read as the dialect's %M (month name). Compiled SQL was DATE_FORMAT(t, '%Y-%m-%d %H:%M:%s') — that %M formats the month.

Fix

The base compiler already has a correct visit_Strftime that builds sge.TimeToStr directly. mysql/trino's SIMPLE_OPS entry was overriding it with the buggy parse-converting version. Dropping the entry restores the base behavior:

DATE_FORMAT(t, '%Y-%m-%d %T')   (%T = %H:%i:%s)   ✓  mysql / trino / singlestoredb

It's a pure 2-line deletion; DATE_FORMAT is the same function these backends already emitted, just with the correct format (no SQL-shape change). SingleStoreDB inherits the fix from MySQL.

Adds test_strftime_with_time — the existing test_strftime only uses "%Y%m%d" (date-only), which is why this slipped through.

🤖 Generated with Claude Code

`strftime` with a format containing a time component (e.g. `"%H:%M:%S"`)
emitted the wrong thing on MySQL/Trino/SingleStoreDB: Python's `%M` (minutes)
was rendered as the dialect's `%M` (month *name*), so formatting a timestamp
produced the month in the minutes position (e.g. "03:January:05" for 03:04:05).

The cause is the same as ibis-project#12025 for the parse direction: `ops.Strftime` was
routed through `self.f.date_format(..., dialect=...)` (via SIMPLE_OPS), which
re-parses the format string as if it were dialect-native. Dropping that
SIMPLE_OPS entry lets these backends fall back to the base `visit_Strftime`,
which builds `sge.TimeToStr` directly and lets the generator translate the
canonical format -> `DATE_FORMAT(x, '%Y-%m-%d %T')`. SingleStoreDB inherits the
fix from MySQL.

Adds a regression test that formats a timestamp with a time component.

Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added tests Issues or PRs related to tests sql Backends that generate SQL labels Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sql Backends that generate SQL tests Issues or PRs related to tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant