MySQL DATETIME time-zone conversion? #833
-
QuestionDoes the Drizzle ORM convert the JavaScript Environment
SELECT @@global.time_zone, @@session.time_zone;
/*
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| +00:00 | +00:00 |
+--------------------+---------------------+
1 row in set (0.02 sec) */ SHOW VARIABLES WHERE Variable_name LIKE '%time_zone%';
/*
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | KST |
| time_zone | +00:00 |
+------------------+--------+
2 rows in set (0.01 sec) */ Reproduction
import { eq } from 'drizzle-orm';
import { bigint, datetime, mysqlTable } from 'drizzle-orm/mysql-core';
import { createDbClient } from './drizzle.client';
const db = await createDbClient();
const users = mysqlTable('users', {
id: bigint('id', { mode: 'bigint' }).notNull().autoincrement().primaryKey(),
joinedAt: datetime('joined_at').notNull()
});
const date = new Date();
console.log(date.toISOString()); // 2023-06-30T05:45:48.194Z
await db.insert(users).values({
id: 1n,
joinedAt: date
});
const result = await db.query.users.findFirst({
where: eq(users.id, 1n)
});
if (result) console.log(result.joinedAt.toISOString());
// 2023-06-30T05:45:48.000Z WorkaroundHad to revert the database server's time-zone to
export const users = mysqlTable('users', {
id: bigint('id', { mode: 'bigint' }).notNull().autoincrement().primaryKey(),
joinedAt: datetime('joined_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`) // uses the database server's time-zone
}); |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 3 replies
-
you shouldn't use TIMESTAMP with mysql, check/watch: https://planetscale.com/courses/mysql-for-developers/schema/dates and all is intended, the video explains very well how to deal with dates |
Beta Was this translation helpful? Give feedback.
-
The mismatch is expected. In the reproduction,
Since the macOS's local time-zone is (KST | GMT+9 |
node-mysql2 uses the local timezone by default. /**
* The timezone used to store local dates. (Default: 'local')
*/
timezone?: string | 'local'; —
—
— Footnotes |
Beta Was this translation helpful? Give feedback.
-
Would be great if there was a universal way to explicitly configure this when instantiating the drizzle client |
Beta Was this translation helpful? Give feedback.
-
Wanted to share my solution here in case it's useful to anyone else. I implemented a custom drizzle type called import { customType } from 'drizzle-orm/mysql-core'
export const datetimeUtc = (name: string, precision: number) =>
customType<{ data: Date; driverData: string }>({
dataType() {
return `datetime(${precision})`
},
toDriver(value: Date): string {
return mysqlDatetimeUtc(value)
},
fromDriver(value: string): Date {
return mysqlDatetimeUtcToDate(value)
}
})(name)
function mysqlDatetimeUtc(date: Date = new Date()) {
return date.toISOString().slice(0, 19).replace('T', ' ')
}
// Use this function instead of new Date() when converting a MySQL datetime to a
// Date object so that the date is interpreted as UTC instead of local time (default behavior)
function mysqlDatetimeUtcToDate(mysqlDatetimeUtc: string) {
return new Date(mysqlDatetimeUtc.replace(' ', 'T') + 'Z')
} To use it, simply replace "datetime" columns in your schema to this "datetimeUtc" column type. import { datetimeUtc } from './datetimeUtc'
export const post = mysqlTable("Post", {
// ...
createdAt: datetimeUtc("createdAt", 3).default(sql`(CURRENT_TIMESTAMP(3))`).notNull(),
updatedAt: datetimeUtc("updatedAt", 3).default(sql`(CURRENT_TIMESTAMP(3))`).notNull(),
// ...
}) Now, when you store datetimes, you can be certain they will be stored as UTC, and when you retrieve them, they will be the same UTC date that you stored. This was the most elegant solution I could find for ensuring datetimes work as expected in my codebase. For more info, see drizzle's custom types docs: https://orm.drizzle.team/docs/custom-types |
Beta Was this translation helpful? Give feedback.
-
just appealing to folks like me that are on less than 8 hours sleep in the last 3 days and would like the mysql 'date' equivalent without thinking too much about it....(although i believe drizzle will be ensuring utc date output soonish). export const dateUtc = (name: string) =>
customType<{ data: Date; driverData: string }>({
dataType() {
return `date`;
},
toDriver(value: Date): string {
// Split the MySQL date string into its components
return value.toISOString().split("T")[0];
},
fromDriver(value: string): Date {
// Create a JavaScript Date object in UTC
const [year, month, day] = value.split("-").map(Number);
const date = new Date(Date.UTC(year, month - 1, day));
return date;
},
})(name); be kinda awkward if this solution was riddled with bugs...so tired im seeing sounds atm.... @miketromba hope i didn't butcher :/ |
Beta Was this translation helpful? Give feedback.
-
Note: #1082 is merged and is released in
https://github.com/drizzle-team/drizzle-orm/releases/tag/0.28.6 |
Beta Was this translation helpful? Give feedback.
Note: #1082 is merged and is released in
0.28.6
https://github.com/drizzle-team/drizzle-orm/releases/tag/0.28.6