背景
Laravel PHP , Laravel

【Laravel】DBから取得した日付型データを文字列に変換する

こんにちは、スズキです。

Laravelを利用している際に、DBから取得した日付型のデータに対し、「YYYY年MM月DD日」形式のような任意の形式の文字列に変換したい場合ってありますよね?
今回はこの方法を紹介します。

例えば、DBテーブルtest_tablesがあり、test_tables上にpublic_dateというDateTime型のフィールドがあったとします。
この場合、せっかくDateTime型のフィールドを参照しているわけですから、できれば以下のようにPHPのDateTime->formatメソッドを直接呼び出せたらいいなって思いますよね?
        $targetId = 1;
        $targetRow = TestTable::query()
            ->where('id', '=', $targetId)
            ->first();
        $publicDate = $targetRow->public_date->format('Y-m-d');
しかし、残念なことに、取得結果の$targetRow->public_dateは標準ではDateTime型になっていません。
そのため、上記コードを実行するとformatメソッドを呼びだそうとしたタイミングでエラーで落ちてしまいます。

これは困りましたね。
かといって、DateTime型のデータを取ってきているのに、取得したデータをPHPのDateTime型に置き換える処理をわざわざ記述するのは面倒です。
できれば楽をしたい・・・

実は、Laravel先生はこのような要望のために、日付型データに変換してくれる便利な機能を提供してくれています。
方法はとても簡単です。
対象テーブルのモデルクラスに対し、以下のように$datesプロパティに目的のDateTime型フィールドの名前を記載するだけでOKです。
use Illuminate\Database\Eloquent\Model;

class TestTable extends Model
{
    protected $dates = ['public_date'];
    
    // 〜〜 略 〜〜 //
}
上記のように$datesプロパティを設定していると、$datesプロパティが指すフィールドに対し、データを取得した際にDateTime型のラッパークラスであるCarbonクラスのデータに置き換える処理を自動で行ってくれます。

そのため、以下のコード(先ほどと同じコードです)の場合も、取得結果に対し、formatメソッドを直接利用することができます。
        $targetId = 1;
        $targetRow = TestTable::query()
            ->where('id', '=', $targetId)
            ->first();
        $publicDate = $targetRow->public_date->format('Y-m-d');

さあ、これで目的の日付文字列を取得することができました。
よかった。よかった。

   ・
   ・
   ・

よくないです。
まだ、元データがNULLの場合の対処が残っています。
えっ?そんなの簡単だって?
いやいや、それって以下のようなソースコードを想像していたりしませんか?
        $targetId = 1;
        $targetRow = TestTable::query()
            ->where('id', '=', $targetId)
            ->first();

        $publicDate = null;
        // 元データがNULL以外の場合は日付文字列を取得する
        if($targetRow->public_date !== null) {
            $publicDate = $targetRow->public_date->format('Y-m-d');
        }

残念でした。
実は、上記コードを実行した場合、元データ(test_tables.public_date)がNULLの場合の
$publicDateの内容は「
-0001-11-30」のような値になります。

どうしてかというと、Laravel先生がCarbonクラスへの置き換え処理を行う際に、元データがNULLの場合もCarbonクラスに置き換えているからです。
そのため、「
if($targetRow->public_date !== null)」のようなチェック方法ではNULL値判別ができないのです。

私の方でも開発中に上記問題で困り、何か良いNULL値判別方法がないか、動作確認をして調べてみました。
すると、どうやら元データがNULLの場合は、Carbon->year値が-1になることに気が付きました。
やったね!これでNULL値チェックができる!

というわけで、以下のようにyear値を元にNULL値チェックを行うことで目的の日付文字列を取得することができます。
        $targetId = 1;
        $targetRow = TestTable::query()
            ->where('id', '=', $targetId)
            ->first();

        $publicDate = null;
        // 元データがNULL以外の場合は日付文字列を取得する
        if($targetRow->public_date->year >= 0) {
            $publicDate = $targetRow->public_date->format('Y-m-d');
        }


DateTime型データの日付文字列変換のロジックは共通しているはずなので、
できれば以下のような共通メソッドを作っておき、共通メソッドを利用するようにした方が良いでしょう。
    /**
     * 日付文字列を取得します。
     */
    public function getDateString($dateValue, $stringFormat)
    {
        // 値未設定の場合はNULLを返す
        // ※補足:Modelクラス側でDateTime型に変換していると(Model->$datesを設定していると)、
        //   本タイミングでは「-0001-11-30 00:00:00.000000」のような値が入っているのでこれを考慮する必要がある
        $year = $dateValue->year;
        $minYear = 0;
        if($year < $minYear){
            return null;
        }

        // 文字列変換
        $dateString = $dateValue->format($stringFormat);
        return $dateString;
    }

これで、以下のように利用することで、目的の日付文字列を取得できるようになります。
        $targetId = 1;
        $targetRow = TestTable::query()
            ->where('id', '=', $targetId)
            ->first();

        // 日付文字列取得
        $dateValue = $targetRow->public_date;
        $stringFormat = "Y-m-d";
        $dateString = $this->getDateString($dateValue, $stringFormat);

Laravelで日付文字列を利用したいときも、これで怖いもの無しですね。
 

追記

すみません。内容が一部間違っていました。
お手数ですが、訂正内容についてはこちらの記事をお読みください。
≪ 【Laravel5】Laravel Collective 5.2 Form Model Bindingの落とし穴  |  [baserCMS] baserCMS3.0.7で追加したリクエストの判定法について ≫

Web制作のお問い合わせ

075-744-6842

(平日/土曜 10:00~17:00)

 お問い合わせ