"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

PHPの日付時刻ライブラリCarbonの和暦表示がWindowsでうまくいかない件

Larvelでもよく使う「日付・時刻ライブラリ」CarbonをWindows環境で試しにさわってみた時に、和暦表示とかがうまくいかなかったりしたので、そのへんをメモがわりに書いておきます。

f:id:arakan_no_boku:20190922143447p:plain

 

はじめに

 

CarbonはLaravelに同梱されています。

でも、Laravel専用ではなく、普通に素のPHPと組み合わせても使えます。

日付・時刻処理をPHPで扱うケースについて「PHP The Right Way」にも、こんな風に書かれている位、スタンダードになってます。

CarbonならDateTimeの全てを継承したうえで、地域化のサポートやDateTimeオブジェクトの加減算やフォーマット方法が追加されている

実際、非常に便利です。

自分も日付・時刻処理は、1つを除いて、ほぼCarbonでやってます。

その1つ・・とは、和暦表示などのロケール情報を使った一部フォーマットです。

ネットで情報を見てると、結構、和暦表示にCarbonの機能を使った例も紹介されていますし、実際うまくいくケースもあるのですが、少なくとも「Windows」ではうまくいかなくて・・結構、最初ははまります。

なので、今回は備忘もかねて、Carbonの機能等についてのおおまかな整理と「うまくいかない使い方」の話題を書いておきます。

 

CarbonをLaravel以外で使うならインストールが必要です

 

CarbonはLaravelをインストールしたら、いっしょにはいります。

Laravelを使わないなら、もプロジェクトにインストールする必要があります。

その場合は、プロジェクトフォルダをカレントにして、composerでインストールします。

composer require nesbot/carbon

カレントフォルダのvenderの下にインストールされます。

 

Carbonに関する情報について

 

Carbonは多機能です。

でも、インタフェースがすっきりしているので、以下のようなページで、サンプルを見れば、なんとなくでも使えてしまう敷居の低さがあります。

まずは本家の方

carbon.nesbot.com

英語なので、自動翻訳してみれば良いと思います。

日本語だと、こちらですかね

blog.capilano-fw.com

実例 217件!

お疲れ様って感じです。

 

DateTimeのサンプルをCarbonで書き直す

 

Carbonを使うには、オートローダーで読み込んで、「use Carbon\Carbon」します。

CarbonはDateTimeを全継承しています。

https://secure.php.net/book.datetime

なので、DateTimeと非常に親和性が高いです。

例として、「PHP The Right Way」のDateTimeのサンプルプログラムをCarbonで書き直してみます。

さて。

ソースはこんな感じ。

src\CarbonSample.php

<?php
require __DIR__ . "/../vendor/autoload.php";

use Carbon\Carbon;

// 開始日付オブジェクトの生成
$raw = '22. 11. 1968';
$start = Carbon::createFromFormat('d. m. Y', $raw);
echo '開始日: ' . $start->format('Y年m月d日') . "\n";

echo "--------------------------------------------\n";

// 開始日付をコピーして、1か月と6日を足して、終了日にする
$end = clone $start;
$end->add(new DateInterval('P1M6D'));

// 開始日と終了日の差を計算して何カ月・何日差があるかを表示する
$diff = $end->diff($start);
echo '開始日と終了日の差: ' . $diff->format('%m ケ月, %d 日 (合計: %a 日の差がある)') . "\n";

echo "--------------------------------------------\n";

// 日付同士を比較もできる
if ($start < $end) {
    echo "開始日は終了日よりも前の日付です。!\n";
}

echo "--------------------------------------------\n";

// 期間オブジェクトを作って、期間中の木曜日の日付をリストする
$periodInterval = DateInterval::createFromDateString('first thursday');
$periodIterator = new DatePeriod($start, $periodInterval, $end, DatePeriod::EXCLUDE_START_DATE);
echo "開始日と終了日の間の期間にある木曜日をリストします。\n";
foreach ($periodIterator as $date) {
    // 毎木曜日を表示する
    echo $date->format('Y年m月d日') . "\n";
    
}

