Timestamp with Timezone in Drizzle ORM

Convert SQL TIMESTAMP, TIMESTAMPTZ, and DATETIME columns to Drizzle ORM schema with proper timezone handling across PostgreSQL, MySQL, and SQLite.

Dialect-Specific

Detailed Explanation

Timestamp Handling in Drizzle

Date and time types are among the most dialect-specific aspects of SQL. Drizzle provides different builders and options depending on the dialect.

PostgreSQL Timestamps

PostgreSQL distinguishes between TIMESTAMP (without timezone) and TIMESTAMPTZ (with timezone):

CREATE TABLE events (
  id SERIAL PRIMARY KEY,
  name VARCHAR(200) NOT NULL,
  starts_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
import { pgTable, serial, timestamp, varchar } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";

export const events = pgTable("events", {
  id: serial("id").primaryKey(),
  name: varchar("name", { length: 200 }).notNull(),
  startsAt: timestamp("starts_at").notNull(),
  createdAt: timestamp("created_at", { withTimezone: true }).default(sql`CURRENT_TIMESTAMP`),
});

The key option is { withTimezone: true }, which tells Drizzle to use TIMESTAMPTZ in the database.

MySQL DATETIME vs TIMESTAMP

MySQL has two similar types with different behavior:

  • DATETIME: No timezone conversion, stores as-is (range: 1000-01-01 to 9999-12-31)
  • TIMESTAMP: Converted to UTC for storage (range: 1970-01-01 to 2038-01-19)
CREATE TABLE logs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  event_time DATETIME NOT NULL,
  recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
import { datetime, mysqlTable, serial, timestamp } from "drizzle-orm/mysql-core";
import { sql } from "drizzle-orm";

export const logs = mysqlTable("logs", {
  id: serial("id").primaryKey(),
  eventTime: datetime("event_time").notNull(),
  recordedAt: timestamp("recorded_at").default(sql`CURRENT_TIMESTAMP`),
});

SQLite Date/Time

SQLite has no dedicated date/time types. Dates are typically stored as TEXT in ISO 8601 format, INTEGER as Unix timestamps, or REAL as Julian day numbers:

import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
import { sql } from "drizzle-orm";

export const logs = sqliteTable("logs", {
  id: integer("id").primaryKey(),
  createdAt: text("created_at").default(sql`CURRENT_TIMESTAMP`),
});

Common Default Values

SQL Default Drizzle Default
CURRENT_TIMESTAMP .default(sql\CURRENT_TIMESTAMP`)`
NOW() .default(sql\CURRENT_TIMESTAMP`)`

Best Practice

For new projects, it is recommended to use TIMESTAMPTZ (PostgreSQL) or TIMESTAMP (MySQL) for columns that represent points in time, and TIMESTAMP without timezone / DATETIME for columns like scheduled events where the time is meaningful in a specific timezone context.

Use Case

You are converting a database schema that heavily uses timestamp columns with various timezone handling patterns and need to ensure the Drizzle schema correctly represents the timezone behavior.

Try It — SQL to Drizzle Schema

Open full tool