ここでは.NETにおける日付と時刻に関連するデータ型であるDateTime構造体・DateTimeOffset構造体・TimeSpan構造体と、それらの型を使った日付と時刻の操作について見ていきます。
なお、本文中にあるいくつかのサンプルコードについて、実行環境に設定されているタイムゾーン・言語・書式等によって実行結果・出力内容が変わるものもが存在します。 特に明記していない場合は、日本標準時(UTC+9)・日本語の環境での実行結果となります。
以下この文書では、年月日のみ(date)を表すために日付、時分秒のみ(time)を表すために時刻、日付と時刻の組み合わせ(date and time)を表すために日時、2つの日時間の差を表すために時間間隔の各用語を用います。
日付・時刻・時間間隔と型
まずは.NETで使用出来る日付と時刻を扱う型について大まかに見ていきます。
日付と時刻
.NETでは日時を表す値を扱うデータ型としてDateTime構造体およびがDateTimeOffset構造体が用意されています。 DateTime・DateTimeOffset構造体は特定の日付と時刻を表すだけでなく、日時の加減算や日時同士の大小(前後)関係の比較を行うための機能、ローカル時刻と世界協定時刻(UTC)との変換を行うための機能などが用意されています。
DateTime
DateTime構造体は、日付と時刻をひとまとめにして扱うデータ型ですが、単に日時の値を表すだけではなく、DateTimeでは時刻がローカル時刻とUTCのどちらかを表すのか、時刻の種類を明示することができるようになっていて、日時をローカル時刻もしくは世界協定時刻(UTC)として取り扱うことができるようになっています。
この例で使用しているToLocalTimeメソッドとToUniversalTimeメソッドは、DateTimeの時刻をローカル時刻・UTCの間で変換するためのメソッドです。 ローカル時刻・UTCの変換については個別に解説します。
DateTimeOffset
.NETでは、もうひとつ日時を表すデータ型としてDateTimeOffset構造体も用意されています。 これは.NET Framework 3.5から導入された構造体です。
DateTimeOffsetはDateTimeとよく似た構造体で、DateTimeにオフセット情報(UTCからの時差)を持たせたものに相当します。 つまり、DateTimeOffsetは日付と時刻に加え、オフセット情報をひとまとめにして扱います。 DateTimeにおける時刻の種類(Kindプロパティ)の代わりとして、DateTimeOffsetではオフセット情報(Offsetプロパティ)が存在すると言うこともできます。
これにより、DateTimeではローカルまたはUTCの日時のみしか扱えないのに対して、DateTimeOffsetでは任意のタイムゾーンの日時が扱えるという違いがあります。
DateTimeでは常にローカル時刻もしくはUTCのどちらかに変換して日時を格納するためオフセット値は消失しますが、DateTimeOffsetではオフセット値を個別に格納するようになっているため、オフセット情報を消失することなく日時を格納することが出来ます。
例えば、実行環境が日本標準時に設定されている環境において、東部標準時での時刻をDateTimeに格納しようとする場合を考えます。 この場合DateTimeでは、ローカル時刻である日本標準時か、もしくはUTCのどちらかに変換して格納しなければならないため、DateTimeに格納する際に「時刻は東部標準時のものである」という情報は失われますが、DateTimeOffsetを使えばオフセット値を維持したまま格納することができるため、「時刻は東部標準時である」という情報は維持されます。
ただ、厳密にいえばDateTimeOffsetに格納されるのはオフセット値のみであり、具体的にどのタイムゾーンの日時かといった情報ではありません。 そのため、例えばUTC+9である日本標準時の日時と、同じくUTC+9である韓国標準時の日時はまったく同一の値として扱われる事になります。 タイムゾーンに関するより高度な操作が必要な場合はTimeZoneInfoクラスを使う必要があります。
DateTimeとDateTimeOffsetの違い
オフセット情報を持たせられるかといった違いを除くと、DateTimeとDateTimeOffsetの両者にはほとんど同じメソッド・プロパティが用意されています。 従って、基本的にはDateTimeもDateTimeOffsetも同じように扱うことが出来ます。
扱う日時がローカル時刻のみ、もしくは単一のタイムゾーン内の時刻のみの場合であればDateTimeを使い、オフセット情報を維持する必要がある場合や、異なるタイムゾーンの時刻を扱う場合はDateTimeOffsetを選ぶ、といった使い分けをします。
DateTime・DateTimeOffsetと暦法
DateTime・DateTimeOffsetでは、日時はグレゴリオ暦のものとして扱われます。 そのため、各月の日数、うるう年などはグレゴリオ暦の暦法に従います。
DateTime・DateTimeOffsetは特に指定しない限りグレゴリオ暦で日時を扱いますが、.NETではCalendarクラスを使うことでヘブライ暦・イスラム暦などの暦も扱えるようになっています。
時間間隔 (TimeSpan)
.NETでは、日時を表すDateTime・DateTimeOffsetと合わせて、時間間隔を表すTimeSpan構造体が用意されています。 TimeSpanは、例えば「36時間」や「50ミリ秒」といった時間の長さを一つの型で表すために使います。
時間の長さをint
・double
などの数値型で表そうとした場合、それが秒を表すのか、分を表すのか、といった単位の扱いや変換が煩雑になりがちですが、TimeSpanを使えばそういった煩雑さは解消されます。 TimeSpanでは加減算もサポートされているので、互いに単位の異なる時間間隔の加減算も容易に行うことができます。
DateTime・DateTimeOffsetがある特定の時点を表すものであるのに対して、TimeSpanは二つの時刻間の差を表すものとも言えます。 実際、DateTime・DateTimeOffsetで日時の加減算を行う場合、TimeSpanを使うことが出来るようになっています。
DateTime・DateTimeOffset
ここでは、DateTimeおよびDateTimeOffsetを使った日時の操作について見ていきます。 ほとんどの場合において、DateTimeとDateTimeOffsetは同様に扱うことができます。
現在日時の取得
現在日時を取得するにはNowプロパティを参照します。 Nowプロパティで取得できる現在日時はローカル時刻となります。 UTCでの現在日時を取得したい場合は、UtcNowプロパティを参照します。
時刻が不要で、今日の日付のみを取得したい場合は、Todayプロパティを参照します。 Todayプロパティでは、時刻部分が 0時0分0秒(日付変更直後) の値が返されます。 また、Nowプロパティと同様に返される日時はローカル時刻となります。
なお、DateTimeOffsetにはTodayプロパティは存在しません。 コンストラクタで日付のみを指定してインスタンスを作成する必要があります。 もしくは、DateTimeOffset.Nowプロパティで現在日時を取得した後、Dateプロパティで日付のみを取得すれば今日の日付が得られますが、Dateプロパティで得られる値の型はDateTimeとなります。
二つの時点でNowプロパティの値を取得することで、次の例のように処理の経過時間を計測することも出来ます。
大雑把な経過時間が把握できればよい場合はこの方法で十分ですが、より高い精度で計測したい場合はStopwatchクラスを使います。 経過時間の計測についてはランタイム・システム・プラットフォームの情報 §.経過時間でも解説しています。
DateTime・DateTimeOffset同士での減算を行う場合、結果は単純な数値型ではなくTimeSpan型となります。
最小値・最大値・精度
DateTime・DateTimeOffsetでは、最小で "0001年1月1日 0時0分0秒"、最大で "9999年12月31日 23時59分59秒" までの範囲の日時を扱うことが出来ます。 この最小値・最大値はMinValueフィールドおよびMaxValueフィールドを参照することで取得できます。
なお、DateTimeOffsetのオフセット部分は、最小値が-14時間、最大値が+14時間となっています。
また、DateTime・DateTimeOffsetで扱える日時の精度は100ナノ秒となっています。 Ticksプロパティを参照すると、日時を100ナノ秒単位での値で取得することができます。
コンストラクタでも100ナノ秒単位の値を指定する事ができ、最小値である0001年1月1日 0時0分0秒に指定した値を加えた値がインスタンスの表す日時となります。
日時の要素の取得
DateTime・DateTimeOffsetでは日時を扱える以上、日時から時分秒や年月日・曜日などを個別に扱うことも出来るようになっています。
時分秒の取得
DateTime・DateTimeOffsetが表す日時の時分秒を参照するには、Hour・Minute・Secondの各プロパティを参照します。 Millisecondプロパティで秒の端数(ミリ秒部分)も取得することが出来ます。
TimeOfDayプロパティでは、DateTimeの表す日時のうち、時刻の部分(午前0時ちょうどからの経過時間)のみをTimeSpanで取得することが出来ます。
Ticksプロパティでは、DateTimeの最小値である0001年1月1日 0時0分0秒からの経過時間を100ナノ秒単位で取得することが出来ます。 なお、DateTimeOffsetにはUtcTicksプロパティが用意されていて、UTCに変換した時刻での経過時間を取得できます。 単位はTicksと同じく100ナノ秒です。
年月日・曜日の取得
DateTime・DateTimeOffsetが表す日時の年月日を参照するには、Year・Month・Dayの各プロパティを参照します。 DayOfWeekプロパティで日付の曜日を取得することが出来ます。
日付が1月の場合、Monthプロパティは1
を返します。 C言語のtm構造体など、1月が0
となる言語・処理系とは異なる点に注意してください。
また、DayOfWeekプロパティが返す曜日は数値ではなく、DayOfWeek列挙体の値となります。
DayOfWeek列挙体と曜日、割り当てられている数値の対応は次のとおりです。
DayOfWeek列挙体のメンバー | 曜日 | 値 |
---|---|---|
DayOfWeek.Sunday | 日曜日 |
0
|
DayOfWeek.Monday | 月曜日 |
1
|
DayOfWeek.Tuesday | 火曜日 |
2
|
DayOfWeek.Wednesday | 水曜日 |
3
|
DayOfWeek.Thursday | 木曜日 |
4
|
DayOfWeek.Friday | 金曜日 |
5
|
DayOfWeek.Saturday | 土曜日 |
6
|
Dateプロパティでは、DateTimeの表す日時のうち、日付の部分のみ(時刻を0時0分0秒にした値)をDateTime型で取得することが出来ます。
月名・曜日名・年号の表記
月名を英語や他の外国語表記にしたり、曜日名を日本語表記にしたり、和暦での年号を付記したりするには、書式を指定した文字列化や特定カルチャの指定を行うことで出来ます。
この点について詳しくは日時・文字列の変換と書式で解説します。 以下のページと合わせてご覧ください。
ISO週番号の取得
DateTime・DateTimeOffsetでは、ISO 8601週番号を求めるプロパティやメソッドは直接提供されません。 .NET 5以降ではISOWeekクラスが用意されているため、これを使用してISO 8601週番号やISO 8601週年を求めることができます。
ISOWeekクラスを使った週番号・週年の取得等についてはISO週番号・週暦 §.ISO週番号・週年の取得 (GetWeekOfYear/GetYear)を参照してください。
うるう年・通算日数・夏時間
DateTimeにはうるう年・夏時間かどうかの判定を行うメソッドや、通算日数を求めるプロパティなど、日付を処理する上で便利なメンバーが用意されています。 一方、いくつかのメソッド・プロパティはDateTimeOffsetには用意されていないため、必要に応じてDateTimeに変換してからこれらのメンバーを参照します。
うるう年
ある年がうるう年かどうかを判別するには、DateTimeの静的メソッドであるIsLeapYearメソッドを使うことが出来ます。 このメソッドは静的メソッドで、引数には年を表す数値を指定します。 次の例では、2010年〜2020年の各年について、その年がうるう年かどうかを調べて表示しています。
DateTimeではグレゴリオ暦が使用されるため、IsLeapYearメソッドもグレゴリオ暦の暦法に従ってうるう年かどうかの判定が行われます。 グレゴリオ暦以外でのうるう年の判定を行う必要がある場合は、Calendarクラスを使います。
通算日数
DayOfYearプロパティを参照することで、DateTime・DateTimeOffsetの表す日時がその年の通算何日目かを取得することが出来ます。
DayOfYearプロパティは、うるう年の場合は追加されたうるう日の分も積算します。 次の例では2011年〜2013年の各年の4月1日を表すDateTimeに対して、その年がうるう年かどうかと、その日までの通算日数を表示しています。
月ごとの日数
DaysInMonthメソッドを使うとある年ある月の日数を求めることが出来ます。 このメソッドでは、指定された年がうるう年の場合は追加されたうるう日の分も含めた日数を返します。 次の例では2012年の各月ごとの日数を表示しています。
このメソッドを用いることで、月末の日付を求めることも出来ます。 実装例は月末の日付を求めるで紹介しています。
夏時間
IsDaylightSavingTimeメソッドを使うと、DateTimeの表す日時が夏時間の期間内かどうかを調べることができます。 このメソッドでは、実行環境に設定されているタイムゾーンに夏時間が導入されていなければ、当然どのような日付に対してもfalseを返します。 なお、実行環境のタイムゾーンに関する情報は、TimeZoneクラスおよびTimeZoneInfoクラスで参照することが出来ます。
実行環境に設定されているものとは異なるタイムゾーンにおける日時が夏時間の期間内かどうかを調べるには、TimeZoneInfo.IsDaylightSavingTimeメソッドを使います。
日時の値の変更・加減算
年月日や時分秒を表すHour・Day・Monthなどのプロパティは参照専用で、インスタンスを作成した後は一切変更することができません。 年月日・時分秒の一部分だけを変更したい場合は、変更したい値をコンストラクタに指定して新たにインスタンスを作成する必要があります。
上記の例では、明日同時刻のDateTimeを作成していますが、月末に実行すると例外ArgumentOutOfRangeExceptionがスローされます。 例えば4月30日では、単純に日にちに1足すと4月31日となり、コンストラクタに不正な日付を指定することになるためです。
このように、既存のDateTimeの値を足し引きしてコンストラクタに指定する場合は、月替わりや日付変更・正時を跨ぐような場合に値が範囲外とならないよう考慮する必要があります。 一方、DateTime.AddDays等のメソッドで日時の加減算を行えば、そういった日時の境界を跨ぐ加減算も容易に行えます。
日時の加減算
コンストラクタで具体的な日時を指定する他にも、基準となる日時から加減算して目的の日時のインスタンスを作成することも出来ます。 例えば、AddDaysメソッドを使用するとインスタンスに指定した日数を足した日時を取得することが出来るため、このメソッドを使うと上記の例は次のように書き換えることが出来ます。
AddDaysメソッドでは、月替りを跨ぐような加算も正しく行われます。 例えば上記の例を4月30日に実行すると、4月31日という不正な日付ではなく、5月1日という正しい日付が得られます。
AddDaysメソッドだけでなく、DateTime・DateTimeOffsetには日時に対して加減算を行うためのメソッドがいくつか用意されています。 次の表はそのようなメソッドをまとめたものです。
メソッド | 機能 | 引数の型 |
---|---|---|
DateTime.AddYears
DateTimeOffset.AddYears |
指定された年数を加算した日時を求める | int/Integer |
DateTime.AddMonths
DateTimeOffset.AddMonths |
指定された月数を加算した日時を求める | int/Integer |
DateTime.AddDays
DateTimeOffset.AddDays |
指定された日数を加算した日時を求める | double/Double |
DateTime.AddHours
DateTimeOffset.AddHours |
指定された時間数を加算した日時を求める | double/Double |
DateTime.AddMinutes
DateTimeOffset.AddMinutes |
指定された分数を加算した日時を求める | double/Double |
DateTime.AddSeconds
DateTimeOffset.AddSeconds |
指定された秒数を加算した日時を求める | double/Double |
DateTime.AddMilliseconds
DateTimeOffset.AddMilliseconds |
指定されたミリ秒数を加算した日時を求める | double/Double |
DateTime.AddTicks
DateTimeOffset.AddTicks |
指定されたタイマ刻み数(100ナノ秒単位)を加算した日時を求める | long/Long |
DateTime.Add
DateTimeOffset.Add |
指定された時間間隔を加算した日時を求める | TimeSpan |
DateTime.Subtract
DateTimeOffset.Subtract |
指定された時間間隔を減算した日時を求める | TimeSpan |
これらのメソッドのうちいくつかは引数にdouble
を取るものが用意されているため、1.5日後や8.5時間後といった日時を求めることが出来ます。 正数だけでなく負数も指定することが出来るため、これらのメソッドを使ってある日時から3日前(= -3日後)、5年前(= -5年後)といった日時を求めることも出来ます。
またDateTime・DateTimeOffsetのコンストラクタでは月であれば1〜12、時間であれば0〜23の範囲内の値を指定しなければArgumentOutOfRangeExceptionがスローされますが、Add*メソッドではその範囲外の値も指定出来るため、45日後、26時間後、といった日時を求めることも出来ます。 これを利用して、例えば「1999年12月31日 27時30分」という時刻を「2000年01月01日 03時30分」に正規化するといったこともできます。 当然、Add*メソッドではうるう年での日数の違いも考慮された上で日時が計算されます。
当然ながらこれらのメソッドで日時の加減算を行なっても、その結果として得られるDateTimeのKindおよびDateTimeOffsetのOffsetは加減算を行う前のものと同じものとなります(日時の加減算はDateTime.KindおよびDateTimeOffset.Offsetには影響しません)。
Addメソッド・Subtractメソッドでは引数にTimeSpanを取るため、8時間30分5秒前や1日と8時間後といった日時を一度のメソッド呼び出しで求めることができます。 さらに、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、DateTime・DateTimeOffsetにTimeSpanを加減算するために加算演算子・減算演算子を使うこともできます。 当然、結果はAddメソッド・Subtractメソッドを使う場合と同じです。
AddYearsとうるう年の考慮
うるう年の2月29日を表すDateTime・DateTimeOffsetに対してAddYearsメソッドで年単位の加減算を行う場合は注意が必要です。 うるう年の2月29日から年単位の加減算をした結果、その年もうるう年となる場合は2月29日、そうでない場合は2月28日が返されます(3月1日にはなりません)。
一方、2月28日または3月1日を表すDateTime・DateTimeOffsetに対してAddYearsメソッドを用いる場合は、その年がうるう年となるか否かに関わらず、結果は2月28日または3月1日となります。
うるう年かどうかの判別については§.うるう年を参照してください。
AddMonthsと月ごとの日数の考慮
AddMonthsメソッドで月単位の加減算を行った結果その月の末日を超える場合は、日付の部分はその月の末日となります。 例えば、1月31日から3ヶ月加算した場合、4月31日は4月の末日を超えるため結果は4月30日となります。 同様に、1月31日から1ヶ月加算した場合、結果はうるう年であれば2月28日、そうでなければ2月29日となります。
日時同士の差
DateTime.SubtractおよびDateTimeOffset.Subtractメソッドは、日時に対する減算を行う目的のほかにも、二つの日時同士の減算を行いその時間差を求める目的でも使うことができます。 日時同士の差を求めるため、このメソッドの戻り値は時間間隔を表すTimeSpanとなります。
このメソッドでDateTime同士の差を求める場合、時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として差が求められる点に注意が必要です。 DateTimeに設定されている時刻の種類も考慮して時間差を求めるには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上でSubstractメソッドを呼び出す必要があります。
一方DateTimeOffset同士の場合は、Substractメソッドでの減算時にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Substractメソッドでは内部的に一旦双方の値をUTCに変換した上でその差が求められます。
なお、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、Substractメソッドを呼び出す代わりに減算演算子を使うことも出来ます。 結果はSubstractメソッドを使う場合と同じです。
日時同士の比較
等価性の比較
二つのDateTime・DateTimeOffsetが等しいかどうか(同一の日時を表すかどうか)を調べるにはEqualsメソッドを使うことが出来ます。 このメソッドは、インスタンスメソッド・静的メソッドの二種類が用意されています。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、Equalsメソッドの代わりに等価演算子==
・不等価演算子!=
,<>
を使って等価性の比較を行うことも出来ます。
Equalsメソッド(および等価・不等価演算子)でDateTime同士の比較を行う場合、DateTime同士の減算の場合と同様に時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として比較される点に注意が必要です。 二つのDateTime同士の比較においては、両者のTicksプロパティの値が同じであればDateTimeは等しいものとして扱われます。 そのため、DateTimeに設定されている時刻の種類も考慮して比較するには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上で比較を行う必要があります。
一方DateTimeOffset同士の場合は、Equalsメソッドでの比較の際にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Equalsメソッドでは内部的に一旦双方の値をUTCに変換した上で比較が行われます。 オフセット値も含めて完全に同一の日時かどうかを比較したい場合には、DateTimeOffset.EqualsExactメソッドを使うことが出来ます。
DateTime・DateTimeOffsetはIEquatableインターフェイスを実装しています。 IEquatableインターフェイスとより高度な等価性の比較処理については等価性の定義と比較も合わせてご覧ください。
大小関係の比較
二つのDateTime・DateTimeOffsetの大小関係(=日時の前後関係)を調べるには静的メソッドのCompareメソッド、インスタンスメソッドのCompareToメソッドを使うことが出来ます。 また、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、等価性の比較と同様に比較演算子も使うことが出来ます。 次の表は、DateTime・DateTimeOffsetの大小関係を求めるためのメソッド・演算子の一覧です。
メソッド・演算子 | 動作 |
---|---|
x > y | x が y よりも後の日時の場合に真(true)となる |
x >= y | x が y よりも後、もしくは等しい日時の場合に真(true)となる |
x < y | x が y よりも前の日時の場合に真(true)となる |
x <= y | x が y よりも前、もしくは等しい日時の場合に真(true)となる |
DateTime.Compare(x, y) DateTimeOffset.Compare(x, y) x.Compare(y) x.Compare(y) |
x が y よりも後の日時(x > y)の場合、正の値を返す x と y が同じ日時(x = y)の場合、0を返す x が y よりも前の日時(x < y)の場合、負の値を返す |
Compare・CompareToメソッド(および比較演算子)でDateTime同士の比較を行う場合、DateTime同士の減算の場合と同様に時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として比較される点に注意が必要です。 二つのDateTime同士の比較結果は、両者のTicksプロパティの値の大小を比較したものと同じとなります。 DateTimeに設定されている時刻の種類も考慮して比較するには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上で比較を行う必要があります。
一方DateTimeOffset同士の場合は、Compare・CompareToメソッドでの比較の際にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Compare・CompareToメソッドでは内部的に一旦双方の値をUTCに変換した上で比較が行われます。
DateTime・DateTimeOffsetはIComparableインターフェイスを実装しています。 IComparableインターフェイスとより高度な大小関係の比較処理については大小関係の定義と比較もご覧ください。
DateTime・DateTimeOffsetとソートについては基本型のソートと昇順・降順でのソートおよび基本型とデフォルトのソート順 §.日付型をご覧ください。
日付のみ・時刻のみの比較
DateTime・DateTimeOffsetの日付のみ・時刻のみを比較するメソッドは用意されていませんが、Dateプロパティで日付のみ、TimeOfDayプロパティで時刻のみを取得できるため、これを使って比較することが出来ます。
なお、DateTimeの時刻の種類(Kindプロパティの値)はDateTime.Dateプロパティが返す値には影響しませんが、DateTimeOffset.DateプロパティはDateTimeOffsetに設定されているオフセット値を加算した上での日付を返す点に注意が必要です。
Dateプロパティとは異なり、DateTime.TimeOfDayプロパティおよびDateTimeOffset.TimeOfDayプロパティが返す値は、どちらも時刻の種類(Kindプロパティ)・オフセット値(Offsetプロパティ)の影響を受けず、時刻部分の値がそのままの値で返されます。 なお、TimeOfDayプロパティはTimeSpan型で時刻を返すため、メソッドを使って比較する場合はDateTime.CompareではなくTimeSpan.Compareを使います(TimeSpan.Compareのかわりに比較演算子を使って比較することもできます)。
日付のみ・時刻のみのソート
Array.SortメソッドなどでDateTime・DateTimeOffsetをソートする場合、デフォルトでは日時の小さい順(古い順)にソートされます。 日付を無視して時刻のみの大小関係でソートしたい場合は、次のようにTimeOfDayプロパティの値を比較するメソッドを用意してそれをSortメソッドに渡すようにします。
TimeOfDayプロパティのかわりにDateTime.Dateプロパティ・DateTimeOffset.Dateプロパティを比較するようにすれば、日付のみを比較してソートするようにすることもできます。
ソートについてより詳しくは、基本型のソートと昇順・降順でのソートおよび複合型のソート・複数キーでのソートなどをご覧ください。
他のフォーマットとの相互変換
DateTime・DateTimeOffsetには日時を他の形式、例えば整数型や実数型の値などで表したものに変換するためのメソッドが用意されています。 以下のメソッドはそのようなメソッドの一覧です。
変換を行うためのメソッド | データ形式 | 解説 |
---|---|---|
DateTimeOffset.ToUnixTimeSeconds
DateTimeOffset.FromUnixTimeSeconds DateTimeOffset.ToUnixTimeMilliseconds DateTimeOffset.FromUnixTimeMilliseconds |
UNIX時間(UNIXタイムスタンプ)形式 64ビットの整数値 (long型) |
解説へ |
DateTime.ToFileTime
DateTime.FromFileTime DateTimeOffset.ToFileTime DateTimeOffset.FromFileTime |
Windowsファイルタイムスタンプ形式 64ビットの整数値 (long型) |
解説へ |
DateTime.ToBinary
DateTime.FromBinary |
DateTimeのバイナリ表現形式 64ビットのバイナリ値 (long型) |
解説へ |
DateTime.ToOADate
DateTime.FromOADate |
OLEオートーメーションの日時形式 64ビットの浮動小数点値 (double型) |
解説へ |
これらのメソッドを使うことで、日時を他のフォーマットへ変換することができます。 例えばBinaryReaderクラス・BinaryWriterクラスを使ってバイナリ形式で日時の読み書きを行う場合や、文字列以外の数値形式で日時を保存しておきたいといった目的でもこれらのメソッドを使うことができます。
なお、文字列に変換するにはToStringメソッド、文字列からDateTime・DateTimeOffsetに変換するにはParseメソッドを使うことができます。 文字列との相互変換については日時・文字列の変換と書式で詳しく解説します。
他にもConvertクラスを使った変換も行えますがここでは省略します。 詳しくは基本型の型変換を参照してください。
ToUnixTimeSeconds/FromUnixTimeSeconds
DateTimeOffset.ToUnixTimeSeconds・FromUnixTimeSecondsメソッドは、日時の値をUNIX時間(UNIXタイムスタンプ)として使われるlong型(64ビット)の値に変換します。
UNIX時間はUTCでの時刻と定義されているため、ToUnixTimeSecondsではUTCに変換された上での値が返されます。 また、FromUnixTimeSecondsメソッドでこの値を変換すると、Offsetプロパティが+00:00
のDateTimeOffsetが返されます。 UNIX時間からDateTimeOffsetに変換した値を、さらにローカル時間として取得したい場合はToLocalTimeメソッドを使用することができます。
ToUnixTimeSeconds/FromUnixTimeSecondsでは、unix epoch(UTCでの1970年01月01日 午前00時00分00秒)からの経過秒数をUNIX時間とした変換を行います。 unix epochからの経過ミリ秒数(ミリ秒単位の精度)で変換を行いたい場合は、ToUnixTimeMilliseconds/FromUnixTimeMillisecondsメソッドを使用することができます。
UNIX時間で表現できる最小(最古)の日時は1970年01月01日 00:00:00(UTC)でありDateTimeで扱える範囲よりも狭いため、その範囲を越える値を変換しようとした場合はArgumentOutOfRangeExceptionがスローされます。 一方このメソッドは64ビットのUNIX時間を扱えるため、32ビットのUNIX時間の上限である2038年以降の日時も変換することができます。
DateTimeにはUNIX時間との相互変換を行うメソッドは用意されていません。 また、ここで挙げたUNIX時間との相互変換を行うメソッドは.NET Framework 4.6以降でサポートされているため、それより前のバージョンでは使用することはできません。 UNIX時間との相互変換、特にDateTimeを使って実装する方法についてはUNIX時間をDateTime型に変換するを参照してください。
UnixEpochフィールドを参照することにより、unix epochをDateTimeOffsetまたはDateTimeの値で取得することができます。 どちらもunix epochの日時である1970年01月01日 午前00時00分00秒(UTC)の値を返します。 つまり、DateTimeOffsetではOffsetプロパティが00:00
、DateTimeではKindプロパティがDateTimeKind.Utc
の値を返します。 UnixEpochフィールドは、ある日時がunix epoch以前かどうかを比較するといった場合に用いることができます。
DateTimeOffset/DateTime.UnixEpochフィールドは、NET Standard 2.1/.NET Core 2.1以降で使用することができます。
ToFileTime/FromFileTime
ToFileTime・FromFileTimeメソッドは、日時の値をWindowsのファイルタイムスタンプで使われるlong型(64ビット)の値に変換します。
タイムスタンプはUTCでの時刻とされているため、ToFileTimeメソッドではUTCに変換された上での値が返されます。 FromFileTimeメソッドでこの値を変換すると、UTCからローカル時刻に変換された(KindプロパティがDateTimeKind.Localの)DateTimeが返されます。 一方、FromFileTimeUtcメソッドで変換すると、UTC(KindプロパティがDateTimeKind.Utc)のDateTimeが返されます。
DateTimeOffset.FromFileTimeメソッドでは、返されるDateTimeOffsetのOffsetプロパティには常にローカル時刻のオフセットが設定されます。
なお、File.SetLastWriteTimeなどFileクラスのタイムスタンプを設定・取得を行うメソッドでは、引数の型がDateTimeとなっています。 そのため、これらのメソッドを使ってタイムスタンプを変更する場合は、わざわざToFileTime・FromFileTimeメソッドを使って値の変換を必要はありません。
ファイルタイムスタンプで表現できる最小(最古)の日時は1601年01月01日 00:00:00(UTC)でありDateTimeで扱える範囲よりも狭いため、その範囲を越える値を変換しようとした場合はArgumentOutOfRangeExceptionがスローされます。
ToBinary/FromBinary
ToBinary・FromBinaryメソッドは、日時の値をlong型(64ビット)の値に変換します。 このメソッドでは、DateTime.TicksプロパティおよびDateTime.Kindプロパティの値を64ビットのバイナリ値として格納したフォーマットが用いられます。 そのため、日時をバイナリデータとして保存・復元したい場合にはこのメソッドを使うことが出来ます。
DateTimeOffsetにはToBinary・FromBinaryメソッドは用意されていません。 DateTimeOffsetのバイナリ表現が必要な場合は、DateTimeOffset.TicksプロパティおよびDateTimeOffset.Offsetプロパティの値をそれぞれ変換・復元します。
ローカル時刻(KindプロパティがDateTimeKind.Local)のDateTimeをToBinaryメソッドで変換し、その値を変換時とは異なるタイムゾーンの環境で復元する場合、復元する環境のタイムゾーンでのローカル時刻として復元される点に注意が必要です。 これを避けるには、あらかじめ日時をUTCに変換しておく必要があります。
ToOADate/FromOADate
ToOADate・FromOADateメソッドは、日時の値をOLEオートメーション日時(double型・64ビット)の値に変換します。 このフォーマットでは時刻の種類は無視され、日時のみが変換されるという点に注意が必要です。 その他フォーマットの詳細などはToOADateメソッドのドキュメントを参照してください。
OLEオートメーション形式で表現できる最小(最古)の日時は0100年01月01日 00:00:00でありDateTimeで扱える範囲よりも狭いため、その範囲を越える値を変換しようとした場合はOverflowExceptionがスローされます。 (ArgumentOutOfRangeExceptionがスローされるToFileTimeメソッドとはスローされる例外が異なる点に注意してください)
アンマネージ呼び出し
DateTimeおよびDateTimeOffsetはアンマネージ呼び出しに使用することはできません。 Marshal.SizeOfメソッドによるサイズの取得や、Marshal.PtrToStructureメソッドによるポインタからの変換なども、例外エラーがスローされ、失敗します。
アンマネージ呼び出しで日時の値を扱いたい場合は、DateTime・DateTimeOffsetをToFileTimeやToBinaryなどのメソッドで変換したり、Ticksプロパティなどの値を用いたりするなど、値を別のフォーマットに変換する必要があります。
TimeSpan
TimeSpan構造体は時間間隔、つまり時間の長さを扱うための型です。 ここでは、TimeSpanの機能と使い方について見ていきます。
インスタンスの作成
コンストラクタ
TimeSpanのコンストラクタでは、時分秒に負の値を指定したり、36時間90分といった値を指定することができます。 負数や大きな値を指定した場合でも、TimeSpanの最大・最小値を越えない限り例外はスローされません。 時間に負の値・分に正の値といった指定もすることが出来ます。 時分秒単位以外にも、DateTime・DateTimeOffsetの精度と同じ単位であるタイマ刻み数(=100ナノ秒)単位の値を指定することも出来ます。
FromXXXメソッド
TimeSpanでは、次のようなメソッドを使うことにより、時間間隔の単位を指定してインスタンスを生成することも出来ます。 FromTicks以外はdouble
型の値を指定できるため、「1.5日」や「9.5時間」といった時間間隔の指定も可能です。
メソッド | 機能 |
---|---|
TimeSpan.FromDays | 日数を指定してTimeSpanを作成する |
TimeSpan.FromHours | 時間数を指定してTimeSpanを作成する |
TimeSpan.FromMinutes | 分数を指定してTimeSpanを作成する |
TimeSpan.FromSeconds | 秒数を指定してTimeSpanを作成する |
TimeSpan.FromMilliseconds | ミリ秒数を指定してTimeSpanを作成する |
TimeSpan.FromTicks | タイマ刻み数(100ナノ秒単位)を指定してTimeSpanを作成する |
合計時間の取得
TimeSpanの表す時間間隔を日数・秒数などに換算した値が必要な場合は、Total*プロパティを参照します。 取得したい数値の単位に応じて、次のプロパティを参照することが出来ます。 これらのプロパティで得られる値はいずれもdouble
です。
プロパティ | 取得できる値 |
---|---|
TimeSpan.TotalDays | TimeSpanの表す時間の長さを日数に換算した値を取得する |
TimeSpan.TotalHours | TimeSpanの表す時間の長さを時間数に換算した値を取得する |
TimeSpan.TotalMinutes | TimeSpanの表す時間の長さを分数に換算した値を取得する |
TimeSpan.TotalSeconds | TimeSpanの表す時間の長さを秒数に換算した値を取得する |
TimeSpan.TotalMilliseconds | TimeSpanの表す時間の長さをミリ秒数に換算した値を取得する |
90分間の時間間隔を表すTimeSpanから1時間と30分という値を得たい場合のように、時間単位ごとに正規化された値を取得したい場合にはHours・Minutesなどのプロパティを参照します。
単位部分の取得
TimeSpanの表す時間間隔の日部分・秒部分の値が必要な場合は、次のプロパティを参照します。 これらのプロパティで得られる値はいずれも端数なしの正規化された整数値で、例えばHoursなら常に0
〜23
の範囲、Minutes・Secondsなら0
〜59
の範囲で値が得られます。
プロパティ | 取得できる値 |
---|---|
TimeSpan.Days | TimeSpanの表す時間の長さの日部分を取得する |
TimeSpan.Hours | TimeSpanの表す時間の長さの時間部分を取得する |
TimeSpan.Minutes | TimeSpanの表す時間の長さの分部分を取得する |
TimeSpan.Seconds | TimeSpanの表す時間の長さの秒部分を取得する |
TimeSpan.Milliseconds | TimeSpanの表す時間の長さのミリ秒部分を取得する |
1時間30分間の時間間隔を表すTimeSpanから1.5時間あるいは90分という値を得たい場合のように、特定単位に変換された合計時間を取得したい場合にはTotalHours・TotalMinutesなどのプロパティを参照します。
最小値・最大値・精度
TimeSpanでは、±Int64.MaxValue×100ナノ秒、おおよそ±10,675,199日の範囲の日時を扱うことが出来ます。 この最小値・最大値はMinValueフィールドおよびMaxValueフィールドを参照することで取得できます。 また、Zeroフィールドを参照することで長さ0の時間間隔を取得することも出来ます。
TimeSpanで扱える時間間隔の精度(タイマ刻み数)は、DateTime・DateTimeOffsetと同じく100ナノ秒となっています。 Ticksプロパティを参照すると、時間間隔を100ナノ秒単位での値で取得することが出来ます。
1時間あたりや1秒あたりのタイマ刻み数を取得する定数として、TicksPerHourフィールドやTicksPerSecondフィールドなどが用意されています。
加減算
TimeSpanでは、TimeSpan同士の加減算を行うことが出来るようになっています。 Addメソッドで加算、Subtractメソッドで減算が行えます。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに加算演算子・減算演算子を使うことも出来ます。
DateTime・DateTimeOffsetに対してTimeSpanを加減算することで、ある日時から一定時間経過した/遡った日時を求めることができます。
DateTime・DateTimeOffsetに対しては、DateTime.Add/Subtractなどのメソッドを使って加減算をすることもできます。
絶対値・符号反転
DurationメソッドでTimeSpanが表す時間の長さ、つまり符号を取り除いた絶対値を取得することができます。 Durationはプロパティではなくメソッドとなっています。
NegateメソッドでTimeSpanが表す時間の前後を逆転した値、つまり符号を反転した値を取得することができます。
乗除算
.NET Standard 2.1/.NET Core 2.0以降のTimeSpanでは、TimeSpanに対してdouble
の値との乗除算を行うことが出来るようになっています。 Multiplyメソッドで乗算、Divideメソッドで除算が行えます。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに乗算演算子・除算演算子を使うことも出来ます。
これらのメソッドが使えない環境では、TimeSpan.TotalSecondsなどのプロパティで一旦数値に変換してから乗除算を行い、その後TimeSpan.FromSecondsなどのメソッドで再びTimeSpanに戻す、といった手順をとることにより乗除算を行うことができます。
等価性・大小関係の比較
TimeSpanでは、二つのTimeSpanの値が同じかどうか、その等価性の比較を行うメソッドとしてEqualsメソッドが用意されています。 また、二つのTimeSpanのどちらが大きいか、その大小関係の比較を行うメソッドとしてCompareメソッド・CompareToメソッドが用意されています。 これらのメソッドはIEquatableインターフェイス・IComparableインターフェイスのメソッドとして提供されます。 これらのメソッド・インターフェイスについての詳細は等価性の定義と比較および大小関係の定義と比較をご覧ください。
これらのメソッドを使う他にも、等価演算子(==
)・不等価演算子(!=
)・比較演算子(<
, >
)を使うことでTimeSpan同士の比較をすることも出来ます。
ソート
TimeSpanはIComparableインターフェイスによって大小関係が定義されているため、ソートすることができます。 TimeSpanでは、負から正の方向にTimeSpanの表す時間間隔の短い順(Ticksプロパティの値の小さい順)でソートされます。
ソートについて詳しくは基本型のソートと昇順・降順でのソートをご覧ください。
文字列への/からの変換
ToStringメソッドを用いることで、TimeSpanの表す時間間隔を文字列形式に変換することができます。 さらに、.NET Framework 4からは書式を指定して文字列化することが可能になっています。 これにより値をゼロ埋めしたり、時分秒などの区切り文字を変更して文字列化することができます。
TimeSpanに対して指定可能な書式については、書式指定子 §.時間間隔の書式指定子および書式指定子 §.時間間隔のカスタム書式指定子をご覧ください。
文字列からTimeSpanに変換するには、Parseメソッド・TryParseメソッドを使うことが出来ます。 また、厳密に書式を指定して文字列からTimeSpanへ変換するには、ParseExactメソッド・TryParseExactメソッドを使うことが出来ます。 なお、これらのメソッドはいずれも.NET Framework 4から使用可能になっています。
ToStringメソッドおよびParse*メソッドでは、現在のカルチャの影響を受けるもの(ローカライズされる書式)が存在します。 これらのメソッドと文字列化に関する詳細な動作については日時・文字列の変換と書式でも解説しているので、あわせてご覧ください。