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


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

土日は[Carbon](https://carbon.nesbot.com/)でも取得できるけど、祝日までは取得できないから、
ライブラリ[azuyalabs/yasumi](https://github.com/azuyalabs/yasumi)を使ってみます

[azuyalabs/yasumi](https://github.com/azuyalabs/yasumi)
https://azuyalabs.github.io/yasumi/
> Yasumi is an easy PHP Library for calculating national holidays

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

# インストール

composerからインストール

```
composer require azuyalabs/yasumi
```

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

```php
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月**の祝日を取得してみます

```php
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](https://carbon.nesbot.com/)との合わせ技で、
**土日と祝日を除いた平日の日数**を取得してみます。
例として**2018年の5月**、ゴールデンウィークがある月で試してみます。

```php
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](https://carbon.nesbot.com/)との合わせ技で、
**土日と祝日を合わせた日数を取得**してみます。
例として**2018年の5月**、ゴールデンウィークがある月で試してみます。

```php
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](https://carbon.nesbot.com/)はDateTimeクラスをうまく使えば使わずに済みそうですが、
- 祝日に関してはどうしてもこういうライブラリに依存してしまいます。
- 今後もメンテが継続してほしいです（他力本願）
- ちなみに、日本以外の祝日もいけるようですよ

# 参考
- [Yasumi - An easy PHP Library for calculating national holidays](https://azuyalabs.github.io/yasumi/cookbook/)
- [Carbon - A simple PHP API extension for DateTime.](https://carbon.nesbot.com/docs/)