はじめに
今さらですが、.NET8 から DateTime 構造体(DateOnly, TimeOnly, DateTimeOffset にも)に Deconstruct
メソッドが追加されています。
同等の機能は簡単に実装できるので特に必要性を感じませんが、関連記事をほとんど見つけられなかったので、スクリプトで動作確認した結果をメモ程度に載せておきます。
PowerShell(7.4 以降)
環境は次のとおりです。
PowerShell 7.4.5
PS C:\Users\User> dotnet --version
8.0.401
引数を参照で渡す必要があるため、先に変数を用意します。
$year = $month = $day = 0
(date).Deconstruct([ref]$year, [ref]$month, [ref]$day) # 今日の日付を分解する
$year, $month, $day
# 2024
# 9
# 25
DateOnly と TimeOnly への分解も同様です。
$dateonly, $timeonly = [dateonly]::new(1, 1, 1), [timeonly]::new(0)
(date).Deconstruct([ref]$dateonly, [ref]$timeonly)
$dateonly, $timeonly
# Year : 2024
# Month : 9
# Day : 25
# DayOfWeek : Wednesday
# DayOfYear : 269
# DayNumber : 739153
# Hour : 5
# Minute : 34
# Second : 51
# Millisecond : 307
# Microsecond : 908
# Nanosecond : 500
# Ticks : 200913079085
IronPython 3.4 (on .NET8)
環境は次のとおりです。(--roll-forward LatestMajor
オプションが必要です。)
PS C:\Users\User> dotnet --roll-forward LatestMajor "C:\Users\User\IronPython\3.4\net6.0\ipy.dll"
IronPython 3.4.1 (3.4.1.1000)
[.NETCoreApp,Version=v6.0 on .NET 8.0.8 (64-bit)] on win32
引数なしの場合
IronPython は融通が利く(?)ので、とりあえず直球を投げます。
import System
from System import DateTime
DateTime.Now.Deconstruct()
# (<System.DateOnly object at 0x000000000000002B [2024/09/25]>, <System.TimeOnly object at 0x000000000000002C [5:46]>)
DateOnly と TimeOnly に分解されます。
代入した上で、さらに分解してみます。
dateonly, timeonly = DateTime.Now.Deconstruct()
dateonly.Deconstruct()
# (2024, 9, 25)
timeonly.Deconstruct()
# (5, 55)
DateOnly と TimeOnly は、それぞれ (年, 月, 日) と (時, 分) に分解されます。
また、タプルの各要素は int です。
日付を DateOnly で扱えば使い勝手がよさそうです。
引数ありの場合
オーバーロードを使い分ける場合は引数を参照で渡す必要があり、少々手間がかかります。
# (System と DateTime は import 済みとします)
import clr
from System import Int32
year_ref = clr.Reference[Int32]()
month_ref = clr.Reference[Int32]()
day_ref = clr.Reference[Int32]()
DateTime.Now.Deconstruct(year_ref, month_ref, day_ref)
year_ref.Value
# 2024
month_ref.Value
# 9
day_ref.Value
# 25
実用性は乏しいのですが、参考まで。
F# (on .NET8)
環境は次のとおりです。
PS C:\Users\User> dotnet fsi --version
Microsoft (R) F# インタラクティブ バージョン F# 8.0 のための 12.8.400.0
本命の F# です。
左辺から推論して、想定した結果を返します。
open System
let year, month, day = DateTime.Now.Deconstruct();;
// val year: int = 2024
// val month: int = 9
// val day: int = 25
let dateonly, timeonly = DateTime.Now.Deconstruct();;
// val timeonly: TimeOnly = 6:24
// val dateonly: DateOnly = 2024/09/25
もちろん結果の一部破棄もできます。
let _, month, day = DateTime.Now.Deconstruct();;
// val month: int = 9
// val day: int = 25
日付データのコレクション処理でも簡潔に記述できる可能性があります。
// とりあえず DateTime 100日分のシーケンスを用意
let seqDate: DateTime seq =
seq { for d in 0..99 -> DateTime(2024, 9, 1).AddDays(d) };;
// val seqDate: DateTime seq
// 左辺に型を明示しておけば オーバーロードに対応できる
let seqYMD: (int * int * int) seq = seqDate |> Seq.map _.Deconstruct()
printfn "%A" seqYMD;;
// seq [(2024, 9, 1); (2024, 9, 2); (2024, 9, 3); (2024, 9, 4); ...]
// val seqYMD: (int * int * int) seq
let seqDateAndTime: (DateOnly * TimeOnly) seq = seqDate |> Seq.map _.Deconstruct()
printfn "%A" seqDateAndTime;;
// seq
// [(2024/09/01, 0:00); (2024/09/02, 0:00); (2024/09/03, 0:00);
// (2024/09/04, 0:00); ...]
// val seqDateAndTime: (DateOnly * TimeOnly) seq
おわりに
冒頭で「特に必要性を感じない」と書きましたが、意外と便利かもしれない...