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