PowerShellで日付をISO 8601で出力してみる

PowerShellで日付を出力する事は多々あるかと思いますが。
今回はISO 8601の形式で日付を出力する場合について記載します。

## 本記事で利用している環境

- PowerShell 7.3.2

## 参考ドキュメント

[Get-Date](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7.3)

[Standard date and time format strings/
The round-trip ("O", "o") format specifier](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip)

[Use Culture Information in PowerShell to Format Dates](https://devblogs.microsoft.com/scripting/use-culture-information-in-powershell-to-format-dates/)

[Convert String to DateTime Object in specific timezone with Powershell](https://stackoverflow.com/questions/59883763/convert-string-to-datetime-object-in-specific-timezone-with-powershell)

# Get-Dateコマンドで現在日付をISO 8601で出力する

[Get-Date](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7.3)

`Get-Date`コマンドレットは、オプションを付けずに実行すると現在日付を出力します。


[Standard date and time format strings/
The round-trip ("O", "o") format specifier](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip)

上記、ドキュメントにある通り、`Format`オプションに`o`を指定すると現在日付をISO 8601の形式で出力してくれます

```PowerShell
Get-Date

Get-Date -Format "o"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/ff58188a-f00f-360f-37ad-03cf6b446da5.png)


実行してみると`2023-02-21T22:15:46.9472899+09:00`とオフセットが`+09:00`で出力されている事がわかります。

これは実行環境が下記のように`Tokyo Standard Time`に設定していることに起因します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/1cc44484-6b60-3b68-af31-a28fc6a1569b.png)

# Get-Dateコマンドで指定日付をISO 8601で出力する

```PowerShell
Get-Date "2023/02/21 09:00:00" -Format "o"
```

`Get-Date`コマンドレットでは文字列を引数として渡すことにより、引数で渡した文字列をパースして`[datetime]`を取得する事ができます。

上記のように文字列をパースする場合、`Format "o"` と実行すると下記のように`2023-02-21T09:00:00.0000000`となり、末尾に`+09:00`とオフセットがつきませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/35ad25cf-48a5-d449-3344-146474ca7892.png)

`Get-Date`で現在日付を`-Format "o"`で出力した場合は、端末の設定を見て、`+09:00`となりタイムゾーンが表記されたのに対して。

`Get-Date`に文字列で日付を指定しつつFormat `o`で出力した場合は、タイムゾーンの表記がなくなりました。

日付指定した場合も同様にオフセットが出力されると予想していましたが、そのような実装にはなっていないようです。

色々と試して見ましたが、下記のようにすれば日付指定した場合でも同様にオフセットを出力できました。

```PowerShell
# 一旦、DateTimeOffsetにしてからToStringで出力
([DateTimeOffset](Get-Date "2023/02/21 09:00:00")).ToString("o")

# DateTimeのままToStringで出力するとオフセットはつかない
(Get-Date "2023/02/21 09:00:00").ToString("o")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/86975c0a-b786-0564-1869-d10a633d4cb7.png)

## 任意のタイムゾーンに変換してみる

[TimeZoneInfo.ConvertTimeBySystemTimeZoneId メソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.timezoneinfo.converttimebysystemtimezoneid?view=net-7.0)

.NETでは`TimeZoneInfo`の`ConvertTimeBySystemTimeZoneId`メソッドが用意されており。
これを利用すると変換できます。

```powershell
Get-Date -Format "o"

(([TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetimeoffset]$(Get-Date),"Eastern Standard Time"))).toString("o")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/aa7d411f-95cb-4e26-c9a6-e949e004c4e8.png)

上記例ではローカル時間が`JST`の端末で現在時間を、`EST`に変換しています。

なお、`ConvertTimeBySystemTimeZoneId`メソッドに渡しているID（"Eastern Standard Time"）については下記コマンドレットで一覧を確認する事ができます。

```PowerShell
Get-TimeZone -ListAvailable
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/a907acc8-31c0-e895-63ae-0388d7d1e060.png)

### ConvertTimeBySystemTimeZoneIdについて補足

[TimeZoneInfo.ConvertTimeBySystemTimeZoneId メソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.timezoneinfo.converttimebysystemtimezoneid?view=net-7.0)

色々とためしていて気が付きました。

```powershell
(([TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetimeoffset]$(Get-Date),"Eastern Standard Time"))).toString("o")

(([TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([datetime]$(Get-Date),"Eastern Standard Time"))).toString("o")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/616cf333-f858-d09c-1c90-da9c68df3e1c.png)

上記のように`[datetime]`で渡した場合と、`[datetimeoffset]`で渡した場合で、オフセット表記に違いがありました。

この違いには見た時にすぐに気が付かなかったのでメモ。

## 総評

PowerShellで日付処理は.NETが使えると便利かと思います。