エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


CakePHP4のFrozenDateで1ヵ月前、先月、今月1日、来月末の日付などを算出する方法

      2024/09/27

CakePHP4のFrozenDateで1ヵ月前、今月1日、来月末などの条件を指定して日付を算出する方法

 
プログラムを作成する際に、下記のような特定の条件に基づいて日付を算出する場合があるかと思います。
・先月の 1日
・来月の月末
・1ヵ月前の日付
 
CakePHP4では「FrozenTime」「FrozenDate」という便利な関数が用意されていますので、これを使用すると簡単に算出することができますので、ご紹介します。
 
 

CakePHPで「FrozenDate」を使用して指定の日付を取得する 3つの方法

 
CakePHPの「FrozenDate」を使用して、例えば「今月の最終日」を取得する記述方法は下記の 3つあります。
 
 
まず最初に、use句で使用する処理を設定します。
(「FrozenDate」と「FrozenTime」の違いについては後述します。)
 

use Cake\I18n\FrozenDate;  // FrozenDate を使用する場合
use Cake\I18n\FrozenTime;  // FrozenTime を使用する場合

 
続けて、Controller内の Action内で下記を記述します。
 

// modify を使用する方法
$today = new FrozenDate();
$lastDay = $today->modify('last day of this month');
$firstDay = $today->modify('first day of this month');

// new FrozenDate を使用する方法
$lastDay = new FrozenDate("last day of this month");

// FrozenDate::parse を使用する方法
$lastDay = FrozenDate::parse("last day of this month");

 
いずれの場合も、結果は下記のようなオブジェクトとして取得できます。
 

Cake\I18n\FrozenDate::__set_state(array(
   'date' => '2024-08-01 00:00:00.000000',
   'timezone_type' => 3,
   'timezone' => 'Asia/Tokyo',
))

 
 

CakePHPで「FrozenDate」を使用して様々な条件を指定する方法

 
先のサンプルでは「last day of this month」と記述して、「今月末の日付」を取得していましたが、「last day of this month」を以下のように書き換えることで、いろいろな条件の日付を取得することができます。
 

// 今月末の日付(「last day」で月末の日付、「this month」で今月)
var_export( FrozenDate::parse("last day of this month") );

// 今月の初日(「first day」で月初の日付)
var_export( FrozenDate::parse("first day of this month") );

// 来月末の日付(「next month」で来月)
var_export( FrozenDate::parse("last day of next month") );

// 先月末の日付(「last month」で先月)
var_export( FrozenDate::parse("last day of last month") );

// 今日から 5日後(前後を「+」「-」で表記もできる)
var_export( FrozenDate::parse("+5 day") );

// 今日から 2ヶ月後(前後を「+」「-」で表記もできる)
var_export( FrozenDate::parse("+2 month") );

// 3年前の 3日後(「-3 year」「+3day」を組み合わせることもできる)
var_export( FrozenDate::parse("-3 year +3day") );

// 3年前(「ago」を付けると過去に)
var_export( FrozenDate::parse("3 year ago") );

// 3年後(「ago」を付けなければ未来に)
var_export( FrozenDate::parse("3 year") );

// 3か月後の月末日
var_export( FrozenDate::parse("last day of 3 month") );

// 5か月前の初日
var_export( FrozenDate::parse("first day of -5 month") );

// 5か月前の初日(「ago」を付けると過去に)
var_export( FrozenDate::parse("first day of 5 month ago") );

// 5か月後の初日(「ago」を付けなければ未来に)
var_export( FrozenDate::parse("first day of 5 month") );

// 「2012-02」の月末日(「2012-02」のように具体的な月の指定もできる)
var_export( FrozenDate::parse("last day of 2012-02") );

// 「2012-02-12」の月末日(「2012-02-12」のように具体的な日付の指定もできる)
var_export( FrozenDate::parse("last day of 2012-02-12") );

// 今年の 2月の月末日(「February」のように月を指定する事もできる。年を指定しない場合は今年の 2月)
var_export( FrozenDate::parse("last day of February") );

// 2020年 2月の月末日(「February」「2020年」を組み合わせることもできる)
var_export( FrozenDate::parse("last day of February 2020") );

 
上記は「FrozenDate::parse()」を使用して取得していますが、「$today->modify()」でも「new FrozenDate()」でも同じように条件を指定することができます。
 
