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