Recipe

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 #

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';            -- ANSI

Example #

Loading SQL editor...

Common variants #

sql
-- "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 #

sql
-- 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 #

EngineSyntaxGotcha
PostgreSQL / DuckDBNOW() / CURRENT_TIMESTAMPtransaction start; CLOCK_TIMESTAMP() for wall clock (Postgres only)
MySQLNOW() / CURRENT_TIMESTAMPsession-local; UTC_TIMESTAMP() for UTC
SQL ServerGETDATE() / SYSDATETIME()server-local; GETUTCDATE() for UTC
BigQueryCURRENT_TIMESTAMP()UTC by default; parens required
SnowflakeCURRENT_TIMESTAMPreturns TIMESTAMP_LTZ
SQLitedatetime('now')always UTC, returned as string
OracleSYSDATE / SYSTIMESTAMPSYSDATE no TZ; SYSTIMESTAMP carries TZ
  • Postgres: CURRENT_TIMESTAMP returns TIMESTAMP WITH TIME ZONE at 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 for CURRENT_TIMESTAMP.
  • MySQL: NOW() and CURRENT_TIMESTAMP return server-local time. UTC_TIMESTAMP() returns UTC. The session variable time_zone controls what "local" means.
  • SQL Server: GETDATE() and CURRENT_TIMESTAMP are server-local; GETUTCDATE() is UTC. SYSDATETIMEOFFSET() returns timezone-aware data.
  • BigQuery: CURRENT_TIMESTAMP() and CURRENT_DATETIME() differ — TIMESTAMP is timezone-aware (UTC by default), DATETIME is timezone-less. Be careful which one you compare against.
  • Snowflake: CURRENT_TIMESTAMP returns TIMESTAMP_LTZ (local time zone). SYSDATE() returns server-local without timezone.
  • DuckDB: CURRENT_TIMESTAMP and NOW() return TIMESTAMP WITH TIME ZONE at the start of the current transaction (Postgres-style). TRANSACTION_TIMESTAMP() is an alias. No CLOCK_TIMESTAMP(). CURRENT_DATE and CURRENT_TIME are timezone-aware in modern versions.
  • SQLite: CURRENT_TIMESTAMP is always UTC, formatted as a string ('2026-04-26 14:30:00').
  • Oracle: SYSDATE is server-local, no timezone; CURRENT_DATE is session-local; SYSTIMESTAMP carries timezone.
Warning

**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.