また、上記は取得した値をそのまま画面に表示するために「var_export()」関数を使用しています。
「var_export()」関数については下記に記事を書いていますので、併せて参考にしてください。
「PHPのデバッグで使う print_r、var_dump、var_exportの動作の違い」
 
 
ちなみに、「FrozenDate」は日付を扱う処理ですが、時間まで扱う「FrozenTime」の方を使用する場合は、下記のように時間・分・秒を加減算することができます。
 

var_export( FrozenTime::parse("+5 hour +10 minute +20 second"));

 
 

日時のオブジェクトは「i18nFormat()」を使用して表示

 
取得した日時のオブジェクトですが、文字列として表示する場合は、「i18nFormat()」を使用して表示したいフォーマットに変換します。
 

// 現在日時をオブジェクトとして生成
$today     = new FrozenDate();
$todayTime = new FrozenDate();

// フォーマットを整えて出力
echo $today->i18nFormat('yyyy-MM-dd');
echo $todayTime->i18nFormat('yyyy年MM月dd日 HH:mm:ss');

 
 
ちなみに「$today」に値が入っていない場合はエラーとなりますので、「$today」に値が入っていない可能性がある場合は、下記のように値があるか否かの判定をする処理を追加しておくことをオススメします。
 

echo $today ? $today->i18nFormat('yyyy-MM-dd') : "";

 
 

CakePHPの日付、時間を扱う処理の「FrozenDate」「FrozenTime」

 
CakePHPの日付、時間を扱う処理には「FrozenDate」「FrozenTime」とあります。
 
「FrozenDate」は、年月日を扱う関数です。
「FrozenTime」は、年月日に加え、時分秒を扱う関数です。
 
これを曖昧に使うと結構な問題が発生します。
(実際に私がそれをやってしまっていましたので...)
 
 
では、実際に「FrozenDate」「FrozenTime」を使用して「現在」の情報を取得してみます。
 

$date = new FrozenDate();
var_export($date);

$time = new FrozenTime();
var_export($time);

 
上記のように実行すると、下記の結果が得られます。
 

// FrozenDate の場合
Cake\I18n\FrozenDate::__set_state(array(
   'date' => '2024-09-01 00:00:00.000000',
   'timezone_type' => 3,
   'timezone' => 'Asia/Tokyo',
))

// FrozenTime の場合
Cake\I18n\FrozenTime::__set_state(array(
   'date' => '2024-09-01 12:12:12.345678',
   'timezone_type' => 3,
   'timezone' => 'Asia/Tokyo',
))

 
「FrozenDate」では「時分秒」が「0(値がない)」のに対し、「FrozenTime」ではそれらが存在します。
 
 
この「FrozenDate」と「FrozenTime」の違いをよく理解せずに、「datetime型」の「created」「modified」などの日時の項目に対して SQLの抽出条件に使用すると、想定していない結果が返ってくることがあります。
 
 
例えば、「2024-08-10」~「2024-08-15」を条件に抽出しようとする場合は「FrozenDate」を使う必要があります。
「FrozenTime」を使うと、「時分秒」を持ちますので、実行した時間によって結果が変わってくる、みたいなことが発生してしまいます。
 
お気を付けください...
 
 

PHPでは月末に対して実行する「+1 month」は想定の結果にならない場合がある

 
PHPでは月末日を基準として「+1 month」を実行したとき、想定した結果にならない場合があるようです。
これは、CakePHPの「FrozenDate」に不具合があるのではなく、PHPの処理自体がそういう仕様で動いているためです。
 
具体的には以下の通りです。
 

$today = new FrozenDate("2024-01-31");
var_export($today);
var_export($today->modify('+1 month'));
var_export($today->modify('+2 month'));
var_export($today->modify('+3 month'));
var_export($today->modify('+4 month'));

 
上記を実行すると、以下のようになります。
 

'date' => '2024-01-31 00:00:00.000000'  // today
'date' => '2024-03-02 00:00:00.000000'  // +1 month
'date' => '2024-03-31 00:00:00.000000'  // +2 month
'date' => '2024-05-01 00:00:00.000000'  // +3 month
'date' => '2024-05-31 00:00:00.000000'  // +4 month

 
 
この PHPの日付の処理については、下記に詳細な仕様の説明と、対応策を書いていますので、併せて参考にしてください。
「PHPで月末から1ヶ月後「+1 month」を算出すると想定する日付にならない場合がある」
 
 

CakePHP4の関連記事

