独自の公休日も考慮した営業日のみを取得する

以前、[祝日をプログラムで判定する - Qiita](https://qiita.com/Uchikoba/items/7174204a9a8eaa2fb79e) で指定された日が祝日かどうかを判定するプログラムを書いたけど、そのときに使った [PEAR::Date_Holidays_Japan](http://pear.php.net/package/Date_Holidays_Japan/) で独自の休日も考慮できるのか不明だった（試す暇もなかった）ので、自作してみた。

```php5:business_days_func.php
<?php
/*
 * @var string[] 土日を除いた祝日および独自の公休日のリスト
 */
$exclusion_days = array(
    '2018-01-01',
    '2018-01-02',
    '2018-01-03',
    '2018-01-04',
    '2018-01-05',
    '2018-01-07',
    '2018-01-08',
    '2018-02-12',
    '2018-03-21',
    '2018-04-30',
    '2018-05-03',
    '2018-05-04',
    '2018-07-16',
    '2018-09-17',
    '2018-08-10',
    '2018-08-13',
    '2018-08-14',
    '2018-08-15',
    '2018-09-17',
    '2018-09-24',
    '2018-10-08',
    '2018-11-23',
    '2018-12-24',
    '2018-12-29',
    '2018-12-30',
    '2018-12-31',
    '2019-01-01',
    '2019-01-02',
    '2019-01-03',
    '2019-01-04',
    '2019-01-14',
);

/**
 * 指定日からｎ営業日前までの日付を配列で取得
 * 
 * Usage:2019-01-07から5営業日前まで遡る
 *  $current_datetime = strtotime('2019-01-07');
 *  $past_business_days = getPastBusinessDays($current_datetime, 5);
 * 
 * @params int $current_datetime 対象としたい日付
 * @params int $seek_num 遡りたい日数
 * @params boolean $is_inclusive_current_day 戻り値に指定日を含む場合はTRUE、含まない場合はFALSE。既定値はFALSE
 * @return int[] $current_datetimeから$seek_num日遡った 平日 のリスト。日付の昇順
 */
function getPastBusinessDays($current_datetime, $seek_num, $is_inclusive_current_day = FALSE) {
    global $exclusion_days;
    
    $result_seek_business_days = array();

    $current_day_index = 0;
    for ($seek_day = $current_datetime; $current_day_index <= $seek_num; $seek_day -= 86400) {
        $result_seek_business_days[$current_day_index] = $seek_day;
        if ((date('w', $seek_day) == 6 || date('w', $seek_day) == 0 || array_search(date('Y-m-d', $seek_day), $exclusion_days) !== FALSE) && $current_day_index != 0) {
            // do nothing
        } else {
            $current_day_index++;
        }
    }

    $result_offset = ($is_inclusive_current_day) ? 0 : 1;    

    return array_reverse(array_slice($result_seek_business_days, $result_offset, $seek_num));
}

/**
 * 指定日からｎ営業日先までの日付を配列で取得
 * 
 * Usage:2019-01-07から5営業日先までの日付を取得
 *  $current_datetime = strtotime('2019-01-07');
 *  $past_business_days = getPastBusinessDays($current_datetime, 5);
 * 
 * @params int $current_datetime 対象としたい日付
 * @params int $seek_num 先取りしたい日数
 * @params boolean $is_inclusive_current_day 戻り値に指定日を含む場合はTRUE、含まない場合はFALSE。既定値はFALSE
 * @return int[] $current_datetimeから$seek_num日後の 平日 のリスト。日付の昇順
 */
function getFutureBusinessDays($current_datetime, $seek_num, $is_inclusive_current_day = FALSE) {
    global $exclusion_days;

    $result_seek_business_days = array();

    $current_day_index = 0;
    for ($seek_day = $current_datetime; $current_day_index <= $seek_num; $seek_day += 86400) {
        $result_seek_business_days[$current_day_index] = $seek_day;
        if ((date('w', $seek_day) == 6 || date('w', $seek_day) == 0 || array_search(date('Y-m-d', $seek_day), $exclusion_days) !== FALSE) && $current_day_index != 0) {
            // do nothing
        } else {
            $current_day_index++;
        }
    }
    
    $result_offset = ($is_inclusive_current_day) ? 0 : 1;    
    
    return array_slice($result_seek_business_days, $result_offset, $seek_num);
}
```

動作確認

```PHP:usage
<?php
$current_datetime = strtotime('2019-01-07');
$past_business_days = getPastBusinessDays($current_datetime, 5);

array_walk_recursive($past_business_days, function (&$val) {
    echo date('Y-m-d', $val) . "\n";
});
```

> 2018-12-21
> 2018-12-25
> 2018-12-26
> 2018-12-27
> 2018-12-28

OKっぽい。