誰も使ってなさそうなPHP関数date_create_from_format()
の挙動が変わった話を紹介します。
誰も困らない内容だと思いますが、気付いてしまったので記録として残しておきます。
date_create_from_format関数とは
date_create_from_format()
は任意のフォーマットの日付文字列を元にDateTime
インスタンスを返す関数です。
<?php
$dt = date_create_from_format("Y年m月d日 H時i分s秒", "2019年1月2日 12時34分56秒");
var_dump($dt->format("Y-m-d H:i:s"));
このように第一引数でフォーマットを指定し、第二引数に日付文字列を渡して利用します。上記コードを実行すると次の結果を得ます。
string(25) "2019-01-02 12:34:56"
指定されていない部分の扱いについて
date_create_from_format
の引数で年月日時分秒のうち一部しか与えられなかったような場合、指定されなかった部分には現在の時刻が採用される、とPHPマニュアルには書いてあります。
format に文字 ! が含まれない場合は、作成した時刻値のうち format で指定されていない部分を 現在のシステム時刻で初期化します。
これは次のように確認することができます。
<?php
$dt = date_create_from_format("H時i分s秒", "12時34分56秒");
var_dump($dt->format("Y-m-d H:i:s"));
これを2019-10-02に実行したところ次の結果が得られました。
string(25) "2019-10-02 12:34:56"
指定されなかった年月日が現在の値で埋められており、マニュアルの記述通りの挙動であることがわかります。
しかし、マニュアルの記述は不正確で、特定の条件の時にゼロが入ることがあります。
<?php
$dt = date_create_from_format("s秒", "56秒");
var_dump($dt->format("Y-m-d H:i:s"));
これを実行すると次のようになります。
string(25) "2019-10-02 00:00:56"
秒しか指定しなかった場合に、時と分は現在時刻で埋められず、必ず0になります。これ以外の組み合わせでも、時分秒のうち1つまたは2つが指定された場合、指定されなかった部分は0になります(これは文書化されていない情報だと思います)。
PHP 7.3でフォーマット文字列"u"の扱いが変わった
ようやく本題です。PHP 7.3からフォーマット文字列で"u"(マイクロ秒)を指定した場合の挙動が変更されています。
<?php
$dt = date_create_from_format("Y-m-d u", "2019-01-02 654321");
var_dump($dt->format("Y-m-d H:i:s.u"));
これをPHP 7.2以前で実行すると、指定されていない時分秒の全てが現在時刻になります。
string(26) "2019-01-02 13:05:46.654321"
しかし、PHP 7.3では次のようになります。
string(26) "2019-01-02 00:00:00.654321"
マイクロ秒が指定された場合も、時分秒のうち指定されていない部分が0になるようになりました。
まとめ
もともと文書化されていない挙動がPHPの特定バージョンから変わったよ、というお話でした。
補足
本件バグレポ上がってるけど瞬時にDocumentation Problemに格下げになってますね。