LoginSignup
7

More than 1 year has passed since last update.

posted at

updated at

Organization

日本の祝日を判定するPowerShellを書いた件

Advent Calendar 初参加です。
Calendar にかけて、前回書いた記事「日本の祝日を判定するBashスクリプトを書いた件」を PowerShell で焼き直してみました。

日本の祝日情報をどこから貰うか

Bash版同様、内閣府のホームページから持ってきます。
Invoke-WebRequestcurlに相当するコマンドレットですが、PowerShellの入出力はすべて .NET のクラスオブジェクトなので、画面で確認するなら次のようになります。

取得方法
(Invoke-WebRequest https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv).Content
実行結果
国民の祝日・休日月日,国民の祝日・休日名称
1955/1/1,元日
1955/1/15,成人の日
1955/3/21,春分の日
1955/4/29,天皇誕生日
     :
2020/7/24,スポーツの日
2020/8/10,山の日
2020/9/21,敬老の日
2020/9/22,秋分の日
2020/11/3,文化の日
2020/11/23,勤労感謝の日

PowerShellスクリプト

仕様はBash版を踏襲しています。つまり、祝日ファイルをローカルにキャッシュし、古くなったら内閣府のサーバから取り直します。
確実に祝日と言える場合のみ、終了ステータスに 0 がセットされる点も同様です。
Bash版と比べてみると、言語の特徴が見えて面白いかもしれません。

check_holiday.ps1
###############################################################
#   本邦休日判定スクリプト
#   @author  MindWood
#   @param   チェック日付を yyyymmdd で指定。省略すると今日を仮定
#   @return  0       ... 確実に祝日
#            1       ... おそらく平日
#            上記以外 ... エラー
###############################################################

# 引数チェック
Param($DateStr = (Get-Date).ToString('yyyyMMdd'))
try {
    $CheckDate = [DateTime]::ParseExact($DateStr, 'yyyyMMdd', $null)
} catch {
    echo 'Invalid argument'
    exit 255
}
$CachePath = 'C:\tmp'                             # 内閣府提供の祝日ファイルをキャッシュするディレクトリ
$HolidayFile = Join-Path $CachePath holiday.csv   # 祝日登録ファイル名
$Limit = (Get-Date).AddMonths(-3)                 # 3ヶ月以上前は古い祝日登録ファイルとする

# 祝日登録ファイルが無い、もしくは祝日登録ファイルの更新日が古くなった場合、再取得する
if (! (Test-Path $HolidayFile) -or $Limit -gt (Get-ItemProperty $HolidayFile).LastWriteTime) {
    try {
        Invoke-WebRequest https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv -OutFile $HolidayFile
    } catch {
        echo $_.Exception.Message
        exit 250
    }
}

# 祝日として登録されていれば 0 を返却して終了(※祝日情報はyyyy/M/d形式で返る)
if (Select-String -Quiet ((Get-Date $CheckDate).ToString('yyyy/M/d') + ',') $HolidayFile) {
    exit 0
}

# 土日なら 0 を返却して終了
$DayOfWeek = (Get-Date $CheckDate).DayOfWeek
if ($DayOfWeek -in @('Saturday', 'Sunday')) {
    exit 0
}

# 年末年始(12月31日~1月3日)なら 0 を返却して終了
$MMDD = (Get-Date $CheckDate).ToString('MMdd')
if ($MMDD -eq '1231' -or $MMDD -le '0103') {
    exit 0
} 

# 上記いずれでもなければ平日として終了
exit 1

このスクリプトで、2019年12月26日から2020年1月16日までの平日を表示させると、次のようになります。

for ($date = '20191226'; $date -lt '20200116'; $date = [DateTime]::ParseExact($date, 'yyyyMMdd', $null).AddDays(1).ToString('yyyyMMdd')) {
    .\check_holiday.ps1 $date
    if (! $?) {
        echo "$date は恐らく平日です"
    }
}
20191226 は恐らく平日です
20191227 は恐らく平日です
20191230 は恐らく平日です
20200106 は恐らく平日です
20200107 は恐らく平日です
20200108 は恐らく平日です
20200109 は恐らく平日です
20200110 は恐らく平日です
20200114 は恐らく平日です
20200115 は恐らく平日です

なお、PowerShellでも $? で直前のコマンド終了ステータスを取得できますが、成功したか(0:True)失敗したか(0以外:False)のブール値で返るので注意が必要。失敗した理由まで知るには$LastExitCodeを評価すると良いです。

平日に必ず実行させるジョブがある場合、Falseかどうかだけ見れば良いことになります。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
7