generated at
プログラム内部のDateをUTCに統一する

Dateは2つの軸で問題がある
タイムゾーンを統一するかどうか
UTC? JST?
日付のフォーマットを統一するかどうか
ISO8601? UnixTime?


「外部」をどこまでと見なすか
パターン1
内部: プログラム内部
外部: DB, View
パターン2
内部: プログラム内部, DB
外部: View
これは状況にもよる
DBが他のシステムからもアクセスされるならパターン1だろうし、
そうじゃないならパターン2のほうが単純


内部のデータ構造の要件
他の型と識別できる
TSならbranded typeなど
serializeできる
TSならDateは無理
superjsonを使う案もある



結論の例
Prismaを使っているような状況だとする
プログラムの内部では、
UTCを使用する
フォーマットはISO8601に準拠する
UnixTimeより可読性が高いので
例えば以下のようなモジュールを用意する
dayjszod.string().datetime()を使っている
ts
import { z } from 'zod'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; dayjs.extend(utc); dayjs.extend(timezone); // ISO8601 (UTC) export type UTC = z.infer<typeof UTC>; export const UTC = z.string().datetime().brand<'UTC'>(); export const mkUTC = (date: string | Date): UTC => { if (date instanceof Date) { const utcDate = dayjs(date).tz('UTC').format(); return UTC.parse(utcDate); } if (!date.includes('T')) { throw new Error( 'Invalid date format. Expected a combined date and time in the ISO 8601 format.', ); } if (date.endsWith('Z')) { return UTC.parse(date); } if (date.includes('+') || date.includes('-')) { const utcDate = dayjs(date).tz('UTC').format(); return UTC.parse(utcDate); } throw new Error('Invalid input type. Expected string or Date.'); }; export const toJSTFormat = (utc: UTC, template: string): string => { return dayjs(utc).tz('Asia/Tokyo').format(template); };
例えばEntityの createdAt など、プログラム内の全ての日付に UTC 型を使用する
Viewなどに日付を表示する際は toJSTFormat を使う
現在の時刻を出力する例
ts
toJSTFormat(mkUTC(new Date()), 'YYYY/MM/DD HH:mm:ss')


以下のような事を気にする必要がなくなる
client/serverの両方でUTCに統一される