はじめに
🤔「new Date() で取得される時間って、何の時間なんだろう…?」
😰「端末の時間?ブラウザの時間?インターネットの正確な時間?」
🫠「Next.jsだとサーバーとクライアントで時間が違ってエラーが出る…!」
JavaScriptの new Date() は、日常的に使うメソッドの一つですよね🍵
ですが、この時間がどこから取得されているのかを正確に理解していないと、思わぬバグやセキュリティリスクにつながります💦
今回は、new Date() の取得元の仕組みと、フロントエンド開発(特にNext.js)で絶対に知っておくべき注意点を整理します🔍
時間の扱いでハマった経験がある方や、これから本格的にWeb開発を始める方の参考になれば幸いです🙏
結論:new Date() はOSの内蔵時計の時間
いきなり結論ですが、new Date() で取得される時間は 「コードが実行されている端末(OS)の内蔵時計の時間」 です⏰
const now = new Date()
console.log(now) // → 端末(OS)の時計が示す現在時刻
インターネット上の正確な時間(NTPサーバーなど)をわざわざ取得しにいっているわけではありません🙅
仕組みをもう少し詳しく
ブラウザでJavaScriptを実行した場合、ブラウザはOSに対して「いま何時?」と尋ねます👂
🌐 ブラウザ「今何時〜?」
↓
💻 OS(Windows / Mac / iOS / Android)「えーっと…今は 2026年4月7日 12:00:00 だよ!」
↓
📦 new Date() → 2026-04-07T12:00:00
⚠️ インターネット(NTPサーバー等)に聞きにいっているわけではなく、あくまで端末の内蔵時計に聞いているだけ!
つまり、ユーザーがパソコンやスマホの時計を手動で 「1年後の未来」 や 「10年前の過去」 にズラしていれば、new Date() もそのままズレた時間を返します🙃
フロントエンド開発における鉄則:クライアントの時間は絶対に信用しない
この仕様があるため、Web開発には 「クライアント(ブラウザ)の時間は絶対に信用するな」 という鉄則があります🔥
❌ 危険な実装例
「今日がキャンペーンの期限内かどうか」を、フロントエンドの new Date() で判定するパターンです👇
const now = new Date()
const campaignEnd = new Date('2026-04-30T23:59:59')
if (now <= campaignEnd) {
// 購入ボタンを表示
showPurchaseButton()
} else {
// 「キャンペーンは終了しました」を表示
showExpiredMessage()
}
何が問題か🚨:
- ユーザーが端末の時間を過去に戻すだけで、期限切れのボタンが押せてしまう😱
- 逆に、端末の時間を未来にすれば、まだ始まっていないキャンペーンにアクセスできてしまう🫣
✅ 正しい実装例
重要な時間の判定は必ずサーバー側で行い、フロントエンドはサーバーから送られてきた判定結果を受け取って画面を描画するだけにしましょう💪
// フロントエンド側
const response = await fetch('/api/campaign/status')
const { isActive } = await response.json()
if (isActive) {
showPurchaseButton()
} else {
showExpiredMessage()
}
// サーバー側(API)
export async function GET() {
const now = new Date() // サーバーの時間は信頼できる
const campaignEnd = new Date('2026-04-30T23:59:59+09:00')
return Response.json({
isActive: now <= campaignEnd
})
}
ポイント💡:
- サーバーの時計はNTPで自動同期されており、ユーザーが操作できない🔒
- フロントエンドは判定結果(True/False)を受け取るだけに徹する🎯
- 時間に依存するビジネスロジックは、すべてサーバーサイドに寄せる🏠
Next.js環境での new Date() の落とし穴
Next.js(App Routerなど)で開発していると、new Date() の挙動がさらにトリッキーになります🤯
「どこでコードが実行されたか」で返される時間が変わるからです😱
実行環境による違い
| 実行場所 | 取得される時間 |
|---|---|
クライアントコンポーネント("use client") |
アクセスしてきたユーザーの端末の時間(端末のタイムゾーン) |
| サーバーコンポーネント | サーバー(インフラ)の時間(基本はUTC) |
| API Routes | サーバー(インフラ)の時間(基本はUTC) |
| Server Actions | サーバー(インフラ)の時間(基本はUTC) |
Vercelなどのホスティング環境では、サーバーの時刻は基本的にUTC(協定世界時)で動いています🌍
日本時間(JST)とは9時間のズレがあるので要注意です⏳
Hydration Errorの発生パターン
Next.jsで最もハマりやすいのが、サーバーとクライアントで new Date() の結果が食い違うことで発生するHydration Errorです💥
// ❌ Hydration Errorが起きやすいパターン
export default function CurrentTime() {
const now = new Date()
return <p>現在時刻: {now.toLocaleString('ja-JP')}</p>
}
何が起こるか:
1. サーバー側で new Date() を実行
→ UTC: 2026-04-07T03:00:00(サーバーの時刻)
→ HTMLを生成して送信
2. クライアント側で new Date() を実行(Hydration)
→ JST: 2026-04-07T12:00:00(ユーザーの端末の時刻)
3. サーバーとクライアントで描画内容が一致しない
→ 💥 Hydration Error 発生!
Reactは、サーバーで生成したHTMLとクライアントで再実行した結果が一致することを前提としています🤝
時間のように実行タイミングで値が変わるものは、この前提を簡単に崩してしまうんです…😢
✅ Hydration Errorを防ぐ方法
方法1:クライアント側でのみ時間を表示する
'use client'
import { useEffect, useState } from 'react'
export default function CurrentTime() {
const [currentTime, setCurrentTime] = useState<string>('')
useEffect(() => {
setCurrentTime(new Date().toLocaleString('ja-JP'))
}, [])
if (!currentTime) return <p>読み込み中...</p>
return <p>現在時刻: {currentTime}</p>
}
useEffect はクライアント側でのみ実行されるため、サーバーとのズレが発生しません✨
方法2:サーバー側で時間を取得してPropsで渡す
// Server Component
export default async function Page() {
const serverTime = new Date().toISOString()
return <TimeDisplay serverTime={serverTime} />
}
'use client'
// Client Component
export function TimeDisplay({ serverTime }: { serverTime: string }) {
const formattedTime = new Date(serverTime).toLocaleString('ja-JP')
return <p>現在時刻: {formattedTime}</p>
}
サーバーで取得した時間を文字列としてクライアントに渡すことで、Hydrationの整合性を保ちつつ、クライアント側でタイムゾーンに合わせた表示ができます👌
意識すべきポイントまとめ
new Date() を使う際に常に意識したいのは、「これは今、どこで実行されているのか?」 という視点です👀
✅ チェックポイント
1. これはユーザーの端末で実行されている?
→ 時間は信頼できない(操作可能)
→ 表示目的のみに使う
2. これはサーバーで実行されている?
→ 時間は信頼できる
→ ただしUTCなので、タイムゾーン変換を忘れずに
3. この時間はビジネスロジックに使われる?
→ 必ずサーバー側で判定する
4. Next.jsのコンポーネントで使っている?
→ サーバー/クライアントどちらで実行されるか確認
→ Hydration Errorに注意
まとめ
🎯 重要なポイント
-
new Date()はOSの時計を参照:インターネットから取得しているわけではない⏰ - クライアントの時間は信用しない:ユーザーが自由に変更できるため、ビジネスロジックに使わない🙅
- 時間の判定はサーバーサイドで行う:キャンペーン期限、アクセス制御などは必ずサーバーで処理🔒
- Next.jsでは実行環境を意識する:サーバー(UTC)とクライアント(端末のTZ)の違いがHydration Errorの原因になる💥
🚀 個人的な学び
当たり前のように使っている new Date() ですが、改めて調べてみると🔍
- 取得元がOSの時計であることの影響範囲は想像以上に広い🌐
- Next.jsのサーバー/クライアント境界と組み合わさると、さらに複雑になる🌀
- 「表示用」と「判定用」で時間の扱い方を明確に分けることが大切🎯
シンプルなメソッドほど、仕組みを正しく理解しておくことがバグの予防につながりますね💪!
最後に
new Date() の挙動、知っているようで意外と奥が深いですよね🍵
皆さんも時間の扱いでハマった経験はありますか🤔?
タイムゾーン関連のトラブルや、便利なライブラリの活用方法があれば、ぜひコメントで教えてください🙌
時間にまつわる開発Tipsやハマりポイントなども共有していただければと思います🌏!
