Current date, time, and timestamp
Short answer: CURRENT_DATE for today's date, CURRENT_TIMESTAMP for the current date-and-time. Both are ANSI standard and work without parentheses on most engines. NOW() is a function-syntax synonym for CURRENT_TIMESTAMP on Postgres / MySQL / DuckDB; SQLite uses datetime('now'); BigQuery uses CURRENT_TIMESTAMP(); SQL Server uses GETDATE() / SYSDATETIME(). The timezone gotcha: these return server time on some engines, UTC on others, session timezone on others. Always confirm before using in a comparison.
Canonical SQL #
-- Today's date (no time component).
SELECT CURRENT_DATE;
-- Right now (date + time + sometimes timezone).
SELECT CURRENT_TIMESTAMP;
SELECT NOW(); -- Postgres / MySQL / DuckDB
SELECT datetime('now'); -- SQLite
SELECT CURRENT_TIMESTAMP(); -- BigQuery (note parens)
SELECT GETDATE(); -- SQL Server (local server time)
SELECT SYSDATETIME(); -- SQL Server (higher precision, server time)
SELECT SYSDATE FROM DUAL; -- Oracle (local server time)
-- Time only.
SELECT CURRENT_TIME; -- Most engines
SELECT LOCALTIME; -- Postgres / DuckDB
-- UTC explicitly (when your CURRENT_TIMESTAMP is local).
SELECT NOW() AT TIME ZONE 'UTC'; -- Postgres
SELECT UTC_TIMESTAMP(); -- MySQL
SELECT GETUTCDATE(); -- SQL Server
SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC'; -- ANSIExample #
Common variants #
-- "Last 7 days" filter.
SELECT * FROM orders
WHERE created_at >= CURRENT_TIMESTAMP - INTERVAL '7 days';
-- "Today's orders" filter (avoid wrapping a column in a function).
SELECT * FROM orders
WHERE order_date = CURRENT_DATE; -- index-friendly
-- "This month so far".
SELECT * FROM orders
WHERE order_date >= DATE_TRUNC('month', CURRENT_DATE)
AND order_date < DATE_TRUNC('month', CURRENT_DATE) + INTERVAL '1 month';
-- Default to NOW() in a column definition (audit timestamps).
CREATE TABLE events (
id INTEGER PRIMARY KEY,
payload VARCHAR,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Postgres: stable timestamp inside a transaction #
-- Postgres-specific demo: NOW() returns transaction start; CLOCK_TIMESTAMP() the wall clock.
BEGIN;
SELECT NOW(); -- e.g. 14:30:00
SELECT pg_sleep(2);
SELECT NOW(); -- still 14:30:00 (transaction start)
SELECT CLOCK_TIMESTAMP(); -- 14:30:02 — actual wall clock
COMMIT;Dialect comparison #
| Engine | Syntax | Gotcha |
|---|---|---|
| PostgreSQL / DuckDB | NOW() / CURRENT_TIMESTAMP | transaction start; CLOCK_TIMESTAMP() for wall clock (Postgres only) |
| MySQL | NOW() / CURRENT_TIMESTAMP | session-local; UTC_TIMESTAMP() for UTC |
| SQL Server | GETDATE() / SYSDATETIME() | server-local; GETUTCDATE() for UTC |
| BigQuery | CURRENT_TIMESTAMP() | UTC by default; parens required |
| Snowflake | CURRENT_TIMESTAMP | returns TIMESTAMP_LTZ |
| SQLite | datetime('now') | always UTC, returned as string |
| Oracle | SYSDATE / SYSTIMESTAMP | SYSDATE no TZ; SYSTIMESTAMP carries TZ |
- Postgres:
CURRENT_TIMESTAMPreturnsTIMESTAMP WITH TIME ZONEat the start of the transaction.STATEMENT_TIMESTAMP()is the start of the current statement.CLOCK_TIMESTAMP()is the current wall clock.NOW()is an alias forCURRENT_TIMESTAMP. - MySQL:
NOW()andCURRENT_TIMESTAMPreturn server-local time.UTC_TIMESTAMP()returns UTC. The session variabletime_zonecontrols what "local" means. - SQL Server:
GETDATE()andCURRENT_TIMESTAMPare server-local;GETUTCDATE()is UTC.SYSDATETIMEOFFSET()returns timezone-aware data. - BigQuery:
CURRENT_TIMESTAMP()andCURRENT_DATETIME()differ —TIMESTAMPis timezone-aware (UTC by default),DATETIMEis timezone-less. Be careful which one you compare against. - Snowflake:
CURRENT_TIMESTAMPreturnsTIMESTAMP_LTZ(local time zone).SYSDATE()returns server-local without timezone. - DuckDB:
CURRENT_TIMESTAMPandNOW()returnTIMESTAMP WITH TIME ZONEat the start of the current transaction (Postgres-style).TRANSACTION_TIMESTAMP()is an alias. NoCLOCK_TIMESTAMP().CURRENT_DATEandCURRENT_TIMEare timezone-aware in modern versions. - SQLite:
CURRENT_TIMESTAMPis always UTC, formatted as a string ('2026-04-26 14:30:00'). - Oracle:
SYSDATEis server-local, no timezone;CURRENT_DATEis session-local;SYSTIMESTAMPcarries timezone.
**Test what CURRENT_TIMESTAMP returns on your specific engine before relying on it.** A query that filters WHERE created_at >= CURRENT_TIMESTAMP - INTERVAL '1 hour' works fine in dev, then silently misses (or duplicates) rows in prod when one server's session is on UTC and another's is on the local timezone. The defensive habit: store every timestamp in UTC, compute relative windows from UTC_TIMESTAMP() / NOW() AT TIME ZONE 'UTC', and let the application or BI layer convert to local for display. Once you've been bitten by a four-hour timezone bug at month-end close, you stop relying on "default" timezone behavior.