Foundation
ADR

日付処理の自前実装

外部日付ライブラリを使わず、自前のDate型ラッパーを実装した理由。

コンテキスト

勤怠管理システムでは日付・時刻の処理が頻繁に発生する(シフト、打刻、勤務時間計算等)。JavaScriptの Date 型はミュータブルであり、タイムゾーンの扱いが暗黙的で、バグの温床になりやすい。

検討した選択肢

  • 自前実装 (@bi-shop-it/lib/date)DateOnly(日付のみ)と DateTime(日時)のブランド型を定義し、薄いラッパー関数を提供する
  • date-fns — 関数ベースの日付ユーティリティライブラリ
  • Day.js / Luxon — オブジェクト指向ベースの日付ライブラリ

決定

外部日付ライブラリは使用せず、@bi-shop-it/lib/dateDateOnly 型と DateTime 型を自前で定義する。内部実装はネイティブの DateIntl APIを使用する。

自前実装を選んだ理由

  • ブランド型による型安全DateOnlyYYYY-MM-DD 形式の文字列)と DateTimeYYYY-MM-DDTHH:mm:ss.000Z 形式の文字列)をブランド型として定義することで、生の stringDate との混同をコンパイル時に防ぐ
  • タイムゾーンの明示的な扱い — すべての変換関数でタイムゾーンを引数として要求し、暗黙的なローカルタイムゾーン依存を排除する
  • 必要最小限の関数セット — 勤怠管理に必要な関数(日数差分、月末計算、日付加算等)のみを提供し、1〜2行で書ける処理はライブラリに含めない
  • 外部依存ゼロ — ネイティブAPIのみで実装することで、バンドルサイズへの影響がない。フォーマットは標準の Intl.DateTimeFormat を使用する
  • 文字列ベースの設計 — 日付をISO 8601文字列として扱うことで、DBへの保存、APIでの送受信、=== での比較がすべてシンプルになる

影響

  • Date 型の直接使用を禁止する — ESLintルールで Date のグローバル使用を禁止し、@bi-shop-it/lib/date の使用を強制する
  • UTCを正とするDateTime は常にUTC(.000Z 終端)で保持し、表示時にのみタイムゾーン変換を行う
  • 追加基準を設ける — 新しい関数の追加は、(1) 複数アプリで必要、(2) 自前実装するとバグを生みやすい(月末、閏年、TZ等)、(3) 1〜2行で書けない、の3条件を満たす場合のみ許可する

On this page