CreaTools LogoCreaTools
Tips

PHPで日時切り替えを実装する前に確認すること

2025-11-12

この記事が解決する状況

あなたの状況読むべきセクション
「◯月◯日 0時に切り替えて」と依頼された実装前に確認すること
本番で動かなかった経験があるキャッシュ環境での選択肢
WordPressで日時切り替えを実装したいWordPress:ショートコード化
キャッシュプラグインを使っているJavaScript実装

「テスト環境では動いたのに本番で動かない」を経験したことがあるなら、必ず読むべき。


よくある失敗

「11月10日 0時に切り替わるはずが、翌朝まで旧バナーのままだった」

コードは正しい。でもキャッシュが効いていて、PHPが実行されていなかった。


実装前に確認すること

項目確認方法NGだった場合
サーバー時刻echo date('Y-m-d H:i:s');NTPで同期、またはオフセット計算
ページキャッシュキャッシュプラグインの設定該当ページを除外
CDNキャッシュCloudflareなどのTTL設定動的コンテンツとして除外

キャッシュが効いている環境では、PHPの日時判定は機能しない。

これを知らずに実装すると、テスト環境で動いて本番で動かない。


事故事例:タイムゾーンと時刻の罠

事例1: 9時間ズレた

状況: 0時に切り替わるはずが、9時に切り替わった
原因: サーバーのタイムゾーンがUTCだった
対処: date_default_timezone_set('Asia/Tokyo') を追加

事例2: キャンペーン終了後も表示され続けた

状況: 11月20日で終了のはずが、21日も表示されていた
原因: 終了条件を設定し忘れた(開始条件のみだった)
対処: 期間指定は必ず開始・終了両方をチェック

事例3: 本番だけ動かない

状況: ローカル・ステージングでは動く、本番だけ古いまま
原因: 本番にはページキャッシュが効いていた
対処: 該当ページをキャッシュ除外、またはJS実装に切り替え

キャッシュ環境での選択肢

方法メリットデメリット
該当ページをキャッシュ除外PHP判定がそのまま使えるそのページだけ遅くなる
JavaScriptで切り替えキャッシュの影響を受けないクライアント時刻依存、SEO的に不利
Cronで静的ファイル生成高速、確実実装が複雑

判断基準: キャッシュを外せるならPHP、外せないならJavaScript。


PHP実装:基本パターン

<?php 
date_default_timezone_set('Asia/Tokyo');
$now = date('Y-m-d H:i');
$target = '2024-11-10 00:00';
?>

<?php if ($now >= $target): ?>
  <div class="banner-new">新キャンペーン実施中</div>
<?php else: ?>
  <div class="banner-old">Coming Soon</div>
<?php endif; ?>
ポイント理由
date_default_timezone_setサーバーのデフォルトがUTCの可能性
Y-m-d H:i 形式文字列比較で正しく動作する

なぜこの書き方が安全か

Y-m-d H:i 形式は辞書順ソートと時系列が一致する。2024-11-10 00:002024-11-09 23:59 より「文字列として」大きい。これが d/m/Y 形式だと壊れる。


PHP実装:期間指定

<?php
date_default_timezone_set('Asia/Tokyo');
$now = date('Y-m-d H:i');
$start = '2024-11-10 00:00';
$end = '2024-11-20 23:59';
?>

<?php if ($now >= $start && $now <= $end): ?>
  <div class="campaign-banner">期間限定セール開催中</div>
<?php endif; ?>

開始と終了を両方チェック。片方だけだと終了後も表示され続ける。


PHP実装:複数フェーズ

<?php
date_default_timezone_set('Asia/Tokyo');
$now = date('Y-m-d H:i');
?>

<?php if ($now < '2024-11-01 00:00'): ?>
  <p>予告</p>
<?php elseif ($now < '2024-11-10 00:00'): ?>
  <p>エントリー受付中</p>
<?php elseif ($now < '2024-11-20 00:00'): ?>
  <p>投票期間</p>
<?php else: ?>
  <p>結果発表</p>
<?php endif; ?>

上から順に評価される。条件の順序を間違えると意図しない表示になる。


WordPress:ショートコード化

再利用するならショートコードにしておく。

// functions.php
function timed_content_shortcode($atts, $content = null) {
    date_default_timezone_set('Asia/Tokyo');
    
    $atts = shortcode_atts([
        'start' => '',
        'end' => '',
    ], $atts);
    
    $now = date('Y-m-d H:i');
    
    if (!empty($atts['start']) && $now < $atts['start']) {
        return '';
    }
    if (!empty($atts['end']) && $now > $atts['end']) {
        return '';
    }
    
    return do_shortcode($content);
}
add_shortcode('timed', 'timed_content_shortcode');

投稿・固定ページで使用:

[timed start="2024-11-10 00:00" end="2024-11-20 23:59"]
期間限定コンテンツ
[/timed]

WordPressでの注意点

WordPressは wp_timezone() でサイト設定のタイムゾーンを取得できる。管理画面の「設定 → 一般 → タイムゾーン」と一致させたい場合:

function timed_content_shortcode($atts, $content = null) {
    $timezone = wp_timezone();
    $now = (new DateTime('now', $timezone))->format('Y-m-d H:i');
    // ...
}

JavaScript実装(キャッシュ環境用)

PHPが使えない場合の代替。

<div id="timed-content" data-start="2024-11-10T00:00:00+09:00">
  <div class="before">Coming Soon</div>
  <div class="after" style="display:none;">公開中</div>
</div>

<script>
(function() {
  const container = document.getElementById('timed-content');
  const start = new Date(container.dataset.start);
  const now = new Date();
  
  if (now >= start) {
    container.querySelector('.before').style.display = 'none';
    container.querySelector('.after').style.display = 'block';
  }
})();
</script>

注意: クライアント側の時刻に依存する。厳密な制御には不向き。

JSの限界

  • ユーザーのPC時刻がズレていたら意図しない表示になる
  • 「厳密に0時に切り替わる必要がある」案件には不向き
  • SEO観点では、クローラーがJSを実行しないと古いコンテンツがインデックスされる

本番前チェックリスト

項目確認
サーバー時刻は正しいかecho date('Y-m-d H:i:s');
タイムゾーン設定はあるかdate_default_timezone_set('Asia/Tokyo')
キャッシュ除外設定はあるかプラグイン・CDNの設定
終了日時も設定したか開始だけだと永久表示
テスト方法は決めたか日時を変えてテストできるか
ロールバック手順はあるか動かなかった時の対処

まとめ

  • キャッシュ環境ではPHP日時判定が効かない
  • 実装前にキャッシュ設定を確認、除外できるか判断
  • タイムゾーンとサーバー時刻の確認は必須
  • 期間指定は開始・終了の両方をチェック
  • キャッシュを外せないならJavaScriptで対応
  • Y-m-d H:i 形式を使えば文字列比較で正しく動く

関連記事