strtotimeの便利さと罠を見きわめる

strtotime とは、日付や時刻を表す文字列を解釈して Unix タイムスタンプに変換する関数です。相対表記の指定が特に得意な反面、書式の曖昧さには注意が要ります。

相対表記が強力すぎる

strtotime() は文字列を解釈して Unix タイムスタンプに変換してくれる関数で、特に相対表記が強力です。「来週の月曜」や「1か月前」みたいな指定がそのまま通るので、バッチの日付計算などで重宝しています。

$now = strtotime('now');

echo date('Y-m-d', strtotime('+1 week'));       // 1週間後
echo date('Y-m-d', strtotime('first day of next month'));
echo date('Y-m-d', strtotime('-3 days', $now)); // 基準日から3日前

第2引数に基準タイムスタンプを渡せるので、「ある日付から見て何日前」といった相対計算もできます。この柔軟さが魅力である一方、油断すると足をすくわれます。

曖昧な書式は解釈がぶれる

いちばんの罠が日付書式の曖昧さです。01/02/2024 のようなスラッシュ区切りはアメリカ式(月/日)と解釈され、日本人の感覚(日/月)とはずれます。ダッシュやドット区切りだと解釈が変わることもあり、入力元が信用できないデータでこれをやると静かにバグります。

// スラッシュは月/日 と解釈される
echo date('Y-m-d', strtotime('01/02/2024')); // 2024-01-02

// 意図が明確な ISO 形式なら安心
echo date('Y-m-d', strtotime('2024-01-02')); // 2024-01-02

フォーマットが決まっている入力なら、strtotime() に推測させず DateTime::createFromFormat() で明示的にパースするほうが安全だと思います。

失敗はfalse、必ず判定する

解釈できない文字列を渡すと strtotime()false を返します。ここで false チェックを怠ると、date() に食わせた瞬間に 1970-01-01(タイムスタンプ 0)扱いになったりして、原因の分かりにくいバグになります。false0 は別物なので、比較は必ず厳密等価で行うのが肝ですね。

$ts = strtotime($input);
if ($ts === false) {
    throw new InvalidArgumentException("日付として解釈できません: {$input}");
}
echo date('Y-m-d H:i', $ts);

まとめ

strtotime() は相対表記が効く場面ではとても便利ですが、書式の曖昧さと false 判定という二つの罠があります。信頼できない入力は createFromFormat() で厳格に、相対計算のような用途に限って strtotime() を使う、と役割を分けると事故が減ると思います。戻り値の false は厳密比較で拾う、これだけは徹底したいところです。

よくある質問

Q. 「来週の月曜」のような指定はできますか?
A. できます。'+1 week''first day of next month' などの相対表記がそのまま通るので、バッチの日付計算で重宝します。

Q. 01/02/2024 はどう解釈されますか?
A. スラッシュ区切りはアメリカ式(月/日)と解釈されます。書式が決まっている入力は DateTime::createFromFormat() で明示的にパースするほうが安全です。

Q. 解釈できない文字列を渡すとどうなりますか?
A. false が返ります。false0 は別物なので、必ず === false の厳密比較で判定します。怠ると date() で 1970-01-01 扱いになりバグの原因になります。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です