【PHP】日本の祝日を扱うときは「Yasumi」を使ってみてはどうですか


休みたい、次の祝日はいつ頃だ

土日はCarbonでも取得できるけど、祝日までは取得できないから、
ライブラリazuyalabs/yasumiを使ってみます

azuyalabs/yasumi
https://azuyalabs.github.io/yasumi/

Yasumi is an easy PHP Library for calculating national holidays

現時点でのstar数は456です。

インストール

composerからインストール

composer require azuyalabs/yasumi

今年の祝日をすべて取得する

use \Yasumi\Yasumi;

$holidays = Yasumi::create('Japan', '2018', 'ja_JP');

foreach($holidays as $holiday) {
    echo $holiday . ':' . $holiday->getName() . PHP_EOL;
}

以下、tinkerで実行した結果

Psy Shell v0.9.6 (PHP 7.2.5-1+ubuntu18.04.1+deb.sury.org+1 — cli) by Justin Hileman
>>> use \Yasumi\Yasumi
>>> $holidays = Yasumi::create('Japan', '2018', 'ja_JP');
=> Yasumi\Provider\Japan {#2883}
>>> foreach($holidays as $holiday){ echo $holiday . ':' . $holiday->getName() . PHP_EOL; }
2018-01-01:元日
2018-01-08:成人の日
2018-02-11:建国記念の日
2018-02-12:振替休日 (建国記念の日)
2018-03-21:春分の日
2018-04-29:昭和の日
2018-04-30:振替休日 (昭和の日)
2018-05-03:憲法記念日
2018-05-04:みどりの日
2018-05-05:こどもの日
2018-07-16:海の日
2018-08-11:山の日
2018-09-17:敬老の日
2018-09-23:秋分の日
2018-09-24:振替休日 (秋分の日)
2018-10-08:体育の日
2018-11-03:文化の日
2018-11-23:勤労感謝の日
2018-12-23:天皇誕生日
2018-12-24:振替休日 (天皇誕生日)
>>>

今月の祝日を取得する

例としてこの記事を書いている2018年7月の祝日を取得してみます

use \Yasumi\Yasumi;

$holidays = Yasumi::create('Japan', '2018', 'ja_JP');

$holidaysInBetweenDays = $holidays->between(
    \DateTime::createFromFormat('m/d/Y', '07/01/2018'),
    \DateTime::createFromFormat('m/d/Y', '08/01/2018')
);

foreach ($holidaysInBetweenDays as $holiday) {
    echo $holiday . ':' . $holiday->getName() . PHP_EOL; 
}

以下、tinkerで実行した結果

Psy Shell v0.9.6 (PHP 7.2.5-1+ubuntu18.04.1+deb.sury.org+1 — cli) by Justin Hileman
>>> use \Yasumi\Yasumi
>>> $holidays = Yasumi::create('Japan', '2018', 'ja_JP');
=> Yasumi\Provider\Japan {#2883}
>>> $holidaysInBetweenDays = $holidays->between(\DateTime::createFromFormat('m/d/Y', '07/01/2018'),\DateTime::createFromFormat('m/d/Y', '08/01/2018'));
=> Yasumi\Filters\BetweenFilter {#2913
     innerIterator: ArrayIterator {#2912
       +"newYearsDay": Yasumi\Holiday @1514732400 {#2882
         date: 2018-01-01 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"comingOfAgeDay": Yasumi\Holiday @1515337200 {#2876
         date: 2018-01-08 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"nationalFoundationDay": Yasumi\Holiday @1518274800 {#2881
         date: 2018-02-11 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"substituteHoliday:nationalFoundationDay": Yasumi\Holiday @1518361200 {#2892
         date: 2018-02-12 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"vernalEquinoxDay": Yasumi\Holiday @1521558000 {#2874
         date: 2018-03-21 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"showaDay": Yasumi\Holiday @1524927600 {#2880
         date: 2018-04-29 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"substituteHoliday:showaDay": Yasumi\Holiday @1525014000 {#2893
         date: 2018-04-30 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"constitutionMemorialDay": Yasumi\Holiday @1525273200 {#2879
         date: 2018-05-03 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"greeneryDay": Yasumi\Holiday @1525359600 {#2887
         date: 2018-05-04 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"childrensDay": Yasumi\Holiday @1525446000 {#2878
         date: 2018-05-05 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"marineDay": Yasumi\Holiday @1531666800 {#2888
         date: 2018-07-16 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"mountainDay": Yasumi\Holiday @1533913200 {#2877
         date: 2018-08-11 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"respectfortheAgedDay": Yasumi\Holiday @1537110000 {#2889
         date: 2018-09-17 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"autumnalEquinoxDay": Yasumi\Holiday @1537628400 {#2884
         date: 2018-09-23 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"substituteHoliday:autumnalEquinoxDay": Yasumi\Holiday @1537714800 {#2891
         date: 2018-09-24 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"healthandSportsDay": Yasumi\Holiday @1538924400 {#2890
         date: 2018-10-08 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"cultureDay": Yasumi\Holiday @1541170800 {#2871
         date: 2018-11-03 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"laborThanksgivingDay": Yasumi\Holiday @1542898800 {#2869
         date: 2018-11-23 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"emperorsBirthday": Yasumi\Holiday @1545490800 {#2886
         date: 2018-12-23 00:00:00.0 Asia/Tokyo (+09:00),
       },
       +"substituteHoliday:emperorsBirthday": Yasumi\Holiday @1545577200 {#2895
         date: 2018-12-24 00:00:00.0 Asia/Tokyo (+09:00),
       },
     },
   }
>>> foreach ($holidaysInBetweenDays as $holiday) { echo $holiday . ':' . $holiday->getName() . PHP_EOL; }
2018-07-16:海の日
>>>

海の日が取得できました
わーい

【応用編】土日と祝日を除いた平日の日数を取得する

ライブラリに依存してしまいますが、Carbonとの合わせ技で、
土日と祝日を除いた平日の日数を取得してみます。
例として2018年の5月、ゴールデンウィークがある月で試してみます。

use Yasumi\Yasumi;
use Carbon\Carbon;

$startDate = new Carbon('2018-05-01');
$endDate   = new Carbon('2018-06-01');

// 土日を除く平日を取得
$days = (int)$startDate->diffInDaysFiltered(
    function (Carbon $date) {
        return $date->isWeekday();
    }, $endDate
);

// 祝日を取得
$holidays = Yasumi::create('Japan', '2018', 'ja_JP');

$holidaysInBetweenDays = $holidays->between(
    \DateTime::createFromFormat('m/d/Y', $startDate->format('m/d/Y')),
    \DateTime::createFromFormat('m/d/Y', $endDate->format('m/d/Y'))
);

$numberOfHoliday = 0;
foreach ($holidaysInBetweenDays as $holiday) {
    if ((new Carbon($holiday))->isWeekend() === false) {
        $numberOfHoliday++;
    }
}

// さらに祝日の数を引いた平日の日数を取得
$numberOfDay = $days - $numberOfHoliday;

// 出力
var_dump($numberOfDay);

/*
int(21) 
*/

【応用編】土日と祝日を合わせた日数を取得する

同じくCarbonとの合わせ技で、
土日と祝日を合わせた日数を取得してみます。
例として2018年の5月、ゴールデンウィークがある月で試してみます。

use Yasumi\Yasumi;
use Carbon\Carbon;

$startDate = new Carbon('2018-05-01');
$endDate   = new Carbon('2018-06-01');

// 土日を取得
$weekends = (int)$startDate->diffInDaysFiltered(
    function (Carbon $date) {
        return $date->isWeekend();
    }, $endDate
);

// 祝日を取得
$holidays = Yasumi::create('Japan', '2018', 'ja_JP');

$holidaysInBetweenDays = $holidays->between(
    \DateTime::createFromFormat('m/d/Y', $startDate->format('m/d/Y')),
    \DateTime::createFromFormat('m/d/Y', $endDate->format('m/d/Y'))
);

$numberOfHoliday = 0;
foreach ($holidaysInBetweenDays as $holiday) {
    if ((new Carbon($holiday))->isWeekend() === false) {
        $numberOfHoliday++;
    }
}

// 土日の日数に祝日の数を足した日数
$numberOfDay = $weekends + $numberOfHoliday;

// 出力
var_dump($numberOfDay);

/*
int(10) 
*/

おわり

  • CarbonはDateTimeクラスをうまく使えば使わずに済みそうですが、
  • 祝日に関してはどうしてもこういうライブラリに依存してしまいます。
  • 今後もメンテが継続してほしいです(他力本願)
  • ちなみに、日本以外の祝日もいけるようですよ

参考