CakePHPのpostlinkで生成した削除リンクをクリックしても処理が実行されない対処法
CakePHP4系でJSONレスポンスの処理ではwithStringBodyを使う。3との違い解説
CakePHP4、CakePHP5の「warning: DebugKit is disabling...」の対処方法
MySQL+CakePHPのdate型、datetime型項目は「2999-12-31」までしか扱えない
CakePHP4のFrozenDateで1ヵ月前、先月、今月1日、来月末の日付などを算出する方法
CakePHP4のcake cache clear_allでPermission deniedはパーミッションの変更が必要
CakePHP4のクリエビルダーを使用してOR条件をAND条件でつなぐSQL文を作る方法
CakePHP4のController内でViewテンプレート、レイアウトの変更設定を記述する方法
CakePHP4から外部のデータベースにアクセスする方法解説
CakePHP4の数値項目は「like %10%」の部分一致検索(find select)はできない
 
その他の「CakePHP4」に関する記事一覧
 
 

 - CakePHP 3.x 4.x 5.x

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

CakePHP3でCookieを保存、呼び出し、削除の操作・CakePHP3.7対応
CakePHP3でCookieを保存、呼び出し、削除の操作・CakePHP3.7対応

CakePHP3.7でCookieを保存、取り出し、削除する方法を解説。CakePHP3でのCookieの取り扱いはバージョンごとに変更されるため、環境に合わせた方法を探す必要がある。

CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法
CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法

CakePHP3のブックマークチュートリアルには記載ミスもあり、そのまま動かない個所もある。CakePHP3では namespaceを使うようになったので、classを呼び出すときに¥を追加する必要が!

CakePHP3のバージョンを指定してインストールする詳細な手順を解説
CakePHP3、CakePHP4、CakePHP5のバージョンを指定してインストールする詳細な手順を解説

CakePHP3のバージョンを指定してインストールする方法を詳細解説。CakePHP3のインストールはComposerを使うため設定もほぼ自動で完了。データベースの接続情報を記載すればアプリ開発のベースが整う。

CakePHP3で他のテーブルのマスタテーブルからセレクトボックス(プルダウンリスト)を作る
CakePHP3で他のテーブルのマスタテーブルからセレクトボックス(プルダウンリスト)を作る

他のテーブルのマスタのレコードからプルダウンリストを作成し、選択できるようにするサンプルプログラムと解説。ORMの設定によりデータベースの値を取得し、配列を作成し optionsに与える。

CakePHP3でモデルなしフォームからCSVをアップロードしレコードを更新する方法解説
CakePHP3でモデルなしフォームからCSVをアップロードしレコードを更新する方法解説

CakePHP3でCSVファイルをアップロードしレコードを追加、更新する処理の作成方法の解説。モデルとは直接関連しないフォームからCSVファイルをアップロードするため汎用的に使用可能。

VirtualBoxにCakePHP3を設置。必要なCentOS、Apache、PHP、MySQL、Composerをインストールし設定する。
VirtualBoxにCakePHP3を設置。必要なCentOS、Apache、PHP、MySQL、Composerをインストールし設定する

VirtualBoxにCentOS、Apache、MySQL、PHPをインストールするところから初めてCakePHP3の開発環境を構築する手順を詳細解説。この記事1つで全ての設定が完了する。

CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法
CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法

CakePHPの同一テーブルにある項目の値を比較し条件に合致するレコードを取得する方法を解説。[”項目名”=>”値”]ではなく[”項目名 = 項目名”]と書くところがポイント。

CakePHP5でヘルパーから他のヘルパーを読み込む方法・CakePHP4からの変更点
CakePHP5でヘルパーから他のヘルパーを読み込む方法・CakePHP4からの変更点

CakePHP5のヘルパーで他のヘルパーを読み込む方法を解説。公式の日本語CookbookはCakePHP4のソースのままで間違っているため注意が必要。CakePHP4からの移行の際も同じ点に注意が必要。

CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い
CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い

CakePHP3のシェルスクリプトを作成し、コマンドラインから実行する方法を解説。複数単語をつなげる場合の対応方法がCakePHP2より制限が厳しくなったのでCakePHP3の命名規則の確認が必要だ。

CakePHP 2.3 テーブルの項目を演算した結果を条件として抽出する方法

アソシエーション(連携)している先のテーブルの項目で演算をする場合の考え方と注意点をサンプルソースを用いて説明しています。分かってしまえば簡単です。