PowerShellで1年度分の週ごとの営業日を整理する

これは何

年度初めで予定を作成する際、縦軸に項目、横軸に年月の表で整理することがよくあると思いますが、このとき、横軸の粒度はどうするでしょうか。

ざっくりでよければ、月単位、月を3分割(10日ごと)、月を4分割(1週間ごと)などにすると思いますが、週単位で作成する場合は、その営業日数も把握しておきたいところです。

祝日は「国民の祝日に関する法律」で定められていますが、春分の日秋分の日は天文学的に定まるため、「何月何日」や「何月の第何曜日」となっておらず、総務省から前年の2月に公表されています。幸いなことにcsvファイルもダウンロード可能です。

www8.cao.go.jp

ということで、この国民の祝日のファイルをダウンロードして、週ごとに営業日数を整理するスクリプトは以下のようになります。

$nendo = 2024

# 未ダウンロードであれば、総務省のWebサイトから国民の祝日のファイルをダウンロード。
# https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html

$url = "https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv"
$localFile = "syukujitsu.csv"

if(-not (Test-Path $localFile)){
    Invoke-WebRequest -Uri $url -OutFile $localFile
}

# 国民の祝日のファイルから対象年度分を配列に抽出。12/29~1/3 も休日扱いに。
# 国民の祝日は年間16日なので、2年分抽出して、16*2未満であればエラー。

$holidays = Import-Csv $localFile -Encoding Default
$holidays_array = @()
$holidays|%{
    $aholiday = [DateTime]$_."国民の祝日・休日月日"
    if($aholiday.Year -eq $nendo -or $aholiday.Year -eq $nendo + 1){
        $holidays_array += $aholiday
    }
}

if($holidays_array.Count -lt 16*2){
    throw "国民の祝日が設定できていません。"
}

$holidays_array += New-Object DateTime $nendo,12,29
$holidays_array += New-Object DateTime $nendo,12,30
$holidays_array += New-Object DateTime $nendo,12,31
$holidays_array += New-Object DateTime ($nendo+1),1,1
$holidays_array += New-Object DateTime ($nendo+1),1,2
$holidays_array += New-Object DateTime ($nendo+1),1,3

# 開始日と終了日を指定して、週ごとの営業日数と合わせて出力。
# 開始と終了の週は特殊処理。

$startDay = New-Object DateTime $nendo,4,1
$lastDay = New-Object DateTime ($nendo+1),3,31

$aDay = $startDay
$eigyo = 0

while($aDay -le $lastDay)
{
    if($aDay.DayOfWeek -ne [DayOfWeek]::Sunday -and $aDay.DayOfWeek -ne [DayOfWeek]::Saturday -and -not $holidays_array.Contains($aDay)){
        $eigyo += 1
    }

    if($aDay.DayOfWeek -eq [DayOfWeek]::Sunday){
        if($aDay.AddDays(-6) -lt $startDay){
            "{0}/{1}~{2}/{3},{4}" -f $startDay.Month, $startDay.Day, $aDay.Month, $aDay.Day, $eigyo
        }else{
            "{0}/{1}~{2}/{3},{4}" -f $aDay.AddDays(-6).Month, $aDay.AddDays(-6).Day, $aDay.Month, $aDay.Day, $eigyo
        }
        $eigyo = 0
    }elseif($aDay -eq $lastDay){
        "{0}/{1}~{2}/{3},{4}" -f $aDay.AddDays(-$aDay.DayOfWeek+1).Month, $aDay.AddDays(-$aDay.DayOfWeek+1).Day, $aDay.Month, $aDay.Day, $eigyo
    }

    $aDay = $aDay.AddDays(1)
}