あまり知られていないとおもいますが、実は PHP でも元号を使って日付を表示することができます。表示可能なのは明治 6 年以降でそれ以前は "西暦" と表示されます。
明治 6 年というとずいぶん中途半端な感じがしますが、Wikipedia1 によるとこの年に新暦となり、旧暦(天保暦)から新暦(グレゴリオ暦) に変更されていて、西暦の日付と和暦の日付が一致するようになったからだと思います。
なお今回例示用に利用した環境は以下の通りです。
$ php -v PHP 7.2.15-0ubuntu0.18.04.2 (cli) (built: Mar 22 2019 17:05:14) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.15-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies
さて、本題です。いきなりいくつかの実行例をみていただきましょう。
$ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%Ec\n");' 平成31年04月04日 11時22分52秒 $ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%EC\n");' 平成 $ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%Ex\n");' 平成31年04月04日 $ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%EX\n");' 11時23分16秒 $ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%Ey\n");' 31 $ php -r 'setlocale(LC_TIME,"ja_JP.UTF-8") ; echo strftime("%EY\n");' 平成31年
ポイントは setlocale()2 関数でロケールを日本に設定して、strftime()3 関数で書式指定して出力しています。その時に書式指定として "%E" 修飾子を追加することで和暦の年号が出力されています。
"%E" はロケールに依存した別表記と定義されているので、日本では元号が表示されるという仕組みです。
さていくつかの境界事例を見てみましょう。strftime() 関数は、日付時刻の指定に UNIX タイムを利用するので、ここでは mktime()4 関数を利用しています。
明治 6 年 (1873) 以前と以後
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,1,1,1873)-1);' 西暦1872年12月31日 23時59分59秒 ~$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,1,1,1873));' 明治6年01月01日 00時00分00秒
明治から大正への改元は 1912 年 7 月 30 日5
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,7,30,1912)-1);' 明治45年07月29日 23時59分59秒 $ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,7,30,1912));' 大正元年07月30日 00時00分00秒
大正から昭和への改元は 1926 年 12 月 25 日6
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,12,25,1926)-1);' 大正15年12月24日 23時59分59秒 $ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,12,25,1926));' 昭和元年12月25日 00時00分00秒
昭和から平成への改元は 1989 年 1 月 8 日。7 急に学校が休みになってびっくりした記憶があります。
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,1,8,1989)-1);' 昭和64年01月07日 23時59分59秒 $ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,1,8,1989));' 平成元年01月08日 00時00分00秒
ついでにほとんど利用することは無いと思いますが、紀元前と紀元後
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",mktime(0,0,0,1,1,1));' 平成13年01月01日 00時00分00秒
おや変ですね。mktime() のマニュアル8 を参照すると以下の記載があります。
2 桁または 4 桁の値を指定可能で、 0-69 の間の値は 2000-2069 に、70-100 は 1970-2000 にマップされます。
おっと、うっかりしていました。ということは、0-100 年は mktime() が使用できません。代わりに date_create_from_format()9 と date_format()10 関数を利用してみます。
$ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",date_format(date_create_from_format("Y-m-d H:i:s","0001-01-01 00:00:00"),"U"));' 西暦1年01月01日 00時00分00秒 $ php -r 'setlocale(LC_TIME,"ja_JP.utf8") ; echo strftime("%Ec\n",date_format(date_create_from_format("Y-m-d H:i:s","0001-01-01 00:00:00"),"U")-1);' 紀元前1年12月31日 23時59分59秒
ちゃんと表示されましたね。
さて気になる新元号「令和」への対応ですが、strftime() は glibc が持っているロケールデータを利用しているので、glibc での対応待ちとなります。glibc では、アップストリームの git に追加データのコミットが 2019/4/2 にされていますので、間もなく各ディストリビューションからアップデートがリリースされると思います。
そこで注意してほしいのは php そのものではなく glibc もしくは ロケールデータの更新となることに注意してください。