4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[.NET 8] DateTime.Deconstruct を使ってみる

Posted at

はじめに

今さらですが、.NET8 から DateTime 構造体(DateOnly, TimeOnly, DateTimeOffset にも)に Deconstructメソッドが追加されています。

同等の機能は簡単に実装できるので特に必要性を感じませんが、関連記事をほとんど見つけられなかったので、スクリプトで動作確認した結果をメモ程度に載せておきます。

PowerShell(7.4 以降)

環境は次のとおりです。

PowerShell 7.4.5
PS C:\Users\User> dotnet --version
8.0.401

引数を参照で渡す必要があるため、先に変数を用意します。

PowerShell 7.4
$year = $month = $day = 0
(date).Deconstruct([ref]$year, [ref]$month, [ref]$day) # 今日の日付を分解する
$year, $month, $day
# 2024
# 9
# 25

DateOnly と TimeOnly への分解も同様です。

PowerShell 7.4
$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 は融通が利く(?)ので、とりあえず直球を投げます。

IronPython 3.4 on .NET8
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 に分解されます。
代入した上で、さらに分解してみます。

IronPython 3.4 on .NET8
dateonly, timeonly = DateTime.Now.Deconstruct()
dateonly.Deconstruct()
# (2024, 9, 25)
timeonly.Deconstruct()
# (5, 55)

DateOnly と TimeOnly は、それぞれ (年, 月, 日) と (時, 分) に分解されます。
また、タプルの各要素は int です。

日付を DateOnly で扱えば使い勝手がよさそうです。

引数ありの場合

オーバーロードを使い分ける場合は引数を参照で渡す必要があり、少々手間がかかります。

IronPython 3.4 on .NET8
# (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# です。
左辺から推論して、想定した結果を返します。

F# 8
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

もちろん結果の一部破棄もできます。

F# 8
let _, month, day = DateTime.Now.Deconstruct();;
// val month: int = 9
// val day: int = 25

日付データのコレクション処理でも簡潔に記述できる可能性があります。

F# 8
// とりあえず 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

おわりに

冒頭で「特に必要性を感じない」と書きましたが、意外と便利かもしれない...

4
2
0

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
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?