日本語表記にするなどの表面的なところ以外で、元のDateTimeのサンプルから変更した部分は一か所だけです。

元が

$start = DateTime::createFromFormat('d. m. Y', $raw);

 となっていたところを、

 $start = Carbon::createFromFormat('d. m. Y', $raw);

 と書き換えただけです。

実際には、英語表記のままでは芸がないので、表示する名称や年月日などの表記を日本語に変えたりしましたが、それですんなり動くのですから、確かに親和性が高いです。

上記ソースは、手間をはぶくため、あえて素のPHPで作ってみました。

コマンドラインで「php .\src\CarbonSample.php」みたいに動かす前提です。

なので、先頭で「require __DIR__ . "/../vendor/autoload.php";」もしています。

実行した結果はこんな感じになります。

f:id:arakan_no_boku:20190926012100p:plain 

 

CarbonのformatLocalizedには癖がある・・

 

実は。

最初は、上記のプログラムで和暦表示も試しました。

でも、うまくいきませんでした。

試してみたのは、曜日の日本語表示。

setlocale(LC_ALL, 'ja_JP.UTF-8');
echo Carbon::now()->formatLocalized('%Y %B %d(%a)');

 それと、年の和暦表示。

setlocale(LC_ALL, 'ja_JP.UTF-8');
Carbon::now()->formatLocalized('%EC%Ey年');

の2つです。

ひとつめは曜日を(月)とか(木)のように日本曜日名で表示させるつもりで、3つめは年の部分を、平成31年とか令和1年とかの和暦で表示させようとしたわけです。

ところが、うまく表示できませんでした。

調べてみると。

どうも「formatLocalized」というメソッドが、「かなりOSに依存する部分が大きいメソッド」らしいということ。

依存する部分を具体的に書くと

  • 「setlocale」のOS依存
  • 「format書式サポート」のOS依存

の2つです。

 

「setlocale」のOS依存

 

例えば・・。

上記のローカライズの前提になっている「setlocale(LC_ALL, 'ja_JP.UTF-8');」が、LinuxではOKですが、Windowsでは動かないらしいというものです。

理由は、こちらの記事に書いてありました。

docs.microsoft.com

たしかに

If you provide a code page value of UTF-7 or UTF-8, setlocale will fail, returning NULL.

UTF-7またはUTF-8のコードページ値を指定すると、setlocaleは失敗し、NULLを返します。)

とあります。

WindowsでもPHP5までは動いてた・・という情報もありますが、少なくとも、自分の「PHP7.3」+Windows環境では見事に動かないから、そうなんでしょう・・。

 

「format書式サポート」のOS依存

 

 和暦を表示する「%EC」とか「%E」という書式は、対応しているシステムとそうでないシステムがあるらしいのです。

これは自分も知らなくて、以下の記事で知りました。

teratail.com

結局。

Linuxでもディストリビューションによって差があり、Macはダメ。

自分が試した感じだと、Windowsもうまくいかないっぽい。

これは厳しいですよね。

 

和暦とかは必要になったら考えよう

 

ということで。

Carbonは使うけど、和暦表示や曜日の日本語表示などについては、Carbonに頼らず、必要になったら別途用意する・・と考えた方が良さげ・・と思ってます。

開発がWindowsで、本番がLinuxというケースは実際多いです。

OS依存のあるメソッドは使わないほうが賢明です。

幸いにして。

DateTimeを使って、和暦表示したり、曜日を日本語表示したりするようなTipsやサンプルはネットにいっぱいあります。

そこまで凝らずに、せいぜい明治以降の年だけ見ればよいなら、一から作っても、和暦表示自体それほど大変な手間がかかる・・ってほどでもありません。

それに。

今時、システムは西暦で統一というところも多く、和暦そのものが必要ない場合も増えてます。

官公庁に提出する書類を作るみたいな和暦が必要な要件ができてから、考えればいいや・・と、個人的には考えてるので「Carbonでできると安易に考えてはいけない」ということだけ忘れないようにできれば、まあいいか・・って感じです。 

今回はこんなところで。

ではでは。