2019/3/1に公開しました「ワードプレスの標準カレンダーを前月と今月の2ヵ月表示にする」のカレンダーショートコードですが、公開からまる2ヵ月が経ちますが、平成から令和に変わった2019/5/1 0:01:00に本サイトで標準カレンダーを2ヵ月表示している書庫(アーカイブ)のページを見たところ、何と3月と5月のカレンダーを表示していることに今更ながら気が付きました。
PHPのstrtotime関数で前月を求める時に、例えば5/31の「-1 month」のような事をしてはいけないのはネットで書かれていているので知っていましたが、時差について考慮が必要であることは気付いていませんでした。
時差が上記現象の原因であるとした理由は、本日2019/5/1 12:00過ぎに見た時は、正しく4月と5月が表示されていたからです。
なおWPの「設定」→「一般設定」のタイムゾーンは「東京」にしているので、標準のカレンダーは5月になっているのだと推測致しますが、Cocoonの子テーマのfunction.phpに追記した際にはタイムゾーンの考慮が必要だったものと思われます。
PHPの経験が浅く、大変失礼を致しました。
PHPマニュアルでstrtotimeを調べる
PHP マニュアル > 関数リファレンス > 日付および時刻関連 > Date/Time > 日付・時刻 関数 > strtotimeを見ると、「この関数の各パラメータでは、パラメータ内でタイムゾーンを指定しない限りはデフォルトのタイムゾーンを使います。」となっています。
今回の症状を見る限り、デフォルトタイムソーンがUTC(協定世界時の現在時刻)になっているものと推測致します。基本的なことで恐縮ですが、UTCと日本との時差は9時間です。
残念ながら「パラメータ内でタイムゾーンを指定しない限り」の具体的に意味する内容がイマイチ理解できていないので、「デフォルトのタイムゾーン」を設定する方法を選択することにします。
date_default_timezone_setを調べる
この関数でデフォルトタイムゾーンを設定するためにはタイムゾーン ID が必要です。
そこでサポートされるタイムゾーンのリストから「Asia/Tokyo」を選択することにしました。
以上を反映したものが下記になります。
2020/1/1【追記】
なお、タイムソーン変更し、計算が終了した後に「Asia/Tokyo」から世界標準時間「UTC」タイムソーンを戻す必要があります。
下記の13行目を追記して正しく動くことを確認しています。
//カレンダーショートコード add_shortcode('calendar-1', 'calendar_shortcode'); if ( !function_exists( 'calendar_shortcode' ) ): function calendar_shortcode( $atts, $content = null ) { extract( shortcode_atts( array( 'month' => 1, ), $atts ) ); ob_start(); global $monthnum, $year; date_default_timezone_set('Asia/Tokyo'); $monthnum = date('m', strtotime(date('Y-m-1') . '-' . $month . ' month')); $year = date('Y', strtotime(date('Y-m-1') . '-' . $month . ' month')); date_default_timezone_set('UTC'); get_calendar(); return ob_get_clean(); } endif;
いままでのバージョンとの違いは、10行目と13行目になります。
まとめ
なおPHPマニュアルのstrtotime関数の「注意」につぎのような記載があります。
- タイムスタンプの有効な範囲は、通常、Fri, 13 Dec 1901 20:45:54 UTC から Tue, 19 Jan 2038 03:14:07 UTC までです (これらは、32 ビット符号付整数の最大及び最小に一致します)。
- この関数を使って日付の足し算や引き算を行うことはおすすめできません。 PHP 5.3 以降なら DateTime::add() や DateTime::sub() を、そして PHP 5.2 なら DateTime::modify() を使いましょう。
従いまして、本来であればstrtotime関数からDateTimeクラスに変更するのが良いはずですが、この場合でもDateTime オブジェクトのタイムゾーンを設定する必要がある認識です。
そのため、まずは今回の修正での有効性を確認してからDateTimeクラスに変更したく存じます。
以上、最後までご一読いただきありがとうございました。