0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Webアプリ開発でハマった「日付フィルターとタイムゾーン問題」解説

Last updated at Posted at 2025-03-25

はじめに

Webアプリを作っていて、「日付フィルターをかけたのにデータが漏れる」現象に出くわしたことはありませんか?

今回は、実際に私が体験した 「日付フィルターのタイムゾーン落とし穴」 を解説します。 私と同じく、初心者の方でも理解できるよう、仕組み・原因・解決策までしっかりまとめました。


■ 発生した問題

Vue.jsの画面で「2024-03-25のデータ」を絞り込みたいと考えました。 ユーザーが「2024-03-25」を選択すると、API(Laravel)に以下のようなクエリを投げます。

{
  "order_date_from": "2024-03-25",
  "order_date_to": "2024-03-25"
}

PHP(Laravel)側ではこう受け取ってフィルターします。

if ($order_date_from) {
    $tr_study = $tr_study->whereDate('order_date', '>=', $order_date_from);
}
if ($order_date_to) {
    $tr_study = $tr_study->whereDate('order_date', '<=', $order_date_to);
}

■ なぜデータが漏れるのか?(原因)

原因は 「タイムゾーン」 です。

多くのサーバーやデータベース(MySQL)は UTC(協定世界時) で動いています。 一方、私たちが普段使っているのは 日本時間(JST/UTC+9) ですよね。

このズレによって、

  • DBの"2024-03-25"はUTC基準(日本時間だと9時間ズレ)
  • フロントはJST基準で送信

結果として「3月25日のデータなのに拾えない」「3月24日の深夜データまで拾ってしまう」現象が起きます。


■ 解決策①【MySQLのタイムゾーンをJSTに設定】

DBがJSTで動いていれば、この問題はほぼ解決します。

【手順】

XAMPPなら、C:\xampp\mysql\bin\my.ini に以下を追記します。

[mysqld]
default-time-zone = '+09:00'

その後、MySQLを再起動しましょう。

【確認】

以下のSQLを実行して、JSTになっているかチェック!

SELECT @@global.time_zone, @@session.time_zone;

結果が +09:00 なら成功!


■ 解決策②【UTC運用の場合はフロントで変換】

もし「サーバーはUTC運用」の場合は、フロントでJST→UTCに変換してAPIへ渡しましょう。

const startUtc = dayjs('2024-03-25').startOf('day').subtract(9, 'hour').toISOString();
const endUtc = dayjs('2024-03-25').endOf('day').subtract(9, 'hour').toISOString();

Laravel側はwhere()で日時比較する形がおすすめです。


■ 解決策③【日付は文字列のまま扱う設計】

もし「時刻は不要」という仕様なら、日付を文字列(YYYY-MM-DD)として扱う設計 も有効です。

【メリット】

  • タイムゾーンの影響を受けにくい
  • SQLのDATE型やwhereDate()で安全に扱える
  • UIもシンプルになる

Laravelならこう書けばOK。

if ($order_date_from) {
    $tr_study = $tr_study->whereDate('order_date', '>=', $order_date_from);
}
if ($order_date_to) {
    $tr_study = $tr_study->whereDate('order_date', '<=', $order_date_to);
}

この形なら、MySQLのDATE()で評価されるため、時刻のズレが影響しません。


■ 【保存時のCarbonの使い方】

ただし、DBにデータを保存する時点で UTCズレしていると意味がない ので、保存時にも注意が必要です。

Laravelでは、保存時にCarbonを使ってJSTに揃えて保存するのがオススメです。

// 例:文字列の日付をCarbonでJST化して保存
$order_date = Carbon::parse($request->input('order_date'))->setTimezone('Asia/Tokyo');
$model->order_date = $order_date;
$model->save();

こうすることで、保存時にもズレが起こらず、後の検索も安全になります。


■ まとめ(再発防止の教訓)

タイムゾーンは最初に設計・方針決め!(JST運用かUTC運用か)
✅ DB・サーバー・フロントで「基準時刻」を合わせる
whereDate()は便利だけど、タイムゾーン影響を受けるので注意
✅ JST運用なら my.ini にdefault-time-zoneを書く だけでも事故防止になる
✅ 時刻が不要なら、日付文字列運用+Carbonで保存時チェック が安全


■ 最後に

日付や時間はアプリ開発の永遠のテーマ。少しでも「なんでズレるの?」が減らせたらうれしいです。 この経験が誰かの役に立ちますように!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?