Prisma DateTime handling and PostgreSQL TIMESTAMPTZ synchronization
0 reputation · 05 Aug 2023, 17:56 UTC
0 reputation · 05 Aug 2023, 17:56 UTC
Prisma enforces UTC storage for all DateTime values across supported database providers. When utilizing PostgreSQL, the TIMESTAMPTZ type is used to ensure data is stored in UTC, but the Prisma Client returns these as standard JavaScript Date objects.
Because timezone conversion occurs at the application layer, there is a disconnect between the database session's timezone setting and the values returned by the Prisma Client. This creates uncertainty when performing date arithmetic or filtering using native database functions versus JavaScript-side manipulation.
DateTime objects?34775 reputation · 05 Aug 2023, 18:51 UTC
No, the Prisma Client does not provide a mechanism to respect database-level session timezone offsets during serialization. Prisma is designed to enforce UTC normalization across all supported providers to ensure consistency. When using PostgreSQL with TIMESTAMPTZ, Prisma always treats the data as UTC, regardless of the timezone setting configured in your PostgreSQL session or server.
To guarantee consistency when mixing native SQL date functions with Prisma's UTC-enforced DateTime objects, you must normalize the execution context. Since PostgreSQL stores TIMESTAMPTZ internally as UTC, the discrepancy usually arises from how the database session formats the output or how native functions (like CURRENT_DATE or now()) interact with the session's local timezone.
Follow these steps to ensure alignment:
prisma.$queryRaw, explicitly cast or set the timezone to UTC to match Prisma's application-layer behavior.TIMESTAMP (Without Time Zone): Ensure your schema uses DateTime (which maps to TIMESTAMPTZ in Postgres). Using TIMESTAMP without a timezone can lead to ambiguous data that ignores UTC normalization.date-fns or luxon.To verify that your data is stored and retrieved consistently, you can compare a raw database query with a Prisma query:
// 1. Check DB session timezone
// SQL: SHOW timezone;
// 2. Compare raw vs Prisma
const raw = await prisma.$queryRaw`SELECT "createdAt" FROM "User" LIMIT 1`;
const prisma = await prisma.user.findFirst();
console.log(raw[0].createdAt); // Formatted by DB session timezone
console.log(prisma.createdAt); // JavaScript Date object (UTC)
Note on Assumptions: This guidance assumes you are using a recent version of Prisma (v4+) and PostgreSQL. If you are using a custom database middleware that alters session settings per request, the behavior of $queryRaw may diverge from the standard Prisma Client methods.
Diagnostic Detail Needed: Are you utilizing $queryRaw for date arithmetic, or are you relying on database-level triggers/defaults (e.g., DEFAULT now())? This determines if the fix should be applied in the Prisma schema or via SQL casting.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 05 Aug 2023, 20:40 UTC
To expand on the consistency requirements, it is critical to distinguish between TIMESTAMPTZ and TIMESTAMP (without time zone) in the PostgreSQL schema. While Prisma maps both to the DateTime scalar in TypeScript, their underlying behavior differs significantly during serialization.
Date object normalized to UTC. This is the recommended type for global synchronization.To verify your current implementation, you can run \d table_name in psql. If the column is listed as timestamp without time zone, any date arithmetic performed via $queryRaw using now() will rely on the database server's local clock rather than the UTC standard enforced by the Prisma Client.