業務で「第1月曜日」や「第3水曜日」等の日付型を扱いたくなったので、PHPでどう書くのか調べてみました。
DateTimeの場合
ドキュメントの相対的な書式に、Datetimeが理解できるフォーマットの一覧があります。
これらを組み合わせることによって自然言語っぽく第n〇曜日を実現できます。
<?php
// 2025年1月の第1月曜日
$dt1 = new DateTime('first Monday of 2025-01');
echo $dt1->format('Y-m-d'); // 2025-01-06
// 今月の第2土曜日
$dt2 = new DateTime('second Saturday of this month');
echo $dt2->format('Y-m-d'); // 2021-07-10
// 来月の第4火曜日
$dt3 = new DateTime('forth Tuesday of next month');
echo $dt3->format('Y-m-d'); 2021-08-24
ちょっと面白い・・・
ちなみに、存在しない第n〇曜日(2021年7月第5月曜日)で試してみると、月初めから数えて5回目の月曜日に当たる翌月の第1月曜日となりました。
<?php
// 2021年7月第5月曜日(存在しない)
$dt4 = new DateTime('fifth Monday of 2021-07');
echo $dt4->format('Y-m-d H:i:s'); // 2021-08-02
Carbonの場合
PHPで日付といえばCarbonですよね。
これはDateTimeのラッパーでLaravel等の人気フレームワークにも組み込まれています。
Composerでインストールできます。
composer require nesbot/carbon
DateTimeのラッパーなのでもちろん上述と同様の方法も使えます。
<?php
require 'vendor/autoload.php';
use Carbon\Carbon;
// 2025年1月の第1月曜日
echo Carbon::createFromDate('first Monday of 2025-01')->format('Y-m-d') // 2025-01-06
// 今月の第2土曜日
echo Carbon::createFromDate('second Saturday of this month')->format('Y-m-d') // 2021-07-10
// 来月の第4火曜日
echo Carbon::createFromDate('first Monday of 2025-01')->format('Y-m-d') // 2021-08-24
// 2021年7月第5月曜日(存在しない)
$dt4 = new DateTime('fifth Monday of 2021-07'); // 2021-08-02
ただ、Carbonにはこのような用途専用のメソッドであるnthOfMonth()
があります。
第n〇曜日を求めたい場合、第一引数にn、第二引数に〇(曜日を表す定数)を与えます。
曜日定数はCarbonに定義されています。
曜日 | 定数 | 値 |
---|---|---|
日曜日 | Carbon::SUNDAY | 0 |
月曜日 | Carbon::MONDAY | 1 |
火曜日 | Carbon::TUESDAY | 2 |
水曜日 | Carbon::WEDNESDAY | 3 |
木曜日 | Carbon::THURSDAY | 4 |
金曜日 | Carbon::FRIDAY | 5 |
土曜日 | Carbon::SATURDAY | 6 |
これらを用いて実行してみてみます。
<?php
require 'vendor/autoload.php';
use Carbon\Carbon;
// 2025年1月の第1月曜日
echo Carbon::createFromDate(2025, 1)->nthOfMonth(1, Carbon::MONDAY)->format('Y-m-d') // 2025-01-06
// 今月の第2土曜日
echo Carbon::now()->nthOfMonth(2, Carbon::TUESDAY)->format('Y-m-d') // 2021-07-10
// 来月の第4火曜日
echo Carbon::now()->addMonth()->nthOfMonth(4, Carbon::TUESDAY)->format('Y-m-d') // 2021-08-24
いい感じですね。
ちなみに存在しない日付の場合は、nthOfMonthの段階でfalseを返してくれます。
require 'vendor/autoload.php';
use Carbon\Carbon;
// 2021年7月第5月曜日(存在しない)
echo Carbon::createFromDate(2021, 7)->nthOfMonth(5, Carbon::MONDAY) // false