1. 導入
Web開発の現場において、予約フォームのプルダウンやカレンダーUI、あるいは日次のバッチ処理などで「特定期間の日付リスト」を作成するケースは頻繁にあります。かつてはmktime()関数を用いたループ処理が一般的でしたが、PHP 5.2以降に導入されたDateTimeクラスを利用することで、より直感的でバグの少ないコードが書けるようになります。本稿では、実務で再利用しやすい「日付生成」のベストプラクティスを解説します。
2. 基礎知識
日付操作を行う上で理解しておくべき重要な概念が「DateTimeオブジェクト」です。従来のmktime()はタイムスタンプ(数値)ベースの操作でしたが、DateTimeクラスは日付をオブジェクトとして管理するため、加算・減算やフォーマット変換が容易です。特に、DateInterval(間隔)クラスと組み合わせることで、「翌日」や「1ヶ月後」といった操作を可読性の高いコードで記述できます。
3. 実装/解決策
日付の一覧を生成する際は、開始日から終了日までをループさせ、各ステップで日付をインクリメントしていく手法が最も汎用的です。このとき、曜日を取得するにはformat(‘w’)メソッドを使用します。これは0(日)から6(土)の数値を返すため、曜日の配列と組み合わせるのが定石です。
4. サンプルプログラム
以下は、指定した年の1年分の日付を曜日付きで生成するサンプルコードです。実務で使いやすいよう、クラス化を想定したシンプルなロジックにしています。
/
function getDateListByYear($year) {
$dateList = [];
$wday = [“日”, “月”, “火”, “水”, “木”, “金”, “土”];
// 開始日をその年の1月1日に設定
$date = new DateTime(“{$year}-01-01”);
// ループ終了条件:翌年の1月1日まで
$endDate = new DateTime(($year + 1) . “-01-01”);
// 1日ずつ加算する間隔を指定
$interval = new DateInterval(‘P1D’);
while ($date < $endDate) {
// 曜日インデックスを取得(0-6)
$w = $wday[$date->format(‘w’)];
// 表示用フォーマットに変換
$dateList[] = $date->format(‘Y/m/d’) . “({$w})”;
// 日付を1日進める
$date->add($interval);
}
return $dateList;
}
// 実行例
$year = 2024;
$list = getDateListByYear($year);
foreach ($list as $day) {
echo $day . PHP_EOL;
}
?>
5. 応用・注意点
タイムゾーンの考慮
実務環境では、サーバーのタイムゾーン設定によって予期せぬ挙動をすることがあります。DateTimeインスタンス生成時には、第二引数にDateTimeZoneオブジェクトを明示的に渡すことを強く推奨します。
パフォーマンスとメモリ
数十年分といった膨大な日数を生成する場合、配列にすべて格納するとメモリを圧迫します。その場合は、リストを返すのではなく、Generator(yield構文)を使用して、必要な時に必要な分だけ日付を生成する設計に切り替えるのが、熟練エンジニアのスマートな解決策です。
バグ回避のヒント
「2月末日」の計算などは、手動で計算すると閏年の考慮漏れが発生しやすい箇所です。DateTimeクラスのaddメソッドやmodifyメソッドはこれらを自動的に処理してくれるため、自作のロジックで日付計算を行うことは避け、標準ライブラリを信頼して活用しましょう。