Cheat Sheets2026-09-26

SQL Date Functions Cheat Sheet: PostgreSQL, MySQL, BigQuery, SQL Server

Every date operation you actually write — now, truncate, add intervals, diff, format, parse, end-of-month — mapped across four dialects in one table, plus the week-numbering and timezone traps.

Quick Answer

  • Truncate to a period: DATE_TRUNC('month', d) in PostgreSQL and BigQuery; MySQL has no equivalent — use DATE_FORMAT(d, '%Y-%m-01'); SQL Server 2022+ has DATETRUNC(month, d).
  • Add or subtract time: PostgreSQL uses interval arithmetic (d - INTERVAL '1 month'), the other three use functions (DATE_ADD, DATE_SUB, DATEADD).
  • End of month: LAST_DAY(d) covers MySQL and BigQuery; PostgreSQL needs DATE_TRUNC('month', d) + INTERVAL '1 month - 1 day'; SQL Server uses EOMONTH(d).

The Master Table

TaskPostgreSQLMySQL 8BigQuerySQL Server
Now (timestamp)NOW()NOW()CURRENT_TIMESTAMP()SYSDATETIME()
Today (date)CURRENT_DATECURDATE()CURRENT_DATE()CAST(GETDATE() AS DATE)
Truncate to monthDATE_TRUNC('month', d)DATE_FORMAT(d, '%Y-%m-01')DATE_TRUNC(d, MONTH)DATETRUNC(month, d) (2022+)
Truncate to weekDATE_TRUNC('week', d) (Monday)DATE_SUB(d, INTERVAL WEEKDAY(d) DAY)DATE_TRUNC(d, WEEK) (Sunday)DATETRUNC(week, d) (Sunday)
Add N daysd + INTERVAL '7 days' or d + 7DATE_ADD(d, INTERVAL 7 DAY)DATE_ADD(d, INTERVAL 7 DAY)DATEADD(day, 7, d)
Subtract 1 monthd - INTERVAL '1 month'DATE_SUB(d, INTERVAL 1 MONTH)DATE_SUB(d, INTERVAL 1 MONTH)DATEADD(month, -1, d)
Difference in daysd2 - d1 (integer)DATEDIFF(d2, d1)DATE_DIFF(d2, d1, DAY)DATEDIFF(day, d1, d2)
Extract yearEXTRACT(YEAR FROM d)YEAR(d)EXTRACT(YEAR FROM d)YEAR(d)
Format as textTO_CHAR(d, 'YYYY-MM')DATE_FORMAT(d, '%Y-%m')FORMAT_DATE('%Y-%m', d)FORMAT(d, 'yyyy-MM')
Parse a stringTO_DATE(s, 'YYYY-MM-DD')STR_TO_DATE(s, '%Y-%m-%d')PARSE_DATE('%Y-%m-%d', s)TRY_PARSE(s AS DATE)
End of monthDATE_TRUNC('month', d) + INTERVAL '1 month - 1 day'LAST_DAY(d)LAST_DAY(d)EOMONTH(d)
Age in yearsEXTRACT(YEAR FROM AGE(now, d))TIMESTAMPDIFF(YEAR, d, NOW())DATE_DIFF(CURRENT_DATE(), d, YEAR)DATEDIFF(year, d, GETDATE())

Grouping by Week: The ISO Trap

"Revenue by week" is where date code goes wrong most often, because the four engines define week boundaries and week numbers differently. PostgreSQL's DATE_TRUNC('week', d) starts weeks on Monday; BigQuery and SQL Server start them on Sunday. If you need ISO week numbers (Monday-based, week 1 contains the first Thursday), MySQL gives them via DATE_FORMAT(d, '%x-W%v') — note the lowercase %x%v for ISO; uppercase %X%V is the Sunday-based variant. Mixing those two formats for year and week is a classic bug that splits one ISO week across two grouping buckets every January.

Adding Months: End-of-Month Drift

DATE '2026-01-31' + INTERVAL '1 month' in PostgreSQL returns 2026-02-28 — the last valid day. MySQL's DATE_ADD('2026-01-31', INTERVAL 1 MONTH) returns the same. But SQL Server's DATEADD(month, 1, '2026-01-31') also returns 2026-02-28, while DATEADD(month, 1, '2026-01-30') returns 2026-02-28 too (it clamps, never overflows). The trap runs the other direction as well: repeated "+1 month" on a clamped date (Jan 31 → Feb 28 → Mar 28) drifts away from the true month-end. For subscription and billing queries, always compute from an anchor date like the first of month, not by iterating.

Timezones

PostgreSQL stores timestamptz in UTC and renders in the session timezone: created_at AT TIME ZONE 'America/New_York' converts explicitly. MySQL's TIMESTAMP auto-converts using the session time_zone, but DATETIME does not convert at all — half the "my dates are off by an hour" reports trace to this. For date-bucket reporting, the safe pattern in every engine is: store UTC, convert once at query time, and group by the converted value — never group by UTC day and label it with a local timezone.

Filling Date Gaps

Date functions get you the axis; the missing-days problem is separate — generating a complete date spine and LEFT JOINing your data onto it. We covered that with dialect-specific recipes here: Find missing dates in SQL.

Try It Yourself

Describe the date logic in plain English — "monthly revenue for the last 6 months in MySQL" — and our free SQL generator writes the dialect-correct functions for you.