[powershell]営業日を求める

powershellを使って営業日を求めるスクリプトです。
特定の日付の翌営業日に実行する処理を自動で日付判定して実行させるために作りました。

以下の記事を大いに参考にさせていただきました。
https://qiita.com/HOBO0222/items/57d22bf92e59fe30e9db

# 考え方
Get-Dateで取得した日付型のデータは、AddDaysメソッドを使って日付の足し算・引き算が可能です。
```powershell:powershell
#明日の日付を取得する
(Get-Date).AddDays(1)
#昨日の日付を取得する
(Get-Date).AddDays(-1)
```
これを使って、会社が休日となる条件に当てはまる場合にAddDaysでスキップし続ければ営業日を求めることができます。

会社の休日条件にはざっくり以下の3点があると思います。
①法定休日（日曜日など）
②日本の祝日
③その他会社が定める休日

①については、Get-Dateで取得した日付情報には曜日の情報も含まれますので、取得した日の曜日が合致するかどうかを判定すれば大丈夫そうです。
②③については別途指定が必要です。今回は②③を記述した holiday.txt を用意し、取得した日付がこれに含まれるかどうかを判定しています。
※記載する日付形式は揃えてください。
```txt:holiday.txt
2022/12/28
2022/12/29
2022/12/30
2022/12/31
2022/01/01
…
```

# コード
まず、前営業日を求める関数です。
```powershell:powershell
function Get-Predate{
	<#
		.SYNOPSIS
		.\holiday.txtに記載の休業日を参照し、前営業日を取得する
		.PARAMETER string
		string 戻り値の日付形式
	#>
	param($string)
	#初期設定
	$PREDATE     = Get-Date
	$HOLIDAYFILE = Get-Content .\holiday.txt

	###前営業日になるまで永久ループ
	do{
		$PREDATE  = $PREDATE.AddDays(-1)             #一日前にスキップ
		$HOLIDATE = $PREDATE.ToString("yyyy/MM/dd")  #HOLIDAYFILEの要素と比較用に日付形式を整える
		$WEEKDATE = $PREDATE.DayOfWeek               #曜日を取得
	}while($HOLIDAYFILE.Contains($HOLIDATE) -or ($WEEKDATE -eq "Saturday") -or ($WEEKDATE -eq "Sunday"))
	return $PREDATE.ToString($string)
}


```
続いて、翌営業日を求める関数です。

```powershell:powershell
function Get-Nextdate{
	<#
		.SYNOPSIS
		.\holiday.txtに記載の休業日を参照し、翌営業日を取得する
		.PARAMETER string
		string 戻り値の日付形式
	#>
	param($string)
	#初期設定
	$NEXTDATE    = Get-Date
	$HOLIDAYFILE = Get-Content .\holiday.txt

	###前営業日になるまで永久ループ
	do{
		$NEXTDATE = $NEXTDATE.AddDays(1)              #一日後にスキップ
		$HOLIDATE = $NEXTDATE.ToString("yyyy/MM/dd")  #HOLIDAYFILEの要素と比較用に日付形式を整える
		$WEEKDATE = $NEXTDATE.DayOfWeek               #曜日を取得
	}while($HOLIDAYFILE.Contains($HOLIDATE) -or ($WEEKDATE -eq "Saturday") -or ($WEEKDATE -eq "Sunday"))
	return $NEXTDATE.ToString($string)
}

```
処理の違いは、do~whileループの一行目で、.AddDays(-1)とするか.AddDays(1)とするかだけです。



# 解説

```powershell:powershell
	    #初期設定
	    $PREDATE     = Get-Date
	    $HOLIDAYFILE = Get-Content .\holiday.txt
```
PREDATE に今日の日付をいれています。
HOLIDAYFILEには holiday.txt の内容を配列として取得したものを格納しています。

```powershell:powershell do~while内１行目
		$PREDATE  = $PREDATE.AddDays(-1)
```
.AddDays(-1)と引き算しているのは前営業日を求めるためです。
翌営業日を求めたい場合は、これを「.AddDays(1)」とするだけで求めることが出来ます。


```powershell:powershell do~while内2,3行目
		$HOLIDATE = $PREDATE.ToString("yyyy/MM/dd") #HOLIDAYFILEの要素と比較用に日付形式を整える
		$WEEKDATE = $PREDATE.DayOfWeek              #曜日を取得
```
.ToString("yyyy/MM/dd")の引数は、holiday.txtに記載している日付形式と一緒にしてください。
例えば、「2022/1/1」形式で書いている場合は、.ToString("yyyy/M/d")とする必要があります。

```powershell:powershell do~while 条件文
	}while($HOLIDAYFILE.Contains($HOLIDATE) -or ($WEEKDATE -eq "Saturday") -or ($WEEKDATE -eq "Sunday"))
```
比較するPREDATEの日付または曜日が、以下の条件に当てはまる場合に、ループを継続します。
①holiday.txtに記載の日付に含まれる
②土曜日または日曜日である

```powershell:powershell
	return $NEXTDATE.ToString($string)
```
関数の引数として受け取っていた$stringを使って、最終的に求められた前営業日の日付形式を整えて返します。

# 呼び出し方例

```powershell:powershell
	$predate = Get-Predate("M/d")
    write-host $predate
```

# 出力例

```txt:powershell
    12/1
```


# おまけ
引数を増やして基準日を指定させることで、基準日の前営業日または翌営業日を求めることもできます。

```powershell:powershell
function Get-Predate{
	<#
		.SYNOPSIS
		.\holiday.txtに記載の休業日を参照し、基準日の前営業日を取得する
		.PARAMETER date string
        date   基準日
		string 戻り値の日付形式
	#>
	param($date, $string)
	#初期設定
	$PREDATE     = $date
	$HOLIDAYFILE = Get-Content .\holiday.txt

	###前営業日になるまで永久ループ
	do{
		$PREDATE  = $PREDATE.AddDays(-1)             #一日前にスキップ
		$HOLIDATE = $PREDATE.ToString("yyyy/MM/dd")  #HOLIDAYFILEの要素と比較用に日付形式を整える
		$WEEKDATE = $PREDATE.DayOfWeek               #曜日を取得
	}while($HOLIDAYFILE.Contains($HOLIDATE) -or ($WEEKDATE -eq "Saturday") -or ($WEEKDATE -eq "Sunday"))
	return $PREDATE.ToString($string)
}
```

あるいは、与えられた日付が今日の前営業日かどうかを判定させるようにしてもいいかもしれません。

```powershell:powershell
function isPredate{
	<#
		.SYNOPSIS
		.\holiday.txtに記載の休業日を参照し、基準日が今日の前営業日かどうかを返す
		.PARAMETER date
        date   基準日
	#>
	param($date)
	#初期設定
	$PREDATE     = Get-Date
	$HOLIDAYFILE = Get-Content .\holiday.txt

	###前営業日になるまで永久ループ
	do{
		$PREDATE  = $PREDATE.AddDays(-1)             #一日前にスキップ
		$HOLIDATE = $PREDATE.ToString("yyyy/MM/dd")  #HOLIDAYFILEの要素と比較用に日付形式を整える
		$WEEKDATE = $PREDATE.DayOfWeek               #曜日を取得
	}while($HOLIDAYFILE.Contains($HOLIDATE) -or ($WEEKDATE -eq "Saturday") -or ($WEEKDATE -eq "Sunday"))
	return ($PREDATE -eq $date)
}
```