ここでは.NETにおける日付と時刻に関連するデータ型であるDateTime構造体・DateTimeOffset構造体・TimeSpan構造体と、それらの型を使った日付と時刻の操作について見ていきます。

なお、本文中にあるいくつかのサンプルコードについて、実行環境に設定されているタイムゾーン・言語・書式等によって実行結果・出力内容が変わるものもが存在します。 特に明記していない場合は、日本標準時(UTC+9)・日本語の環境での実行結果となります。

以下この文書では、年月日のみ(date)を表すために日付、時分秒のみ(time)を表すために時刻、日付と時刻の組み合わせ(date and time)を表すために日時、2つの日時間の差を表すために時間間隔の各用語を用います。

日付・時刻・時間間隔と型

まずは.NETで使用出来る日付と時刻を扱う型について大まかに見ていきます。

日付と時刻

.NETでは日時を表す値を扱うデータ型としてDateTime構造体およびがDateTimeOffset構造体が用意されています。 DateTime・DateTimeOffset構造体は特定の日付と時刻を表すだけでなく、日時の加減算日時同士の大小(前後)関係の比較を行うための機能、ローカル時刻と世界協定時刻(UTC)との変換を行うための機能などが用意されています。

DateTime

DateTime構造体は、日付と時刻をひとまとめにして扱うデータ型ですが、単に日時の値を表すだけではなく、DateTimeでは時刻がローカル時刻とUTCのどちらかを表すのか、時刻の種類を明示することができるようになっていて、日時をローカル時刻もしくは世界協定時刻(UTC)として取り扱うことができるようになっています。

DateTime構造体
using System;

class Sample {
  static void Main()
  {
    // 2013年4月1日 午後3時0分30秒
    var a = new DateTime(2013, 4, 1, 15, 0, 30);

    // 2013年4月1日 午後3時0分30秒 (ローカル時刻)
    var b = new DateTime(2013, 4, 1, 15, 0, 30, DateTimeKind.Local);

    // 上の日時を世界協定時間に変換
    var c = b.ToUniversalTime();

    // 2013年4月1日 午後3時0分30秒 (世界協定時刻・UTC)
    var d = new DateTime(2013, 4, 1, 15, 0, 30, DateTimeKind.Utc);

    // 上の日時をローカル時刻に変換
    var e = d.ToLocalTime();
  }
}
DateTime構造体
Imports System

Class Sample
  Shared Sub Main()
    ' 2013年4月1日 午後3時0分30秒
    Dim a As New DateTime(2013, 4, 1, 15, 0, 30)

    ' 2013年4月1日 午後3時0分30秒 (ローカル時刻)
    Dim b As New DateTime(2013, 4, 1, 15, 0, 30, DateTimeKind.Local)

    ' 上の日時を世界協定時間に変換
    Dim c As DateTime = b.ToUniversalTime()

    ' 2013年4月1日 午後3時0分30秒 (世界協定時刻・UTC)
    Dim d As New DateTime(2013, 4, 1, 15, 0, 30, DateTimeKind.Utc)

    ' 上の日時をローカル時刻に変換
    Dim e = d.ToLocalTime()
  End Sub
End Class

この例で使用しているToLocalTimeメソッドToUniversalTimeメソッドは、DateTimeの時刻をローカル時刻・UTCの間で変換するためのメソッドです。 ローカル時刻・UTCの変換については個別に解説します。

DateTimeOffset

.NETでは、もうひとつ日時を表すデータ型としてDateTimeOffset構造体も用意されています。 これは.NET Framework 3.5から導入された構造体です。

DateTimeOffsetはDateTimeとよく似た構造体で、DateTimeにオフセット情報(UTCからの時差)を持たせたものに相当します。 つまり、DateTimeOffsetは日付と時刻に加え、オフセット情報をひとまとめにして扱います。 DateTimeにおける時刻の種類(Kindプロパティ)の代わりとして、DateTimeOffsetではオフセット情報(Offsetプロパティ)が存在すると言うこともできます。

これにより、DateTimeではローカルまたはUTCの日時のみしか扱えないのに対して、DateTimeOffsetでは任意のタイムゾーンの日時が扱えるという違いがあります。

DateTimeOffset構造体
using System;

class Sample {
  static void Main()
  {
    // 2013年4月1日 午後3時0分30秒 (ローカル時刻)
    var a = new DateTime(2013, 4, 1, 15, 0, 30);

    // 2013年4月1日 午後3時0分30秒 (UTC)
    var b = new DateTimeOffset(2013, 4, 1, 15, 0, 30, TimeSpan.Zero);

    // 2013年4月1日 午後3時0分30秒 (UTC+9)
    var c = new DateTimeOffset(2013, 4, 1, 15, 0, 30, new TimeSpan(9, 0, 0));

    // 2013年4月1日 午後3時0分30秒 (UTC-5)
    var d = new DateTimeOffset(a, new TimeSpan(-5, 0, 0));
  }
}
DateTimeOffset構造体
Imports System

Class Sample
  Shared Sub Main()
    ' 2013年4月1日 午後3時0分30秒 (ローカル時刻)
    Dim a As New DateTime(2013, 4, 1, 15, 0, 30)

    ' 2013年4月1日 午後3時0分30秒 (UTC)
    Dim b As New DateTimeOffset(2013, 4, 1, 15, 0, 30, TimeSpan.Zero)

    ' 2013年4月1日 午後3時0分30秒 (UTC+9)
    Dim c As New DateTimeOffset(2013, 4, 1, 15, 0, 30, New TimeSpan(9, 0, 0))

    ' 2013年4月1日 午後3時0分30秒 (UTC-5)
    Dim d As New DateTimeOffset(a, New TimeSpan(-5, 0, 0))
  End Sub
End Class

DateTimeでは常にローカル時刻もしくはUTCのどちらかに変換して日時を格納するためオフセット値は消失しますが、DateTimeOffsetではオフセット値を個別に格納するようになっているため、オフセット情報を消失することなく日時を格納することが出来ます。

例えば、実行環境が日本標準時に設定されている環境において、東部標準時での時刻をDateTimeに格納しようとする場合を考えます。 この場合DateTimeでは、ローカル時刻である日本標準時か、もしくはUTCのどちらかに変換して格納しなければならないため、DateTimeに格納する際に「時刻は東部標準時のものである」という情報は失われますが、DateTimeOffsetを使えばオフセット値を維持したまま格納することができるため、「時刻は東部標準時である」という情報は維持されます。

DateTimeではオフセット値は保存されないがDateTimeOffsetでは保存される
using System;

class Sample {
  static void Main()
  {
    // ESTでの時刻を表す文字列 (オフセット値を含む日時)
    var dtm = "2013-04-01T15:00:30-05:00";

    // 文字列からDateTime・DateTimeOffsetに変換
    var a = DateTime.Parse(dtm);
    var b = DateTimeOffset.Parse(dtm);

    Console.WriteLine(a);
    Console.WriteLine(b);
  }
}
DateTimeではオフセット値は保存されないがDateTimeOffsetでは保存される
Imports System

Class Sample
  Shared Sub Main()
    ' ESTでの時刻を表す文字列 (オフセット値を含む日時)
    Dim dtm As String = "2013-04-01T15:00:30-05:00"

    ' 文字列からDateTime・DateTimeOffsetに変換
    Dim a As DateTime = DateTime.Parse(dtm)
    Dim b As DateTimeOffset = DateTimeOffset.Parse(dtm)

    Console.WriteLine(a)
    Console.WriteLine(b)
  End Sub
End Class
実行結果
2013/04/02 5:00:30
2013/04/01 15:00:30 -05:00

ただ、厳密にいえば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ミリ秒」といった時間の長さを一つの型で表すために使います。

時間の長さをintdoubleなどの数値型で表そうとした場合、それが秒を表すのか、分を表すのか、といった単位の扱いや変換が煩雑になりがちですが、TimeSpanを使えばそういった煩雑さは解消されます。 TimeSpanでは加減算もサポートされているので、互いに単位の異なる時間間隔の加減算も容易に行うことができます。

TimeSpan構造体
using System;

class Sample {
  static void Main()
  {
    // 3日と1時間30分0秒
    var a = new TimeSpan(3, 1, 30, 00);

    // aを分単位で表すと何分になるか
    Console.WriteLine("{0} = {1}分", a, a.TotalMinutes);

    // 210分
    var b = TimeSpan.FromMinutes(210.0);

    // bは何時間何分か
    Console.WriteLine("{0} = {1}時間{2}分", b, b.Hours, b.Minutes);

    // -1500ミリ秒
    var c = TimeSpan.FromMilliseconds(-1500);

    // cを時間単位で表すと何時間になるか
    Console.WriteLine("{0} = {1}時間", c, c.TotalHours);

    // bとcの合計時間
    var d = b + c;

    Console.WriteLine(d);
  }
}
TimeSpan構造体
Imports System

Class Sample
  Shared Sub Main()
    ' 3日と1時間30分0秒
    Dim a As New TimeSpan(3, 1, 30, 00)

    ' aを分単位で表すと何分になるか
    Console.WriteLine("{0} = {1}分", a, a.TotalMinutes)

    ' 210分
    Dim b As TimeSpan = TimeSpan.FromMinutes(210.0)

    ' bは何時間何分か
    Console.WriteLine("{0} = {1}時間{2}分", b, b.Hours, b.Minutes)

    ' -1500ミリ秒
    Dim c As TimeSpan = TimeSpan.FromMilliseconds(-1500)

    ' cを時間単位で表すと何時間になるか
    Console.WriteLine("{0} = {1}時間", c, c.TotalHours)

    ' bとcの合計時間
    Dim d As TimeSpan = b + c

    Console.WriteLine(d)
  End Sub
End Class
実行結果
3.01:30:00 = 4410分
03:30:00 = 3時間30分
-00:00:01.5000000 = -0.000416666666666667時間
03:29:58.5000000

DateTime・DateTimeOffsetがある特定の時点を表すものであるのに対して、TimeSpanは二つの時刻間の差を表すものとも言えます。 実際、DateTime・DateTimeOffsetで日時の加減算を行う場合、TimeSpanを使うことが出来るようになっています。

DateTime・DateTimeOffset

ここでは、DateTimeおよびDateTimeOffsetを使った日時の操作について見ていきます。 ほとんどの場合において、DateTimeとDateTimeOffsetは同様に扱うことができます。

現在日時の取得

現在日時を取得するにはNowプロパティを参照します。 Nowプロパティで取得できる現在日時はローカル時刻となります。 UTCでの現在日時を取得したい場合は、UtcNowプロパティを参照します。

DateTime/DateTimeOffset.Nowプロパティで現在日時を取得する
using System;

class Sample {
  static void Main()
  {
    // ローカル時刻での現在日時
    Console.WriteLine(DateTime.Now);
    Console.WriteLine(DateTimeOffset.Now);

    // UTCでの現在日時
    Console.WriteLine(DateTime.UtcNow);
    Console.WriteLine(DateTimeOffset.UtcNow);
  }
}
DateTime/DateTimeOffset.Nowプロパティで現在日時を取得する
Imports System

Class Sample
  Shared Sub Main()
    ' ローカル時刻での現在日時
    Console.WriteLine(DateTime.Now)
    Console.WriteLine(DateTimeOffset.Now)

    ' UTCでの現在日時
    Console.WriteLine(DateTime.UtcNow)
    Console.WriteLine(DateTimeOffset.UtcNow)
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
2013/04/01 15:00:30 +09:00
2013/04/01 6:00:30
2013/04/01 6:00:30 +00:00

時刻が不要で、今日の日付のみを取得したい場合は、Todayプロパティを参照します。 Todayプロパティでは、時刻部分が 0時0分0秒(日付変更直後) の値が返されます。 また、Nowプロパティと同様に返される日時はローカル時刻となります。

なお、DateTimeOffsetにはTodayプロパティは存在しません。 コンストラクタで日付のみを指定してインスタンスを作成する必要があります。 もしくは、DateTimeOffset.Nowプロパティで現在日時を取得した後、Dateプロパティで日付のみを取得すれば今日の日付が得られますが、Dateプロパティで得られる値の型はDateTimeとなります。

DateTime.Todayプロパティで現在日時を取得する
using System;

class Sample {
  static void Main()
  {
    // 今日の日付を取得する
    Console.WriteLine(DateTime.Now);
    Console.WriteLine(DateTime.Today);
    Console.WriteLine(DateTimeOffset.Now.Date); // DateTime.Todayと同じ値になる
    Console.WriteLine();

    // DateTimeOffsetで今日の日付(DateTime.Todayに相当する値)を取得する
    var today = new DateTimeOffset(DateTime.Today, DateTimeOffset.Now.Offset);

    Console.WriteLine(DateTimeOffset.Now);
    Console.WriteLine(today);
  }
}
DateTime.Todayプロパティで現在日時を取得する
Imports System

Class Sample
  Shared Sub Main()
    ' 今日の日付を取得する
    Console.WriteLine(DateTime.Now)
    Console.WriteLine(DateTime.Today)
    Console.WriteLine(DateTimeOffset.Now.Date) ' DateTime.Todayと同じ値になる
    Console.WriteLine()

    ' DateTimeOffsetで今日の日付(DateTime.Todayに相当する値)を取得する
    Dim today As New DateTimeOffset(DateTime.Today, DateTimeOffset.Now.Offset)

    Console.WriteLine(DateTimeOffset.Now)
    Console.WriteLine(today)
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
2013/04/01 0:00:00
2013/04/01 0:00:00

2013/04/01 15:00:30 +09:00
2013/04/01 0:00:00 +09:00

二つの時点でNowプロパティの値を取得することで、次の例のように処理の経過時間を計測することも出来ます。

DateTime.Nowプロパティから取得した値を使って経過時間を計測する
using System;
using System.Threading;

class Sample {
  static void Main()
  {
    // 開始時刻を保持
    var startTime = DateTime.Now;

    // 計測対象の処理と仮定
    Thread.Sleep(3000);

    // 終了時刻を保持
    var endTime = DateTime.Now;

    // 経過時間を表示
    Console.WriteLine(endTime - startTime);
  }
}
DateTime.Nowプロパティから取得した値を使って経過時間を計測する
Imports System
Imports System.Threading

Class Sample
  Shared Sub Main()
    ' 開始時刻を保持
    Dim startTime As DateTime = DateTime.Now

    ' 計測対象の処理と仮定
    Thread.Sleep(3000)

    ' 終了時刻を保持
    Dim endTime As DateTime = DateTime.Now

    ' 経過時間を表示
    Console.WriteLine(endTime - startTime)
  End Sub
End Class
実行結果例
00:00:03.0026460

大雑把な経過時間が把握できればよい場合はこの方法で十分ですが、より高い精度で計測したい場合はStopwatchクラスを使います。 経過時間の計測についてはランタイム・システム・プラットフォームの情報 §.経過時間でも解説しています。

DateTime・DateTimeOffset同士での減算を行う場合、結果は単純な数値型ではなくTimeSpan型となります。

最小値・最大値・精度

DateTime・DateTimeOffsetでは、最小で "0001年1月1日 0時0分0秒"、最大で "9999年12月31日 23時59分59秒" までの範囲の日時を扱うことが出来ます。 この最小値・最大値はMinValueフィールドおよびMaxValueフィールドを参照することで取得できます。

DateTime/DateTimeOffset.MinValue/MaxValueプロパティで最小値・最大値を取得する
using System;

class Sample {
  static void Main()
  {
    Console.WriteLine("[DateTime]");
    Console.WriteLine(DateTime.MinValue);
    Console.WriteLine(DateTime.MaxValue);
    Console.WriteLine();

    Console.WriteLine("[DateTimeOffset]");
    Console.WriteLine(DateTimeOffset.MinValue);
    Console.WriteLine(DateTimeOffset.MaxValue);
  }
}
DateTime/DateTimeOffset.MinValue/MaxValueプロパティで最小値・最大値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Console.WriteLine("[DateTime]")
    Console.WriteLine(DateTime.MinValue)
    Console.WriteLine(DateTime.MaxValue)
    Console.WriteLine()

    Console.WriteLine("[DateTimeOffset]")
    Console.WriteLine(DateTimeOffset.MinValue)
    Console.WriteLine(DateTimeOffset.MaxValue)
  End Sub
End Class
実行結果例
[DateTime]
0001/01/01 0:00:00
9999/12/31 23:59:59

[DateTimeOffset]
0001/01/01 0:00:00 +00:00
9999/12/31 23:59:59 +00:00

なお、DateTimeOffsetのオフセット部分は、最小値が-14時間、最大値が+14時間となっています。


また、DateTime・DateTimeOffsetで扱える日時の精度は100ナノ秒となっています。 Ticksプロパティを参照すると、日時を100ナノ秒単位での値で取得することができます。

コンストラクタでも100ナノ秒単位の値を指定する事ができ、最小値である0001年1月1日 0時0分0秒に指定した値を加えた値がインスタンスの表す日時となります。

DateTime/DateTimeOffset.Ticksプロパティで100ナノ秒単位の値を取得する
using System;

class Sample {
  static void Main()
  {

    Console.WriteLine("[DateTime]");
    Console.WriteLine(DateTime.MinValue.Ticks);
    Console.WriteLine(DateTime.MaxValue.Ticks);

    // 30,000,000 × 100ナノ秒 = 3秒
    Console.WriteLine(new DateTime(30000000));
    Console.WriteLine();

    Console.WriteLine("[DateTimeOffset]");
    Console.WriteLine(DateTimeOffset.MinValue.Ticks);
    Console.WriteLine(DateTimeOffset.MaxValue.Ticks);

    // 30,000,000 × 100ナノ秒 = 3秒
    Console.WriteLine(new DateTimeOffset(30000000, TimeSpan.Zero));
  }
}
DateTime/DateTimeOffset.Ticksプロパティで100ナノ秒単位の値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Console.WriteLine("[DateTime]")
    Console.WriteLine(DateTime.MinValue.Ticks)
    Console.WriteLine(DateTime.MaxValue.Ticks)

    ' 30,000,000 × 100ナノ秒 = 3秒
    Console.WriteLine(New DateTime(30000000))
    Console.WriteLine()

    Console.WriteLine("[DateTimeOffset]")
    Console.WriteLine(DateTimeOffset.MinValue.Ticks)
    Console.WriteLine(DateTimeOffset.MaxValue.Ticks)

    ' 30,000,000 × 100ナノ秒 = 3秒
    Console.WriteLine(New DateTimeOffset(30000000, TimeSpan.Zero))
  End Sub
End Class
実行結果例
[DateTime]
0
3155378975999999999
0001/01/01 0:00:03

[DateTimeOffset]
0
3155378975999999999
0001/01/01 0:00:03 +00:00

日時の要素の取得

DateTime・DateTimeOffsetでは日時を扱える以上、日時から時分秒や年月日・曜日などを個別に扱うことも出来るようになっています。

時分秒の取得

DateTime・DateTimeOffsetが表す日時の時分秒を参照するには、HourMinuteSecondの各プロパティを参照します。 Millisecondプロパティで秒の端数(ミリ秒部分)も取得することが出来ます。

DateTime/DateTimeOffset.Hour/Minute/Secondプロパティで時・分・秒それぞれの値を取得する
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    Console.WriteLine("{0}時", dt.Hour);             // 現在時刻の時部分を取得
    Console.WriteLine("{0}分", dt.Minute);           // 現在時刻の分部分を取得
    Console.WriteLine("{0}秒", dt.Second);           // 現在時刻の秒部分を取得
    Console.WriteLine("{0}ミリ秒", dt.Millisecond);  // 現在時刻のミリ秒部分を取得
    Console.WriteLine();

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    Console.WriteLine("{0}時", dto.Hour);            // 現在時刻の時部分を取得
    Console.WriteLine("{0}分", dto.Minute);          // 現在時刻の分部分を取得
    Console.WriteLine("{0}秒", dto.Second);          // 現在時刻の秒部分を取得
    Console.WriteLine("{0}ミリ秒", dto.Millisecond); // 現在時刻のミリ秒部分を取得
  }
}
DateTime/DateTimeOffset.Hour/Minute/Secondプロパティで時・分・秒それぞれの値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Console.WriteLine("{0}時", dt.Hour)             ' 現在時刻の時部分を取得
    Console.WriteLine("{0}分", dt.Minute)           ' 現在時刻の分部分を取得
    Console.WriteLine("{0}秒", dt.Second)           ' 現在時刻の秒部分を取得
    Console.WriteLine("{0}ミリ秒", dt.Millisecond)  ' 現在時刻のミリ秒部分を取得
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Console.WriteLine("{0}時", dto.Hour)            ' 現在時刻の時部分を取得
    Console.WriteLine("{0}分", dto.Minute)          ' 現在時刻の分部分を取得
    Console.WriteLine("{0}秒", dto.Second)          ' 現在時刻の秒部分を取得
    Console.WriteLine("{0}ミリ秒", dto.Millisecond) ' 現在時刻のミリ秒部分を取得
  End Sub
End Class
実行結果例
15時
0分
30秒
123ミリ秒

15時
0分
30秒
123ミリ秒

TimeOfDayプロパティでは、DateTimeの表す日時のうち、時刻の部分(午前0時ちょうどからの経過時間)のみをTimeSpanで取得することが出来ます。

DateTime/DateTimeOffset.TimeOfDayプロパティで時刻のみを取得する
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    var timeOfDt = dt.TimeOfDay; // 時刻部分のみをTimeSpanとして取得

    Console.WriteLine(timeOfDt);

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    var timeOfDto = dto.TimeOfDay; // 時刻部分のみをTimeSpanとして取得

    Console.WriteLine(timeOfDto);
  }
}
DateTime/DateTimeOffset.TimeOfDayプロパティで時刻のみを取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Dim timeOfDt As TimeSpan = dt.TimeOfDay ' 時刻部分のみをTimeSpanとして取得

    Console.WriteLine(timeOfDt)

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Dim timeOfDto As TimeSpan = dto.TimeOfDay ' 時刻部分のみをTimeSpanとして取得

    Console.WriteLine(timeOfDto)
  End Sub
End Class
実行結果例
15:00:30.1230000
15:00:30.1230000

Ticksプロパティでは、DateTimeの最小値である0001年1月1日 0時0分0秒からの経過時間を100ナノ秒単位で取得することが出来ます。 なお、DateTimeOffsetにはUtcTicksプロパティが用意されていて、UTCに変換した時刻での経過時間を取得できます。 単位はTicksと同じく100ナノ秒です。

DateTime/DateTimeOffset.Ticksプロパティで基準時刻からの経過時間を100ナノ秒単位で取得する
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    Console.WriteLine(dt.Ticks);
    Console.WriteLine();

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    Console.WriteLine(dto.Ticks);
    Console.WriteLine(dto.UtcTicks); // UTCに変換した時刻での経過時間
  }
}
DateTime/DateTimeOffset.Ticksプロパティで基準時刻からの経過時間を100ナノ秒単位で取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Console.WriteLine(dt.Ticks)
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Console.WriteLine(dto.Ticks)
    Console.WriteLine(dto.UtcTicks)
  End Sub
End Class
実行結果例
635004252301230000

635004252301230000
635003928301230000

年月日・曜日の取得

DateTime・DateTimeOffsetが表す日時の年月日を参照するには、YearMonthDayの各プロパティを参照します。 DayOfWeekプロパティで日付の曜日を取得することが出来ます。

日付が1月の場合、Monthプロパティは1を返します。 C言語のtm構造体など、1月が0となる言語・処理系とは異なる点に注意してください。

また、DayOfWeekプロパティが返す曜日は数値ではなく、DayOfWeek列挙体の値となります。

DateTime/DateTimeOffset.Year/Month/Day/DayOfWeekプロパティで年・月・日・曜日それぞれの値を取得する
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    Console.WriteLine("{0}年", dt.Year);         // 現在日付の年部分を取得
    Console.WriteLine("{0}月", dt.Month);        // 現在日付の月部分を取得
    Console.WriteLine("{0}日", dt.Day);          // 現在日付の日部分を取得
    Console.WriteLine("{0}曜日", dt.DayOfWeek);  // 現在日付の曜日部分を取得
    Console.WriteLine();

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    Console.WriteLine("{0}年", dto.Year);         // 現在日付の年部分を取得
    Console.WriteLine("{0}月", dto.Month);        // 現在日付の月部分を取得
    Console.WriteLine("{0}日", dto.Day);          // 現在日付の日部分を取得
    Console.WriteLine("{0}曜日", dto.DayOfWeek);  // 現在日付の曜日部分を取得
  }
}
DateTime/DateTimeOffset.Year/Month/Day/DayOfWeekプロパティで年・月・日・曜日それぞれの値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Console.WriteLine("{0}年", dt.Year)         ' 現在日付の年部分を取得
    Console.WriteLine("{0}月", dt.Month)        ' 現在日付の月部分を取得
    Console.WriteLine("{0}日", dt.Day)          ' 現在日付の日部分を取得
    Console.WriteLine("{0}曜日", dt.DayOfWeek)  ' 現在日付の曜日部分を取得
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Console.WriteLine("{0}年", dto.Year)         ' 現在日付の年部分を取得
    Console.WriteLine("{0}月", dto.Month)        ' 現在日付の月部分を取得
    Console.WriteLine("{0}日", dto.Day)          ' 現在日付の日部分を取得
    Console.WriteLine("{0}曜日", dto.DayOfWeek)  ' 現在日付の曜日部分を取得
  End Sub
End Class
実行結果例
2013年
4月
1日
Monday曜日

2013年
4月
1日
Monday曜日

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型で取得することが出来ます。

DateTime/DateTimeOffset.Dateプロパティで日付部分のみの値を取得する
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    Console.WriteLine(dt);
    Console.WriteLine(dt.Date); // 日付部分のみを取得
    Console.WriteLine();

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    Console.WriteLine(dto);
    Console.WriteLine(dto.Date); // 日付部分のみを取得
  }
}
DateTime/DateTimeOffset.Dateプロパティで日付部分のみの値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Console.WriteLine(dt)
    Console.WriteLine(dt.Date) ' 日付部分のみを取得
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Console.WriteLine(dto)
    Console.WriteLine(dto.Date) ' 日付部分のみを取得
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
2013/04/01 0:00:00

2013/04/01 15:00:30 +09:00
2013/04/01 0:00:00

月名・曜日名・年号の表記

月名を英語や他の外国語表記にしたり、曜日名を日本語表記にしたり、和暦での年号を付記したりするには、書式を指定した文字列化や特定カルチャの指定を行うことで出来ます。

DateTime/DateTimeOffsetの値を英語・日本語や他の言語での表記で文字列化する
using System;
using System.Globalization;
using System.Threading;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    // スレッドのカルチャをen-US(英語/アメリカ合衆国)に変更
    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

    Console.WriteLine("{0:D} {0:T}", dt);  // 日付と時刻を長い形式で表す標準の書式指定子
    Console.WriteLine(dt.ToString("MMMM")); // 月の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("MMM"));  // 月の省略名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("dddd")); // 曜日の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("ddd"));  // 曜日の省略名を表すカスタム書式指定子
    Console.WriteLine();

    // スレッドのカルチャは変更せず、カルチャを指定して文字列化
    var jajp = new CultureInfo("ja-JP"); // 日本語/日本のカルチャを作成

    Console.WriteLine(string.Format(jajp, "{0:D} {0:T}", dt));  // 日付と時刻を長い形式で表す標準の書式指定子
    Console.WriteLine(dt.ToString("MMMM", jajp)); // 月の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("MMM", jajp));  // 月の省略名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("dddd", jajp)); // 曜日の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("ddd", jajp));  // 曜日の省略名を表すカスタム書式指定子
    Console.WriteLine();

    // 個別にカルチャを指定して文字列化する
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("de-DE"))); // ドイツ語/ドイツでの曜日の完全名
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("fr-FR"))); // フランス語/フランスでの曜日の完全名
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("zh-TW"))); // 繁体字中国語/台湾での曜日の完全名
    Console.WriteLine();
  }
}
DateTime/DateTimeOffsetの値を英語・日本語や他の言語での表記で文字列化する
Imports System
Imports System.Globalization
Imports System.Threading

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    ' スレッドのカルチャをen-US(英語/アメリカ合衆国)に変更
    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")

    Console.WriteLine("{0:D} {0:T}", dt)  ' 日付と時刻を長い形式で表す標準の書式指定子
    Console.WriteLine(dt.ToString("MMMM")) ' 月の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("MMM"))  ' 月の省略名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("dddd")) ' 曜日の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("ddd"))  ' 曜日の省略名を表すカスタム書式指定子
    Console.WriteLine()

    ' スレッドのカルチャは変更せず、カルチャを指定して文字列化
    Dim jajp As New CultureInfo("ja-JP") ' 日本語/日本のカルチャを作成

    Console.WriteLine(String.Format(jajp, "{0:D} {0:T}", dt))  ' 日付と時刻を長い形式で表す標準の書式指定子
    Console.WriteLine(dt.ToString("MMMM", jajp)) ' 月の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("MMM", jajp))  ' 月の省略名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("dddd", jajp)) ' 曜日の完全名を表すカスタム書式指定子
    Console.WriteLine(dt.ToString("ddd", jajp))  ' 曜日の省略名を表すカスタム書式指定子
    Console.WriteLine()

    ' 個別にカルチャを指定して文字列化する
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("de-DE"))) ' ドイツ語/ドイツでの曜日の完全名
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("fr-FR"))) ' フランス語/フランスでの曜日の完全名
    Console.WriteLine(dt.ToString("dddd", new CultureInfo("zh-TW"))) ' 繁体字中国語/台湾での曜日の完全名
    Console.WriteLine()
  End Sub
End Class
実行結果例
Monday, April 01, 2013 3:00:30 PM
April
Apr
Monday
Mon

2013年4月1日 15:00:30
4月
4
月曜日
月

Montag
lundi
星期一
DateTime/DateTimeOffsetの値を西暦・和暦の表記で文字列化する
using System;
using System.Globalization;

class Sample {
  static void Main()
  {
    var dt1 = new DateTime(2019, 4, 30); // 2019年4月30日
    var dt2 = new DateTime(2019, 5, 1);  // 2019年5月1日

    // ja-JPのCultureInfoを作成
    var jajp = new CultureInfo("ja-JP");

    // カルチャを指定して文字列化
    Console.WriteLine(dt1.ToString("gg yyyy", jajp)); // 年号+年4桁
    Console.WriteLine(dt2.ToString("gg yyyy", jajp));
    Console.WriteLine();

    // JapaneseCalendarで定義される日付と時刻の書式を使用するように変更
    jajp.DateTimeFormat.Calendar = new JapaneseCalendar();

    // JapaneseCalendarに変更したカルチャを指定して文字列化
    Console.WriteLine(dt1.ToString("gg yyyy", jajp)); // 年号+年4桁
    Console.WriteLine(dt2.ToString("gg yyyy", jajp));
  }
}
DateTime/DateTimeOffsetの値を西暦・和暦の表記で文字列化する
Imports System
Imports System.Globalization

Class Sample
  Shared Sub Main()
    Dim dt1 As New DateTime(2019, 4, 30) ' 2019年4月30日
    Dim dt2 As New DateTime(2019, 5, 1)  ' 2019年5月1日

    ' ja-JPのCultureInfoを作成
    Dim jajp As New CultureInfo("ja-JP")

    ' カルチャを指定して文字列化
    Console.WriteLine(dt1.ToString("gg yyyy", jajp)) ' 年号+年4桁
    Console.WriteLine(dt2.ToString("gg yyyy", jajp))
    Console.WriteLine()

    ' JapaneseCalendarで定義される日付と時刻の書式を使用するように変更
    jajp.DateTimeFormat.Calendar = New JapaneseCalendar()

    ' JapaneseCalendarに変更したカルチャを指定して文字列化
    Console.WriteLine(dt1.ToString("gg yyyy", jajp)) ' 年号+年4桁
    Console.WriteLine(dt2.ToString("gg yyyy", jajp))
  End Sub
End Class
実行結果例
西暦 2019
西暦 2019

平成 31
令和 01

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メソッドである年がうるう年かどうかを調べる
using System;

class Sample {
  static void Main()
  {
    for (var year = 2010; year <= 2020; year++) {
      // 2010年〜2020年の各年がうるう年かどうかを求める
      Console.WriteLine("IsLeapYear({0}) : {1}", year, DateTime.IsLeapYear(year));
    }
  }
}
DateTime.IsLeapYearメソッドである年がうるう年かどうかを調べる
Imports System

Class Sample
  Shared Sub Main()
    For year As Integer = 2010 to 2020
      ' 2010年〜2020年の各年がうるう年かどうかを求める
      Console.WriteLine("IsLeapYear({0}) : {1}", year, DateTime.IsLeapYear(year))
    Next
  End Sub
End Class
実行結果
IsLeapYear(2010) : False
IsLeapYear(2011) : False
IsLeapYear(2012) : True
IsLeapYear(2013) : False
IsLeapYear(2014) : False
IsLeapYear(2015) : False
IsLeapYear(2016) : True
IsLeapYear(2017) : False
IsLeapYear(2018) : False
IsLeapYear(2019) : False
IsLeapYear(2020) : True

DateTimeではグレゴリオ暦が使用されるため、IsLeapYearメソッドもグレゴリオ暦の暦法に従ってうるう年かどうかの判定が行われます。 グレゴリオ暦以外でのうるう年の判定を行う必要がある場合は、Calendarクラスを使います。

通算日数

DayOfYearプロパティを参照することで、DateTime・DateTimeOffsetの表す日時がその年の通算何日目かを取得することが出来ます。

DateTime/DateTimeOffset.DayOfYearプロパティでその年の通算何日目かを求める
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // 現在の日時を取得

    Console.WriteLine(dt);
    Console.WriteLine(dt.DayOfYear); // 今年の何日目か取得する
    Console.WriteLine();

    var dto = DateTimeOffset.Now; // 現在の日時を取得

    Console.WriteLine(dto);
    Console.WriteLine(dto.DayOfYear); // 今年の何日目か取得する
  }
}
DateTime/DateTimeOffset.DayOfYearプロパティでその年の通算何日目かを求める
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' 現在の日時を取得

    Console.WriteLine(dt)
    Console.WriteLine(dt.DayOfYear) ' 今年の何日目か取得する
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now ' 現在の日時を取得

    Console.WriteLine(dto)
    Console.WriteLine(dto.DayOfYear) ' 今年の何日目か取得する
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
91

2013/04/01 15:00:30 +09:00
91

DayOfYearプロパティは、うるう年の場合は追加されたうるう日の分も積算します。 次の例では2011年〜2013年の各年の4月1日を表すDateTimeに対して、その年がうるう年かどうかと、その日までの通算日数を表示しています。

DateTime/DateTimeOffset.DayOfYearプロパティでうるう年での通算何日目かを求める
using System;

class Sample {
  static void Main()
  {
    // 2011年〜2013年の各年の4月1日
    var dt20110401 = new DateTime(2011, 4, 1);
    var dt20120401 = new DateTime(2012, 4, 1);
    var dt20130401 = new DateTime(2013, 4, 1);

    Console.WriteLine("{0} ({1}) : {2}", dt20110401, DateTime.IsLeapYear(dt20110401.Year), dt20110401.DayOfYear);
    Console.WriteLine("{0} ({1}) : {2}", dt20120401, DateTime.IsLeapYear(dt20120401.Year), dt20120401.DayOfYear);
    Console.WriteLine("{0} ({1}) : {2}", dt20130401, DateTime.IsLeapYear(dt20130401.Year), dt20130401.DayOfYear);
  }
}
DateTime/DateTimeOffset.DayOfYearプロパティでうるう年での通算何日目かを求める
Imports System

Class Sample
  Shared Sub Main()
    ' 2011年〜2013年の各年の4月1日
    Dim dt20110401 As New DateTime(2011, 4, 1)
    Dim dt20120401 As New DateTime(2012, 4, 1)
    Dim dt20130401 As New DateTime(2013, 4, 1)

    Console.WriteLine("{0} ({1}) : {2}", dt20110401, DateTime.IsLeapYear(dt20110401.Year), dt20110401.DayOfYear)
    Console.WriteLine("{0} ({1}) : {2}", dt20120401, DateTime.IsLeapYear(dt20120401.Year), dt20120401.DayOfYear)
    Console.WriteLine("{0} ({1}) : {2}", dt20130401, DateTime.IsLeapYear(dt20130401.Year), dt20130401.DayOfYear)
  End Sub
End Class

実行結果
2011/04/01 0:00:00 (False) : 91
2012/04/01 0:00:00 (True) : 92
2013/04/01 0:00:00 (False) : 91

月ごとの日数

DaysInMonthメソッドを使うとある年ある月の日数を求めることが出来ます。 このメソッドでは、指定された年がうるう年の場合は追加されたうるう日の分も含めた日数を返します。 次の例では2012年の各月ごとの日数を表示しています。

DateTime.DaysInMonthメソッドである年ある月の日数を求める
using System;

class Sample {
  static void Main()
  {
    for (var month = 1; month <= 12; month++) {
      // 2012年1月〜12月の各月の日数を求める
      Console.WriteLine("2012-{0} : {1} days", month, DateTime.DaysInMonth(2012, month));
    }
  }
}
DateTime.DaysInMonthメソッドである年ある月の日数を求める
Imports System

Class Sample
  Shared Sub Main()
    For month As Integer = 1 To 12
      ' 2012年1月〜12月の各月の日数を求める
      Console.WriteLine("2012-{0} : {1} days", month, DateTime.DaysInMonth(2012, month))
    Next
  End Sub
End Class
実行結果
2012-1 : 31 days
2012-2 : 29 days
2012-3 : 31 days
2012-4 : 30 days
2012-5 : 31 days
2012-6 : 30 days
2012-7 : 31 days
2012-8 : 31 days
2012-9 : 30 days
2012-10 : 31 days
2012-11 : 30 days
2012-12 : 31 days

このメソッドを用いることで、月末の日付を求めることも出来ます。 実装例は月末の日付を求めるで紹介しています。

夏時間

IsDaylightSavingTimeメソッドを使うと、DateTimeの表す日時が夏時間の期間内かどうかを調べることができます。 このメソッドでは、実行環境に設定されているタイムゾーンに夏時間が導入されていなければ、当然どのような日付に対してもfalseを返します。 なお、実行環境のタイムゾーンに関する情報は、TimeZoneクラスおよびTimeZoneInfoクラスで参照することが出来ます。

DateTime.IsDaylightSavingTimeメソッドを使ってDateTimeの表す日時が夏時間かどうかを調べる
using System;

class Sample {
  static void Main()
  {
    // 標準時間・夏時間のタイムゾーン名を表示
    Console.WriteLine("StandardName: {0}", TimeZone.CurrentTimeZone.StandardName);
    Console.WriteLine("DaylightName: {0}", TimeZone.CurrentTimeZone.DaylightName);

    // 冬期・夏期の日付に対してIsDaylightSavingTimeメソッドを呼び出して夏時間かどうか調べる
    var winter = new DateTime(2013, 1, 1);
    var summer = new DateTime(2013, 7, 1);

    Console.WriteLine("{0} {1}", winter, winter.IsDaylightSavingTime());
    Console.WriteLine("{0} {1}", summer, summer.IsDaylightSavingTime());
  }
}
DateTime.IsDaylightSavingTimeメソッドを使ってDateTimeの表す日時が夏時間かどうかを調べる
Imports System

Class Sample
  Shared Sub Main()
    ' 標準時間・夏時間のタイムゾーン名を表示
    Console.WriteLine("StandardName: {0}", TimeZone.CurrentTimeZone.StandardName)
    Console.WriteLine("DaylightName: {0}", TimeZone.CurrentTimeZone.DaylightName)

    ' 冬期・夏期の日付に対してIsDaylightSavingTimeメソッドを呼び出して夏時間かどうか調べる
    Dim winter As New DateTime(2013, 1, 1)
    Dim summer As New DateTime(2013, 7, 1)

    Console.WriteLine("{0} {1}", winter, winter.IsDaylightSavingTime())
    Console.WriteLine("{0} {1}", summer, summer.IsDaylightSavingTime())
  End Sub
End Class
Windows 10+.NET Framework 4.8・タイムゾーンが「大阪、札幌、東京」での実行結果例
StandardName: 東京 (標準時)
DaylightName: 東京 (夏時間)
2013/01/01 0:00:00 False
2013/07/01 0:00:00 False
Ubuntu 18.04+.NET Core 2.1・環境変数TZ=America/Los_Angelesでの実行結果例
StandardName: アメリカ太平洋標準時
DaylightName: アメリカ太平洋夏時間
2013/01/01 0:00:00 False
2013/07/01 0:00:00 True
Ubuntu 18.04+Mono 6.0・環境変数TZ=Asia/Tokyoでの実行結果例
StandardName: JST
DaylightName: JDT
2013/01/01 0:00:00 False
2013/07/01 0:00:00 False
Ubuntu 18.04+Mono 6.0・環境変数TZ=America/Los_Angelesでの実行結果例
StandardName: PST
DaylightName: PDT
2013/01/01 0:00:00 False
2013/07/01 0:00:00 True

実行環境に設定されているものとは異なるタイムゾーンにおける日時が夏時間の期間内かどうかを調べるには、TimeZoneInfo.IsDaylightSavingTimeメソッドを使います。

日時の値の変更・加減算

年月日や時分秒を表すHour・Day・Monthなどのプロパティは参照専用で、インスタンスを作成した後は一切変更することができません。 年月日・時分秒の一部分だけを変更したい場合は、変更したい値をコンストラクタに指定して新たにインスタンスを作成する必要があります。

既存のDateTimeから日時の値を変更したDateTimeを作成する
using System;

class Sample {
  static void Main()
  {
    var now = DateTime.Now; // 現在日時を取得

    // 明日同時刻のインスタンスを作成
    var oneDayLater = new DateTime(now.Year, now.Month, now.Day + 1, now.Hour, now.Minute, now.Second);

    Console.WriteLine(now);
    Console.WriteLine(oneDayLater);
  }
}
既存のDateTimeから日時の値を変更したDateTimeを作成する
Imports System

Class Sample
  Shared Sub Main()
    Dim now As DateTime = DateTime.Now ' 現在日時を取得

    ' 明日同時刻のインスタンスを作成
    Dim oneDayLater As New DateTime(now.Year, now.Month, now.Day + 1, now.Hour, now.Minute, now.Second)

    Console.WriteLine(now)
    Console.WriteLine(oneDayLater)
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
2013/04/02 15:00:30

上記の例では、明日同時刻のDateTimeを作成していますが、月末に実行すると例外ArgumentOutOfRangeExceptionがスローされます。 例えば4月30日では、単純に日にちに1足すと4月31日となり、コンストラクタに不正な日付を指定することになるためです。

このように、既存のDateTimeの値を足し引きしてコンストラクタに指定する場合は、月替わりや日付変更・正時を跨ぐような場合に値が範囲外とならないよう考慮する必要があります。 一方、DateTime.AddDays等のメソッドで日時の加減算を行えば、そういった日時の境界を跨ぐ加減算も容易に行えます。

日時の加減算

コンストラクタで具体的な日時を指定する他にも、基準となる日時から加減算して目的の日時のインスタンスを作成することも出来ます。 例えば、AddDaysメソッドを使用するとインスタンスに指定した日数を足した日時を取得することが出来るため、このメソッドを使うと上記の例は次のように書き換えることが出来ます。

DateTime.Addメソッドを使ってDateTimeの表す日時に加減算する
using System;

class Sample {
  static void Main()
  {
    var now = DateTime.Now; // 現在日時を取得

    // 明日同時刻のインスタンスを作成
    var oneDayLater = now.AddDays(1.0); // nowに1.0日分加算した値を求める

    Console.WriteLine(now);
    Console.WriteLine(oneDayLater);
  }
}
DateTime.Addメソッドを使ってDateTimeの表す日時に加減算する
Imports System

Class Sample
  Shared Sub Main()
    Dim now As DateTime = DateTime.Now ' 現在日時を取得

    ' 明日同時刻のインスタンスを作成
    Dim oneDayLater As DateTime = now.AddDays(1.0) ' nowに1.0日分加算した値を求める

    Console.WriteLine(now)
    Console.WriteLine(oneDayLater)
  End Sub
End Class
実行結果例
2013/04/01 15:00:30
2013/04/02 15:00:30

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.Addメソッドを使って日時を正規化する
using System;

class Sample {
  static void Main()
  {
    var now = DateTime.Now; // 現在日時を取得

    Console.WriteLine("now: {0}", now);
    Console.WriteLine("3 days before: {0}", now.AddDays(-3.0).Date); // 3日前の日付を求める
    Console.WriteLine();

    // 日時「2012年2月28日 32時の5分前」を正規化する
    var dt = new DateTime(2012, 2, 28);

    dt = dt.AddHours(32.0); // 32時
    dt = dt.AddMinutes(-5.0); // 5分前

    Console.WriteLine(dt);
  }
}
DateTime.Addメソッドを使って日時を正規化する
Imports System

Class Sample
  Shared Sub Main()
    Dim now As DateTime = DateTime.Now ' 現在日時を取得

    Console.WriteLine("now: {0}", now)
    Console.WriteLine("3 days before: {0}", now.AddDays(-3.0).Date) ' 3日前の日付を求める
    Console.WriteLine()

    ' 日時「2012年2月28日 32時の5分前」を正規化する
    Dim dt As New DateTime(2012, 2, 28)

    dt = dt.AddHours(32.0) ' 32時
    dt = dt.AddMinutes(-5.0) ' 5分前

    Console.WriteLine(dt)
  End Sub
End Class
実行結果例
now: 2013/04/01 15:00:30
3 days before: 2013/03/29 0:00:00

2012/02/29 7:55:00

当然ながらこれらのメソッドで日時の加減算を行なっても、その結果として得られるDateTimeのKindおよびDateTimeOffsetのOffsetは加減算を行う前のものと同じものとなります(日時の加減算はDateTime.KindおよびDateTimeOffset.Offsetには影響しません)。


Addメソッド・Subtractメソッドでは引数にTimeSpanを取るため、8時間30分5秒前や1日と8時間後といった日時を一度のメソッド呼び出しで求めることができます。 さらに、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、DateTime・DateTimeOffsetにTimeSpanを加減算するために加算演算子・減算演算子を使うこともできます。 当然、結果はAddメソッド・Subtractメソッドを使う場合と同じです。

DateTime/DateTimeOffset.Add・SubtractメソッドとTimeSpanを使って日時の加減算を行う
using System;

class Sample {
  static void Main()
  {
    // +36時間を表すTimeSpan
    var span = new TimeSpan(36, 0, 0);

    // DateTimeにTimeSpanを加算する
    var dt = new DateTime(2012, 2, 28);

    Console.WriteLine(dt + span); // == dt.Add(span)

    // DateTimeOffsetにTimeSpanを加算する
    var dto = new DateTimeOffset(2012, 2, 28, 0, 0, 0, TimeSpan.Zero);

    Console.WriteLine(dto + span); // == dto.Add(span)
  }
}
DateTime/DateTimeOffset.Add・SubtractメソッドとTimeSpanを使って日時の加減算を行う
Imports System

Class Sample
  Shared Sub Main()
    ' +36時間を表すTimeSpan
    Dim span As New TimeSpan(36, 0, 0)

    ' DateTimeにTimeSpanを加算する
    Dim dt As New DateTime(2012, 2, 28)

    Console.WriteLine(dt + span) ' == dt.Add(span)

    ' DateTimeOffsetにTimeSpanを加算する
    Dim dto As New DateTimeOffset(2012, 2, 28, 0, 0, 0, TimeSpan.Zero)

    Console.WriteLine(dto + span) ' == dto.Add(span)
  End Sub
End Class
実行結果
2012/02/29 12:00:00
2012/02/29 12:00:00 +00:00

AddYearsとうるう年の考慮

うるう年の2月29日を表すDateTime・DateTimeOffsetに対してAddYearsメソッドで年単位の加減算を行う場合は注意が必要です。 うるう年の2月29日から年単位の加減算をした結果、その年もうるう年となる場合は2月29日、そうでない場合は2月28日が返されます(3月1日にはなりません)。

DateTime/DateTimeOffset.AddYearsで2月29日のn年前・n年後の日付を求める場合の動作
using System;

class Sample {
  static void Main()
  {
    var baseDate = new DateTime(2012, 2, 29);

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1));
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1));
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4));
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4));
    Console.WriteLine();

    baseDate = new DateTime(2016, 2, 29);

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1));
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1));
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4));
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4));
  }
}
DateTime/DateTimeOffset.AddYearsで2月29日のn年前・n年後の日付を求める場合の動作
Imports System

Class Sample
  Shared Sub Main()
    Dim baseDate As New DateTime(2012, 2, 29)

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1))
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1))
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4))
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4))
    Console.WriteLine()

    baseDate = New DateTime(2016, 2, 29)

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1))
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1))
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4))
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4))
  End Sub
End Module
実行結果
2012/02/29 0:00:00 + 1 years = 2013/02/28 0:00:00
2012/02/29 0:00:00 - 1 years = 2011/02/28 0:00:00
2012/02/29 0:00:00 + 4 years = 2016/02/29 0:00:00
2012/02/29 0:00:00 - 4 years = 2008/02/29 0:00:00

2016/02/29 0:00:00 + 1 years = 2017/02/28 0:00:00
2016/02/29 0:00:00 - 1 years = 2015/02/28 0:00:00
2016/02/29 0:00:00 + 4 years = 2020/02/29 0:00:00
2016/02/29 0:00:00 - 4 years = 2012/02/29 0:00:00

一方、2月28日または3月1日を表すDateTime・DateTimeOffsetに対してAddYearsメソッドを用いる場合は、その年がうるう年となるか否かに関わらず、結果は2月28日または3月1日となります。

DateTime/DateTimeOffset.AddYearsで2月28日・3月1日のn年前・n年後の日付を求める場合の動作
using System;

class Sample {
  static void Main()
  {
    var baseDate = new DateTime(2012, 2, 28);

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1));
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1));
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4));
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4));
    Console.WriteLine();

    baseDate = new DateTime(2016, 3, 1);

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1));
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1));
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4));
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4));
  }
}
DateTime/DateTimeOffset.AddYearsで2月28日・3月1日のn年前・n年後の日付を求める場合の動作
Imports System

Class Sample
  Shared Sub Main()
    Dim baseDate As New DateTime(2012, 2, 28)

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1))
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1))
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4))
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4))
    Console.WriteLine()

    baseDate = New DateTime(2016, 3, 1)

    Console.WriteLine("{0} + 1 years = {1}", baseDate, baseDate.AddYears(+1))
    Console.WriteLine("{0} - 1 years = {1}", baseDate, baseDate.AddYears(-1))
    Console.WriteLine("{0} + 4 years = {1}", baseDate, baseDate.AddYears(+4))
    Console.WriteLine("{0} - 4 years = {1}", baseDate, baseDate.AddYears(-4))
  End Sub
End Module
実行結果
2012/02/28 0:00:00 + 1 years = 2013/02/28 0:00:00
2012/02/28 0:00:00 - 1 years = 2011/02/28 0:00:00
2012/02/28 0:00:00 + 4 years = 2016/02/28 0:00:00
2012/02/28 0:00:00 - 4 years = 2008/02/28 0:00:00

2016/03/01 0:00:00 + 1 years = 2017/03/01 0:00:00
2016/03/01 0:00:00 - 1 years = 2015/03/01 0:00:00
2016/03/01 0:00:00 + 4 years = 2020/03/01 0:00:00
2016/03/01 0:00:00 - 4 years = 2012/03/01 0:00:00

うるう年かどうかの判別については§.うるう年を参照してください。

AddMonthsと月ごとの日数の考慮

AddMonthsメソッドで月単位の加減算を行った結果その月の末日を超える場合は、日付の部分はその月の末日となります。 例えば、1月31日から3ヶ月加算した場合、4月31日は4月の末日を超えるため結果は4月30日となります。 同様に、1月31日から1ヶ月加算した場合、結果はうるう年であれば2月28日、そうでなければ2月29日となります。

DateTime/DateTimeOffset.AddMonthsで1月31日のnヶ月後の日付を求める場合の動作
using System;

class Sample {
  static void Main()
  {
    var baseDate = new DateTime(2015, 1, 31);

    Console.WriteLine("{0} + 1 months = {1}", baseDate, baseDate.AddMonths(+1));
    Console.WriteLine("{0} + 2 months = {1}", baseDate, baseDate.AddMonths(+2));
    Console.WriteLine("{0} + 3 months = {1}", baseDate, baseDate.AddMonths(+3));
    Console.WriteLine();

    baseDate = new DateTime(2016, 1, 31);

    Console.WriteLine("{0} + 1 months = {1}", baseDate, baseDate.AddMonths(+1));
    Console.WriteLine("{0} + 2 months = {1}", baseDate, baseDate.AddMonths(+2));
    Console.WriteLine("{0} + 3 months = {1}", baseDate, baseDate.AddMonths(+3));
  }
}
DateTime/DateTimeOffset.AddMonthsで1月31日のnヶ月後の日付を求める場合の動作
Imports System

Class Sample
  Shared Sub Main()
    Dim baseDate As New DateTime(2015, 1, 31)

    Console.WriteLine("{0} + 1 months = {1}", baseDate, baseDate.AddMonths(+1))
    Console.WriteLine("{0} + 2 months = {1}", baseDate, baseDate.AddMonths(+2))
    Console.WriteLine("{0} + 3 months = {1}", baseDate, baseDate.AddMonths(+3))
    Console.WriteLine()

    baseDate = New DateTime(2016, 1, 31)

    Console.WriteLine("{0} + 1 months = {1}", baseDate, baseDate.AddMonths(+1))
    Console.WriteLine("{0} + 2 months = {1}", baseDate, baseDate.AddMonths(+2))
    Console.WriteLine("{0} + 3 months = {1}", baseDate, baseDate.AddMonths(+3))
  End Sub
End Module
実行結果
2015/01/31 0:00:00 + 1 months = 2015/02/28 0:00:00
2015/01/31 0:00:00 + 2 months = 2015/03/31 0:00:00
2015/01/31 0:00:00 + 3 months = 2015/04/30 0:00:00

2016/01/31 0:00:00 + 1 months = 2016/02/29 0:00:00
2016/01/31 0:00:00 + 2 months = 2016/03/31 0:00:00
2016/01/31 0:00:00 + 3 months = 2016/04/30 0:00:00

日時同士の差

DateTime.SubtractおよびDateTimeOffset.Subtractメソッドは、日時に対する減算を行う目的のほかにも、二つの日時同士の減算を行いその時間差を求める目的でも使うことができます。 日時同士の差を求めるため、このメソッドの戻り値は時間間隔を表すTimeSpanとなります。

このメソッドでDateTime同士の差を求める場合、時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として差が求められる点に注意が必要です。 DateTimeに設定されている時刻の種類も考慮して時間差を求めるには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上でSubstractメソッドを呼び出す必要があります。

DateTime.Subtractメソッドで2つの日時の時間間隔を求める
using System;

class Sample {
  static void Main()
  {
    // 日時aと日時bの時間差を求める
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 8, 30, 0);

    var diff = a.Subtract(b);

    Console.WriteLine(diff);

    // 一方はローカル時刻、もう一方はUTCの異なる時刻同士の差を求める
    var c = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local); // ローカル時刻
    var d = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc); // UTC

    diff = c.Subtract(d); // 時刻の種類は考慮されないため、時間差は0として計算される

    Console.WriteLine(diff);

    // 両者をUTCに統一して時刻同士の差を求める
    var uc = c.ToUniversalTime();
    var ud = d.ToUniversalTime();

    diff = uc.Subtract(ud);

    Console.WriteLine(diff);
  }
}
DateTime.Subtractメソッドで2つの日時の時間間隔を求める
Imports System

Class Sample
  Shared Sub Main()
    ' 日時aと日時bの時間差を求める
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 8, 30, 0)

    Dim diff As TimeSpan = a.Subtract(b)

    Console.WriteLine(diff)

    ' 一方はローカル時刻、もう一方はUTCの異なる時刻同士の差を求める
    Dim c As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local) ' ローカル時刻
    Dim d As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc) ' UTC

    diff = c.Subtract(d) ' 時刻の種類は考慮されないため、時間差は0として計算される

    Console.WriteLine(diff)

    ' 両者をUTCに統一して時刻同士の差を求める
    Dim uc As DateTime = c.ToUniversalTime()
    Dim ud As DateTime = d.ToUniversalTime()

    diff = uc.Subtract(ud)

    Console.WriteLine(diff)
  End Sub
End Class
実行結果
2.06:30:00
00:00:00
-09:00:00

一方DateTimeOffset同士の場合は、Substractメソッドでの減算時にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Substractメソッドでは内部的に一旦双方の値をUTCに変換した上でその差が求められます。

DateTimeOffset.Subtractメソッドで2つの日時の時間間隔を求める
using System;

class Sample {
  static void Main()
  {
    // 日時aと日時bの時間差を求める
    var a = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);
    var b = new DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero);

    var diff = a.Subtract(b);

    Console.WriteLine(diff);

    // 一方はUTC+9、もう一方はUTC+0の異なる時刻同士の差を求める
    var c = new DateTimeOffset(2013, 4, 5, 15, 0, 0, new TimeSpan(9, 0, 0));
    var d = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);

    diff = c.Subtract(d);

    Console.WriteLine(diff);
  }
}
DateTimeOffset.Subtractメソッドで2つの日時の時間間隔を求める
Imports System

Class Sample
  Shared Sub Main()
    ' 日時aと日時bの時間差を求める
    Dim a As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)
    Dim b As New DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero)

    Dim diff As TimeSpan = a.Subtract(b)

    Console.WriteLine(diff)

    ' 一方はUTC+9、もう一方はUTC+0の異なる時刻同士の差を求める
    Dim c As New DateTimeOffset(2013, 4, 5, 15, 0, 0, New TimeSpan(9, 0, 0))
    Dim d As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)

    diff = c.Subtract(d)

    Console.WriteLine(diff)
  End Sub
End Class
実行結果
2.06:30:00
-09:00:00

なお、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、Substractメソッドを呼び出す代わりに減算演算子を使うことも出来ます。 結果はSubstractメソッドを使う場合と同じです。

減算演算子を使って2つのDateTime/DateTimeOffsetの時間間隔を求める
using System;

class Sample {
  static void Main()
  {
    // DateTime同士の減算
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 8, 30, 0);

    Console.WriteLine(a - b); // == a.Subtract(b)

    // DateTimeOffset同士の減算
    var c = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);
    var d = new DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero);

    Console.WriteLine(c - d); // == c.Subtract(d)
  }
}
減算演算子を使って2つのDateTime/DateTimeOffsetの時間間隔を求める
Imports System

Class Sample
  Shared Sub Main()
    ' DateTime同士の減算
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 8, 30, 0)

    Console.WriteLine(a - b) ' == a.Subtract(b)

    ' DateTimeOffset同士の減算
    Dim c As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)
    Dim d As New DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero)

    Console.WriteLine(c - d) ' == c.Subtract(d)
  End Sub
End Class
実行結果
2.06:30:00
2.06:30:00

日時同士の比較

等価性の比較

二つのDateTime・DateTimeOffsetが等しいかどうか(同一の日時を表すかどうか)を調べるにはEqualsメソッドを使うことが出来ます。 このメソッドは、インスタンスメソッド・静的メソッドの二種類が用意されています。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、Equalsメソッドの代わりに等価演算子==・不等価演算子!=,<>を使って等価性の比較を行うことも出来ます。

Equalsメソッド(および等価・不等価演算子)でDateTime同士の比較を行う場合、DateTime同士の減算の場合と同様に時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として比較される点に注意が必要です。 二つのDateTime同士の比較においては、両者のTicksプロパティの値が同じであればDateTimeは等しいものとして扱われます。 そのため、DateTimeに設定されている時刻の種類も考慮して比較するには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上で比較を行う必要があります。

等価演算子・Equalsメソッドを使って2つのDateTimeが等しいかどうかを調べる
using System;

class Sample {
  static void Main()
  {
    // 二つのDateTimeを比較する
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 8, 30, 0);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a == b : {0}", a == b);
    Console.WriteLine("a != b : {0}", a != b);
    Console.WriteLine("a.Equals(b) : {0}", a.Equals(b));
    Console.WriteLine("DateTime.Equals(a, b) : {0}", DateTime.Equals(a, b));
    Console.WriteLine();

    // 一方はローカル時刻、もう一方はUTCの異なる時刻同士を比較する
    var c = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local); // ローカル時刻
    var d = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc); // UTC

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("d = {0}", d);
    Console.WriteLine("c == d : {0}", c == d);
    Console.WriteLine();

    // 両者をUTCに統一して時刻同士を比較する
    var uc = c.ToUniversalTime();
    var ud = d.ToUniversalTime();

    Console.WriteLine("uc = {0}", uc);
    Console.WriteLine("ud = {0}", ud);
    Console.WriteLine("uc == ud : {0}", uc == ud);
    Console.WriteLine();
  }
}
等価演算子・Equalsメソッドを使って2つのDateTimeが等しいかどうかを調べる
Imports System

Class Sample
  Shared Sub Main()
    ' 二つのDateTimeを比較する
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 8, 30, 0)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a = b : {0}", a = b)
    Console.WriteLine("a <> b : {0}", a <> b)
    Console.WriteLine("a.Equals(b) : {0}", a.Equals(b))
    Console.WriteLine("DateTime.Equals(a, b) : {0}", DateTime.Equals(a, b))
    Console.WriteLine()

    ' 一方はローカル時刻、もう一方はUTCの異なる時刻同士を比較する
    Dim c As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local) ' ローカル時刻
    Dim d As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc) ' UTC

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("d = {0}", d)
    Console.WriteLine("c = d : {0}", c = d)
    Console.WriteLine()

    ' 両者をUTCに統一して時刻同士を比較する
    Dim uc As DateTime = c.ToUniversalTime()
    Dim ud As DateTime = d.ToUniversalTime()

    Console.WriteLine("uc = {0}", uc)
    Console.WriteLine("ud = {0}", ud)
    Console.WriteLine("uc = ud : {0}", uc = ud)
    Console.WriteLine()
  End Sub
End Class
実行結果
a = 2013/04/05 15:00:00
b = 2013/04/03 8:30:00
a == b : False
a != b : True
a.Equals(b) : False
DateTime.Equals(a, b) : False

c = 2013/04/05 15:00:00
d = 2013/04/05 15:00:00
c == d : True

uc = 2013/04/05 6:00:00
ud = 2013/04/05 15:00:00
uc == ud : False

一方DateTimeOffset同士の場合は、Equalsメソッドでの比較の際にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Equalsメソッドでは内部的に一旦双方の値をUTCに変換した上で比較が行われます。 オフセット値も含めて完全に同一の日時かどうかを比較したい場合には、DateTimeOffset.EqualsExactメソッドを使うことが出来ます。

等価演算子・Equalsメソッド・EqualsExactメソッドを使って2つのDateTimeOffsetが等しいかどうかを調べる
using System;

class Sample {
  static void Main()
  {
    // 二つのDateTimeOffsetを比較する
    var a = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);
    var b = new DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a == b : {0}", a == b);
    Console.WriteLine("a != b : {0}", a != b);
    Console.WriteLine("a.Equals(b) : {0}", a.Equals(b));
    Console.WriteLine("DateTimeOffset.Equals(a, b) : {0}", DateTimeOffset.Equals(a, b));
    Console.WriteLine();

    // 一方はUTC+9、もう一方はUTC+0の異なる時刻同士を比較する
    var c = new DateTimeOffset(2013, 4, 5, 15, 0, 0, new TimeSpan(9, 0, 0));
    var d = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("d = {0}", d);
    Console.WriteLine("c == d : {0}", c == d);
    Console.WriteLine();

    // cと同一時刻でタイムゾーンが異なる時刻を比較する
    var e = new DateTimeOffset(2013, 4, 5, 1, 0, 0, new TimeSpan(-5, 0, 0));

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("e = {0}", e);
    Console.WriteLine("c.Equals(e)      : {0}", c.Equals(e));
    Console.WriteLine("c.EqualsExact(e) : {0}", c.EqualsExact(e));
  }
}
等価演算子・Equalsメソッド・EqualsExactメソッドを使って2つのDateTimeOffsetが等しいかどうかを調べる
Imports System

Class Sample
  Shared Sub Main()
    ' 二つのDateTimeOffsetを比較する
    Dim a As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)
    Dim b As New DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a = b : {0}", a = b)
    Console.WriteLine("a <> b : {0}", a <> b)
    Console.WriteLine("a.Equals(b) : {0}", a.Equals(b))
    Console.WriteLine("DateTimeOffset.Equals(a, b) : {0}", DateTimeOffset.Equals(a, b))
    Console.WriteLine()

    ' 一方はUTC+9、もう一方はUTC+0の異なる時刻同士を比較する
    Dim c As New DateTimeOffset(2013, 4, 5, 15, 0, 0, new TimeSpan(9, 0, 0))
    Dim d As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("d = {0}", d)
    Console.WriteLine("c = d : {0}", c = d)
    Console.WriteLine()

    ' cと同一時刻でタイムゾーンが異なる時刻を比較する
    Dim e As New DateTimeOffset(2013, 4, 5, 1, 0, 0, new TimeSpan(-5, 0, 0))

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("e = {0}", e)
    Console.WriteLine("c.Equals(e)      : {0}", c.Equals(e))
    Console.WriteLine("c.EqualsExact(e) : {0}", c.EqualsExact(e))
  End Sub
End Class
実行結果
a = 2013/04/05 15:00:00 +00:00
b = 2013/04/03 8:30:00 +00:00
a == b : False
a != b : True
a.Equals(b) : False
DateTimeOffset.Equals(a, b) : False

c = 2013/04/05 15:00:00 +09:00
d = 2013/04/05 15:00:00 +00:00
c == d : False

c = 2013/04/05 15:00:00 +09:00
e = 2013/04/05 1:00:00 -05:00
c.Equals(e)      : True
c.EqualsExact(e) : False

DateTime・DateTimeOffsetはIEquatableインターフェイスを実装しています。 IEquatableインターフェイスとより高度な等価性の比較処理については等価性の定義と比較も合わせてご覧ください。

大小関係の比較

二つのDateTime・DateTimeOffsetの大小関係(=日時の前後関係)を調べるには静的メソッドのCompareメソッド、インスタンスメソッドのCompareToメソッドを使うことが出来ます。 また、C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、等価性の比較と同様に比較演算子も使うことが出来ます。 次の表は、DateTime・DateTimeOffsetの大小関係を求めるためのメソッド・演算子の一覧です。

DateTime・DateTimeOffsetの大小関係を求めるメソッド・演算子
メソッド・演算子 動作
x > y xy よりも後の日時の場合に真(true)となる
x >= y xy よりも、もしくは等しい日時の場合に真(true)となる
x < y xy よりも前の日時の場合に真(true)となる
x <= y xy よりも、もしくは等しい日時の場合に真(true)となる
DateTime.Compare(x, y)
DateTimeOffset.Compare(x, y)
x.Compare(y)
x.Compare(y)
xy よりも後の日時(x > y)の場合、正の値を返す
xy同じ日時(x = y)の場合、0を返す
xy よりも前の日時(x < y)の場合、負の値を返す

Compare・CompareToメソッド(および比較演算子)でDateTime同士の比較を行う場合、DateTime同士の減算の場合と同様に時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として比較される点に注意が必要です。 二つのDateTime同士の比較結果は、両者のTicksプロパティの値の大小を比較したものと同じとなります。 DateTimeに設定されている時刻の種類も考慮して比較するには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上で比較を行う必要があります。

比較演算子・CompareToメソッドを使って2つのDateTimeの大小関係を調べる
using System;

class Sample {
  static void Main()
  {
    // 二つのDateTimeを比較する
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 8, 30, 0);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a > b : {0}", a > b);
    Console.WriteLine("a <= b : {0}", a <= b);
    Console.WriteLine("a.CompareTo(b) : {0}", a.CompareTo(b));
    Console.WriteLine("DateTime.Compare(b) : {0}", DateTime.Compare(a, b));
    Console.WriteLine();

    // 一方はローカル時刻、もう一方はUTCの異なる時刻同士を比較する
    var c = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local); // ローカル時刻
    var d = new DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc); // UTC

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("d = {0}", d);
    Console.WriteLine("c < d : {0}", c < d);
    Console.WriteLine("c > d : {0}", c > d);
    Console.WriteLine("DateTime.Compare(c, d) : {0}", DateTime.Compare(c, d));
    Console.WriteLine();

    // 両者をUTCに統一して時刻同士を比較する
    var uc = c.ToUniversalTime();
    var ud = d.ToUniversalTime();

    Console.WriteLine("uc = {0}", uc);
    Console.WriteLine("ud = {0}", ud);
    Console.WriteLine("uc < ud : {0}", uc < ud);
    Console.WriteLine("uc > ud : {0}", uc > ud);
    Console.WriteLine("DateTime.Compare(uc, ud) : {0}", DateTime.Compare(uc, ud));
    Console.WriteLine();
  }
}
比較演算子・CompareToメソッドを使って2つのDateTimeの大小関係を調べる
Imports System

Class Sample
  Shared Sub Main()
    ' 二つのDateTimeを比較する
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 8, 30, 0)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a > b : {0}", a > b)
    Console.WriteLine("a <= b : {0}", a <= b)
    Console.WriteLine("a.CompareTo(b) : {0}", a.CompareTo(b))
    Console.WriteLine("DateTime.Compare(b) : {0}", DateTime.Compare(a, b))
    Console.WriteLine()

    ' 一方はローカル時刻、もう一方はUTCの異なる時刻同士を比較する
    Dim c As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Local) ' ローカル時刻
    Dim d As New DateTime(2013, 4, 5, 15, 0, 0, DateTimeKind.Utc) ' UTC

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("d = {0}", d)
    Console.WriteLine("c < d : {0}", c < d)
    Console.WriteLine("c > d : {0}", c > d)
    Console.WriteLine("DateTime.Compare(c, d) : {0}", DateTime.Compare(c, d))
    Console.WriteLine()

    ' 両者をUTCに統一して時刻同士を比較する
    Dim uc As DateTime = c.ToUniversalTime()
    Dim ud As DateTime = d.ToUniversalTime()

    Console.WriteLine("uc = {0}", uc)
    Console.WriteLine("ud = {0}", ud)
    Console.WriteLine("uc < ud : {0}", uc < ud)
    Console.WriteLine("uc > ud : {0}", uc > ud)
    Console.WriteLine("DateTime.Compare(uc, ud) : {0}", DateTime.Compare(uc, ud))
    Console.WriteLine()
  End Sub
End Class
実行結果
a = 2013/04/05 15:00:00
b = 2013/04/03 8:30:00
a > b : True
a <= b : False
a.CompareTo(b) : 1
DateTime.Compare(b) : 1

c = 2013/04/05 15:00:00
d = 2013/04/05 15:00:00
c < d : False
c > d : False
DateTime.Compare(c, d) : 0

uc = 2013/04/05 6:00:00
ud = 2013/04/05 15:00:00
uc < ud : True
uc > ud : False
DateTime.Compare(uc, ud) : -1

一方DateTimeOffset同士の場合は、Compare・CompareToメソッドでの比較の際にオフセット値も考慮されるため、事前にローカル時刻またはUTCに変換する必要はありません。 Compare・CompareToメソッドでは内部的に一旦双方の値をUTCに変換した上で比較が行われます。

比較演算子・CompareToメソッドを使って2つのDateTimeOffsetの大小関係を調べる
using System;

class Sample {
  static void Main()
  {
    // 二つのDateTimeOffsetを比較する
    var a = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);
    var b = new DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a > b : {0}", a > b);
    Console.WriteLine("a < b : {0}", a < b);
    Console.WriteLine("a.CompareTo(b) : {0}", a.CompareTo(b));
    Console.WriteLine("DateTimeOffset.Compare(a, b) : {0}", DateTimeOffset.Compare(a, b));
    Console.WriteLine();

    // 一方はUTC+9、もう一方はUTC+0の異なる時刻同士を比較する
    var c = new DateTimeOffset(2013, 4, 5, 15, 0, 0, new TimeSpan(9, 0, 0));
    var d = new DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero);

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("d = {0}", d);
    Console.WriteLine("c < d : {0}", c > d);
    Console.WriteLine("c > d : {0}", c < d);
    Console.WriteLine("DateTimeOffset.Compare(c, d) : {0}", DateTimeOffset.Compare(c, d));
    Console.WriteLine();

    // cと同一時刻でタイムゾーンが異なる時刻を比較する
    var e = new DateTimeOffset(2013, 4, 5, 1, 0, 0, new TimeSpan(-5, 0, 0));

    Console.WriteLine("c = {0}", c);
    Console.WriteLine("e = {0}", e);
    Console.WriteLine("c < e : {0}", c > e);
    Console.WriteLine("c > e : {0}", c < e);
    Console.WriteLine("DateTimeOffset.Compare(c, e) : {0}", DateTimeOffset.Compare(c, e));
  }
}
比較演算子・CompareToメソッドを使って2つのDateTimeOffsetの大小関係を調べる
Imports System

Class Sample
  Shared Sub Main()
    ' 二つのDateTimeOffsetを比較する
    Dim a As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)
    Dim b As New DateTimeOffset(2013, 4, 3, 8, 30, 0, TimeSpan.Zero)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a > b : {0}", a > b)
    Console.WriteLine("a < b : {0}", a < b)
    Console.WriteLine("a.CompareTo(b) : {0}", a.CompareTo(b))
    Console.WriteLine("DateTimeOffset.Compare(a, b) : {0}", DateTimeOffset.Compare(a, b))
    Console.WriteLine()

    ' 一方はUTC+9、もう一方はUTC+0の異なる時刻同士を比較する
    Dim c As New DateTimeOffset(2013, 4, 5, 15, 0, 0, new TimeSpan(9, 0, 0))
    Dim d As New DateTimeOffset(2013, 4, 5, 15, 0, 0, TimeSpan.Zero)

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("d = {0}", d)
    Console.WriteLine("c < d : {0}", c > d)
    Console.WriteLine("c > d : {0}", c < d)
    Console.WriteLine("DateTimeOffset.Compare(c, d) : {0}", DateTimeOffset.Compare(c, d))
    Console.WriteLine()

    ' cと同一時刻でタイムゾーンが異なる時刻を比較する
    Dim e As New DateTimeOffset(2013, 4, 5, 1, 0, 0, new TimeSpan(-5, 0, 0))

    Console.WriteLine("c = {0}", c)
    Console.WriteLine("e = {0}", e)
    Console.WriteLine("c < e : {0}", c > e)
    Console.WriteLine("c > e : {0}", c < e)
    Console.WriteLine("DateTimeOffset.Compare(c, e) : {0}", DateTimeOffset.Compare(c, e))
  End Sub
End Class
実行結果
a = 2013/04/05 15:00:00 +00:00
b = 2013/04/03 8:30:00 +00:00
a > b : True
a < b : False
a.CompareTo(b) : 1
DateTimeOffset.Compare(a, b) : 1

c = 2013/04/05 15:00:00 +09:00
d = 2013/04/05 15:00:00 +00:00
c < d : False
c > d : True
DateTimeOffset.Compare(c, d) : -1

c = 2013/04/05 15:00:00 +09:00
e = 2013/04/05 1:00:00 -05:00
c < e : False
c > e : False
DateTimeOffset.Compare(c, e) : 0

DateTime・DateTimeOffsetはIComparableインターフェイスを実装しています。 IComparableインターフェイスとより高度な大小関係の比較処理については大小関係の定義と比較もご覧ください。

DateTime・DateTimeOffsetとソートについては基本型のソートと昇順・降順でのソートおよび基本型とデフォルトのソート順 §.日付型をご覧ください。

日付のみ・時刻のみの比較

DateTime・DateTimeOffsetの日付のみ・時刻のみを比較するメソッドは用意されていませんが、Dateプロパティで日付のみ、TimeOfDayプロパティで時刻のみを取得できるため、これを使って比較することが出来ます。

なお、DateTimeの時刻の種類(Kindプロパティの値)はDateTime.Dateプロパティが返す値には影響しませんが、DateTimeOffset.DateプロパティはDateTimeOffsetに設定されているオフセット値を加算した上での日付を返す点に注意が必要です。

Dateプロパティを使って2つのDateTimeの日付のみを比較する
using System;

class Sample {
  static void Main()
  {
    // 各DateTimeの日付のみを比較する
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 0, 0, 0, DateTimeKind.Local);
    var c = new DateTime(2013, 4, 3, 8, 30, 0, DateTimeKind.Utc);

    Console.WriteLine("a      = {0}", a);
    Console.WriteLine("b      = {0}", b);
    Console.WriteLine("c      = {0}", c);
    Console.WriteLine("a.Date = {0}", a.Date);
    Console.WriteLine("b.Date = {0}", b.Date);
    Console.WriteLine("c.Date = {0}", c.Date);

    Console.WriteLine("DateTime.Compare(a, b)      : {0}", DateTime.Compare(a, b));
    Console.WriteLine("DateTime.Compare(b, c)      : {0}", DateTime.Compare(b, c));
    Console.WriteLine("DateTime.Compare(c, a)      : {0}", DateTime.Compare(c, a));
    Console.WriteLine("DateTime.Compare(a.Date, b.Date) : {0}", DateTime.Compare(a.Date, b.Date));
    Console.WriteLine("DateTime.Compare(b.Date, c.Date) : {0}", DateTime.Compare(b.Date, c.Date));
    Console.WriteLine("DateTime.Compare(c.Date, a.Date) : {0}", DateTime.Compare(c.Date, a.Date));
    Console.WriteLine();
  }
}
Dateプロパティを使って2つのDateTimeの日付のみを比較する
Imports System

Class Sample
  Shared Sub Main()
    ' 各DateTimeの日付のみを比較する
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 0, 0, 0, DateTimeKind.Local)
    Dim c As New DateTime(2013, 4, 3, 8, 30, 0, DateTimeKind.Utc)

    Console.WriteLine("a      = {0}", a)
    Console.WriteLine("b      = {0}", b)
    Console.WriteLine("c      = {0}", c)
    Console.WriteLine("a.Date = {0}", a.Date)
    Console.WriteLine("b.Date = {0}", b.Date)
    Console.WriteLine("c.Date = {0}", c.Date)

    Console.WriteLine("DateTime.Compare(a, b)      : {0}", DateTime.Compare(a, b))
    Console.WriteLine("DateTime.Compare(b, c)      : {0}", DateTime.Compare(b, c))
    Console.WriteLine("DateTime.Compare(c, a)      : {0}", DateTime.Compare(c, a))
    Console.WriteLine("DateTime.Compare(a.Date, b.Date) : {0}", DateTime.Compare(a.Date, b.Date))
    Console.WriteLine("DateTime.Compare(b.Date, c.Date) : {0}", DateTime.Compare(b.Date, c.Date))
    Console.WriteLine("DateTime.Compare(c.Date, a.Date) : {0}", DateTime.Compare(c.Date, a.Date))
    Console.WriteLine()
  End Sub
End Class
実行結果
a      = 2013/04/05 15:00:00
b      = 2013/04/03 0:00:00
c      = 2013/04/03 8:30:00
a.Date = 2013/04/05 0:00:00
b.Date = 2013/04/03 0:00:00
c.Date = 2013/04/03 0:00:00
DateTime.Compare(a, b) : 1
DateTime.Compare(b, c) : -1
DateTime.Compare(c, a) : -1
DateTime.Compare(a.Date, b.Date) : 1
DateTime.Compare(b.Date, c.Date) : 0
DateTime.Compare(c.Date, a.Date) : -1
Dateプロパティを使って2つのDateTimeOffsetの日付のみを比較する
using System;

class Sample {
  static void Main()
  {
    // 各DateTimeOffsetの日付のみを比較する
    var a = new DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0));
    var b = new DateTimeOffset(2013, 4, 4, 21, 0, 0, TimeSpan.Zero);
    var c = new DateTimeOffset(2013, 4, 4, 16, 0, 0, new TimeSpan(-5, 0, 0));

    Console.WriteLine("a      = {0}", a);
    Console.WriteLine("b      = {0}", b);
    Console.WriteLine("c      = {0}", c);
    Console.WriteLine("a.Date = {0}", a.Date);
    Console.WriteLine("b.Date = {0}", b.Date);
    Console.WriteLine("c.Date = {0}", c.Date);

    Console.WriteLine("DateTimeOffset.Compare(a, b) : {0}", DateTimeOffset.Compare(a, b));
    Console.WriteLine("DateTimeOffset.Compare(b, c) : {0}", DateTimeOffset.Compare(b, c));
    Console.WriteLine("DateTimeOffset.Compare(c, a) : {0}", DateTimeOffset.Compare(c, a));
    Console.WriteLine("DateTime.Compare(a.Date, b.Date) : {0}", DateTime.Compare(a.Date, b.Date));
    Console.WriteLine("DateTime.Compare(b.Date, c.Date) : {0}", DateTime.Compare(b.Date, c.Date));
    Console.WriteLine("DateTime.Compare(c.Date, a.Date) : {0}", DateTime.Compare(c.Date, a.Date));
  }
}
Dateプロパティを使って2つのDateTimeOffsetの日付のみを比較する
Imports System

Class Sample
  Shared Sub Main()
    ' 各DateTimeOffsetの日付のみを比較する
    Dim a As New DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0))
    Dim b As New DateTimeOffset(2013, 4, 4, 21, 0, 0, TimeSpan.Zero)
    Dim c As New DateTimeOffset(2013, 4, 4, 16, 0, 0, new TimeSpan(-5, 0, 0))

    Console.WriteLine("a      = {0}", a)
    Console.WriteLine("b      = {0}", b)
    Console.WriteLine("c      = {0}", c)
    Console.WriteLine("a.Date = {0}", a.Date)
    Console.WriteLine("b.Date = {0}", b.Date)
    Console.WriteLine("c.Date = {0}", c.Date)

    Console.WriteLine("DateTimeOffset.Compare(a, b) : {0}", DateTimeOffset.Compare(a, b))
    Console.WriteLine("DateTimeOffset.Compare(b, c) : {0}", DateTimeOffset.Compare(b, c))
    Console.WriteLine("DateTimeOffset.Compare(c, a) : {0}", DateTimeOffset.Compare(c, a))
    Console.WriteLine("DateTime.Compare(a.Date, b.Date) : {0}", DateTime.Compare(a.Date, b.Date))
    Console.WriteLine("DateTime.Compare(b.Date, c.Date) : {0}", DateTime.Compare(b.Date, c.Date))
    Console.WriteLine("DateTime.Compare(c.Date, a.Date) : {0}", DateTime.Compare(c.Date, a.Date))
  End Sub
End Class
実行結果
a      = 2013/04/05 6:00:00 +09:00
b      = 2013/04/04 21:00:00 +00:00
c      = 2013/04/04 16:00:00 -05:00
a.Date = 2013/04/05 0:00:00
b.Date = 2013/04/04 0:00:00
c.Date = 2013/04/04 0:00:00
DateTimeOffset.Compare(a, b) : 0
DateTimeOffset.Compare(b, c) : 0
DateTimeOffset.Compare(c, a) : 0
DateTime.Compare(a.Date, b.Date) : 1
DateTime.Compare(b.Date, c.Date) : 0
DateTime.Compare(c.Date, a.Date) : -1

Dateプロパティとは異なり、DateTime.TimeOfDayプロパティおよびDateTimeOffset.TimeOfDayプロパティが返す値は、どちらも時刻の種類(Kindプロパティ)・オフセット値(Offsetプロパティ)の影響を受けず、時刻部分の値がそのままの値で返されます。 なお、TimeOfDayプロパティはTimeSpan型で時刻を返すため、メソッドを使って比較する場合はDateTime.CompareではなくTimeSpan.Compareを使います(TimeSpan.Compareのかわりに比較演算子を使って比較することもできます)。

TimeOfDayプロパティを使って2つのDateTimeの時刻のみを比較する
using System;

class Sample {
  static void Main()
  {
    // 各DateTimeの時刻のみを比較する
    var a = new DateTime(2013, 4, 5, 15, 0, 0);
    var b = new DateTime(2013, 4, 3, 0, 0, 0, DateTimeKind.Local);
    var c = new DateTime(2013, 4, 3, 8, 30, 0, DateTimeKind.Utc);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("c = {0}", c);
    Console.WriteLine("a.TimeOfDay = {0}", a.TimeOfDay);
    Console.WriteLine("b.TimeOfDay = {0}", b.TimeOfDay);
    Console.WriteLine("c.TimeOfDay = {0}", c.TimeOfDay);

    Console.WriteLine("a.TimeOfDay < b.TimeOfDay : {0}", a.TimeOfDay < b.TimeOfDay);
    Console.WriteLine("b.TimeOfDay < c.TimeOfDay : {0}", b.TimeOfDay < c.TimeOfDay);
    Console.WriteLine("c.TimeOfDay < a.TimeOfDay : {0}", c.TimeOfDay < a.TimeOfDay);
    Console.WriteLine("TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : {0}", TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay));
    Console.WriteLine("TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : {0}", TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay));
    Console.WriteLine("TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : {0}", TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay));
  }
}
TimeOfDayプロパティを使って2つのDateTimeの時刻のみを比較する
Imports System

Class Sample
  Shared Sub Main()
    ' 各DateTimeの時刻のみを比較する
    Dim a As New DateTime(2013, 4, 5, 15, 0, 0)
    Dim b As New DateTime(2013, 4, 3, 0, 0, 0, DateTimeKind.Local)
    Dim c As New DateTime(2013, 4, 3, 8, 30, 0, DateTimeKind.Utc)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("c = {0}", c)
    Console.WriteLine("a.TimeOfDay = {0}", a.TimeOfDay)
    Console.WriteLine("b.TimeOfDay = {0}", b.TimeOfDay)
    Console.WriteLine("c.TimeOfDay = {0}", c.TimeOfDay)

    Console.WriteLine("a.TimeOfDay < b.TimeOfDay : {0}", a.TimeOfDay < b.TimeOfDay)
    Console.WriteLine("b.TimeOfDay < c.TimeOfDay : {0}", b.TimeOfDay < c.TimeOfDay)
    Console.WriteLine("c.TimeOfDay < a.TimeOfDay : {0}", c.TimeOfDay < a.TimeOfDay)
    Console.WriteLine("TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : {0}", TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay))
    Console.WriteLine("TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : {0}", TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay))
    Console.WriteLine("TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : {0}", TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay))
  End Sub
End Class
実行結果
a = 2013/04/05 15:00:00
b = 2013/04/03 0:00:00
c = 2013/04/03 8:30:00
a.TimeOfDay = 15:00:00
b.TimeOfDay = 00:00:00
c.TimeOfDay = 08:30:00
a.TimeOfDay < b.TimeOfDay : False
b.TimeOfDay < c.TimeOfDay : True
c.TimeOfDay < a.TimeOfDay : True
TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : 1
TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : -1
TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : -1
TimeOfDayプロパティを使って2つのDateTimeOffsetの時刻のみを比較する
using System;

class Sample {
  static void Main()
  {
    // 各DateTimeOffsetの時刻のみを比較する
    var a = new DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0));
    var b = new DateTimeOffset(2013, 4, 4, 21, 0, 0, TimeSpan.Zero);
    var c = new DateTimeOffset(2013, 4, 4, 16, 0, 0, new TimeSpan(-5, 0, 0));

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("c = {0}", c);
    Console.WriteLine("a.TimeOfDay = {0}", a.TimeOfDay);
    Console.WriteLine("b.TimeOfDay = {0}", b.TimeOfDay);
    Console.WriteLine("c.TimeOfDay = {0}", c.TimeOfDay);

    Console.WriteLine("a.TimeOfDay < b.TimeOfDay : {0}", a.TimeOfDay < b.TimeOfDay);
    Console.WriteLine("b.TimeOfDay < c.TimeOfDay : {0}", b.TimeOfDay < c.TimeOfDay);
    Console.WriteLine("c.TimeOfDay < a.TimeOfDay : {0}", c.TimeOfDay < a.TimeOfDay);
    Console.WriteLine("TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : {0}", TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay));
    Console.WriteLine("TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : {0}", TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay));
    Console.WriteLine("TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : {0}", TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay));
  }
}
TimeOfDayプロパティを使って2つのDateTimeOffsetの時刻のみを比較する
Imports System

Class Sample
  Shared Sub Main()
    ' 各DateTimeOffsetの時刻のみを比較する
    Dim a As New DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0))
    Dim b As New DateTimeOffset(2013, 4, 4, 21, 0, 0, TimeSpan.Zero)
    Dim c As New DateTimeOffset(2013, 4, 4, 16, 0, 0, new TimeSpan(-5, 0, 0))

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("c = {0}", c)
    Console.WriteLine("a.TimeOfDay = {0}", a.TimeOfDay)
    Console.WriteLine("b.TimeOfDay = {0}", b.TimeOfDay)
    Console.WriteLine("c.TimeOfDay = {0}", c.TimeOfDay)

    Console.WriteLine("a.TimeOfDay < b.TimeOfDay : {0}", a.TimeOfDay < b.TimeOfDay)
    Console.WriteLine("b.TimeOfDay < c.TimeOfDay : {0}", b.TimeOfDay < c.TimeOfDay)
    Console.WriteLine("c.TimeOfDay < a.TimeOfDay : {0}", c.TimeOfDay < a.TimeOfDay)
    Console.WriteLine("TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : {0}", TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay))
    Console.WriteLine("TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : {0}", TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay))
    Console.WriteLine("TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : {0}", TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay))
  End Sub
End Class
実行結果
a = 2013/04/05 6:00:00 +09:00
b = 2013/04/04 21:00:00 +00:00
c = 2013/04/04 16:00:00 -05:00
a.TimeOfDay = 06:00:00
b.TimeOfDay = 21:00:00
c.TimeOfDay = 16:00:00
a.TimeOfDay < b.TimeOfDay : True
b.TimeOfDay < c.TimeOfDay : False
c.TimeOfDay < a.TimeOfDay : False
TimeSpan.Compare(a.TimeOfDay, b.TimeOfDay) : -1
TimeSpan.Compare(b.TimeOfDay, c.TimeOfDay) : 1
TimeSpan.Compare(c.TimeOfDay, a.TimeOfDay) : 1

日付のみ・時刻のみのソート

Array.SortメソッドなどでDateTime・DateTimeOffsetをソートする場合、デフォルトでは日時の小さい順(古い順)にソートされます。 日付を無視して時刻のみの大小関係でソートしたい場合は、次のようにTimeOfDayプロパティの値を比較するメソッドを用意してそれをSortメソッドに渡すようにします。

DateTimeOffsetの時刻のみを比較してソートする
using System;

class Sample {
  // DateTimeOffsetのTimeOfDayプロパティを比較するメソッド
  static int CompareTimeOfDay(DateTimeOffset x, DateTimeOffset y)
  {
    return TimeSpan.Compare(x.TimeOfDay, y.TimeOfDay);
  }

  static void Main()
  {
    var a = new DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0));
    var b = new DateTimeOffset(2013, 4, 4, 8, 0, 0, TimeSpan.Zero);
    var c = new DateTimeOffset(2013, 4, 3, 11, 0, 0, new TimeSpan(-5, 0, 0));

    var arr = new DateTimeOffset[] {a, b, c};

    // デフォルトの順序(日時の小さい順)でソート
    Array.Sort(arr);

    foreach (var dto in arr) {
      Console.WriteLine("{0} (UTC: {1})", dto, dto.ToUniversalTime());
    }
    Console.WriteLine();

    // 時刻のみを比較してソート
    Array.Sort(arr, CompareTimeOfDay);

    foreach (var dto in arr) {
      Console.WriteLine("{0} (TimeOfDay: {1})", dto, dto.TimeOfDay);
    }
    Console.WriteLine();
  }
}
DateTimeOffsetの時刻のみを比較してソートする
Imports System

Class Sample
  ' DateTimeOffsetのTimeOfDayプロパティを比較するメソッド
  Shared Function CompareTimeOfDay(ByVal x As DateTimeOffset, ByVal y As DateTimeOffset) As Integer
    Return TimeSpan.Compare(x.TimeOfDay, y.TimeOfDay)
  End Function

  Shared Sub Main()
    Dim a As New DateTimeOffset(2013, 4, 5, 6, 0, 0, new TimeSpan(9, 0, 0))
    Dim b As New DateTimeOffset(2013, 4, 4, 8, 0, 0, TimeSpan.Zero)
    Dim c As New DateTimeOffset(2013, 4, 3, 11, 0, 0, new TimeSpan(-5, 0, 0))

    Dim arr() As DateTimeOffset = New DateTimeOffset() {a, b, c}

    ' デフォルトの順序(日時の小さい順)でソート
    Array.Sort(arr)

    For Each dto As DateTimeOffset In arr
      Console.WriteLine("{0} (UTC: {1})", dto, dto.ToUniversalTime())
    Next
    Console.WriteLine()

    ' 時刻のみを比較してソート
    Array.Sort(arr, AddressOf CompareTimeOfDay)

    For Each dto As DateTimeOffset In arr
      Console.WriteLine("{0} (TimeOfDay: {1})", dto, dto.TimeOfDay)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
2013/04/03 11:00:00 -05:00 (UTC: 2013/04/03 16:00:00 +00:00)
2013/04/04 8:00:00 +00:00 (UTC: 2013/04/04 8:00:00 +00:00)
2013/04/05 6:00:00 +09:00 (UTC: 2013/04/04 21:00:00 +00:00)

2013/04/05 6:00:00 +09:00 (TimeOfDay: 06:00:00)
2013/04/04 8:00:00 +00:00 (TimeOfDay: 08:00:00)
2013/04/03 11:00:00 -05:00 (TimeOfDay: 11:00:00)

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.ToUnixTimeSecondsFromUnixTimeSecondsメソッドは、日時の値をUNIX時間(UNIXタイムスタンプ)として使われるlong型(64ビット)の値に変換します。

UNIX時間はUTCでの時刻と定義されているため、ToUnixTimeSecondsではUTCに変換された上での値が返されます。 また、FromUnixTimeSecondsメソッドでこの値を変換すると、Offsetプロパティが+00:00のDateTimeOffsetが返されます。 UNIX時間からDateTimeOffsetに変換した値を、さらにローカル時間として取得したい場合はToLocalTimeメソッドを使用することができます。

DateTimeOffset.ToUnixTimeSeconds/FromUnixTimeSecondsメソッドで日時⇄UNIX時間の変換をする .NET Framework 4.6
using System;

class Sample {
  static void Main()
  {
    var dto = new DateTimeOffset(2009, 02, 13, 23, 31, 30, new TimeSpan(+00, 00, 00));

    // DateTimeOffsetからUNIX時間へ変換する
    Console.WriteLine(dto.ToUnixTimeSeconds());

    // 2038-01-19T03:14:07+00:00をUNIX時間に変換する
    Console.WriteLine((new DateTimeOffset(2038, 01, 19, 03, 14, 07, new TimeSpan(+00, 00, 00))).ToUnixTimeSeconds());

    // 2038-01-19T12:14:07+09:00をUNIX時間に変換する
    Console.WriteLine((new DateTimeOffset(2038, 01, 19, 12, 14, 07, new TimeSpan(+09, 00, 00))).ToUnixTimeSeconds());

    Console.WriteLine();


    // UNIX時間からDateTimeOffsetへ変換する (オフセット値は+00:00になる)
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L));

    // UNIX時間からDateTimeOffsetへ、さらにローカル時間に変換する
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L).ToLocalTime());

    // 32ビット符号付き整数の最大値を変換する
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds((long)int.MaxValue));
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds((long)int.MaxValue).ToLocalTime());
  }
}
DateTimeOffset.ToUnixTimeSeconds/FromUnixTimeSecondsメソッドで日時⇄UNIX時間の変換をする .NET Framework 4.6
Imports System

Class Sample
  Shared Sub Main()
    Dim dto As New DateTimeOffset(2009, 02, 13, 23, 31, 30, New TimeSpan(+00, 00, 00))

    ' DateTimeOffsetからUNIX時間へ変換する
    Console.WriteLine(dto.ToUnixTimeSeconds())

    ' 2038-01-19T03:14:07+00:00をUNIX時間に変換する
    Console.WriteLine((New DateTimeOffset(2038, 01, 19, 03, 14, 07, New TimeSpan(+00, 00, 00))).ToUnixTimeSeconds())

    ' 2038-01-19T12:14:07+09:00をUNIX時間に変換する
    Console.WriteLine((New DateTimeOffset(2038, 01, 19, 12, 14, 07, New TimeSpan(+09, 00, 00))).ToUnixTimeSeconds())

    Console.WriteLine()


    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L).ToLocalTime());


    ' UNIX時間からDateTimeOffsetへ変換する (オフセット値は+00:00になる)
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L))

    ' UNIX時間からDateTimeOffsetへ、さらにローカル時間に変換する
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(1000000000L).ToLocalTime())

    ' 32ビット符号付き整数の最大値を変換する
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(CLng(Integer.MaxValue)))
    Console.WriteLine(DateTimeOffset.FromUnixTimeSeconds(CLng(Integer.MaxValue)).ToLocalTime())
  End Sub
End Class
出力例
1234567890
2147483647
2147483647

2001/09/09 1:46:40 +00:00
2001/09/09 10:46:40 +09:00
2038/01/19 3:14:07 +00:00
2038/01/19 12:14:07 +09:00

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以降で使用することができます。

DateTime/DateTimeOffset.UnixEpochフィールドを参照してunix epochの日時を取得する .NET Standard 2.1/.NET Core 2.1
using System;

class Sample {
  static void Main()
  {
    // unix epochをDateTimeOffset/DateTimeの値で取得する
    Console.WriteLine(DateTimeOffset.UnixEpoch);
    Console.WriteLine($"{DateTime.UnixEpoch} ({DateTime.UnixEpoch.Kind})");
    Console.WriteLine();

    // 日時がunix epochより前のものかどうか調べる
    var dto = new DateTimeOffset(1969, 7, 20, 20, 17, 39, TimeSpan.Zero);

    if (dto < DateTimeOffset.UnixEpoch)
      Console.WriteLine($"{dto}はunix epochより前の日時です");
  }
}
DateTime/DateTimeOffset.UnixEpochフィールドを参照してunix epochの日時を取得する .NET Standard 2.1/.NET Core 2.1
Imports System

Class Sample
  Shared Sub Main()
    ' unix epochをDateTimeOffset/DateTimeの値で取得する
    Console.WriteLine(DateTimeOffset.UnixEpoch)
    Console.WriteLine($"{DateTime.UnixEpoch} ({DateTime.UnixEpoch.Kind})")
    Console.WriteLine()

    ' 日時がunix epochより前のものかどうか調べる
    Dim dto As New DateTimeOffset(1969, 7, 20, 20, 17, 39, TimeSpan.Zero)

    If dto < DateTimeOffset.UnixEpoch Then
      Console.WriteLine($"{dto}はunix epochより前の日時です")
    End If
  End Sub
End Class
実行結果
1970/01/01 0:00:00 +00:00
1970/01/01 0:00:00 (Utc)

1969/07/20 20:17:39 +00:00はunix epochより前の日時です

ToFileTime/FromFileTime

ToFileTimeFromFileTimeメソッドは、日時の値をWindowsのファイルタイムスタンプで使われるlong型(64ビット)の値に変換します。

タイムスタンプはUTCでの時刻とされているため、ToFileTimeメソッドではUTCに変換された上での値が返されます。 FromFileTimeメソッドでこの値を変換すると、UTCからローカル時刻に変換された(KindプロパティがDateTimeKind.Localの)DateTimeが返されます。 一方、FromFileTimeUtcメソッドで変換すると、UTC(KindプロパティがDateTimeKind.Utc)のDateTimeが返されます。

DateTimeOffset.FromFileTimeメソッドでは、返されるDateTimeOffsetのOffsetプロパティには常にローカル時刻のオフセットが設定されます。

DateTime.ToFileTime/FromFileTimeメソッドで日時⇄ファイルタイムスタンプ値の変換をする
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now;
    var ts = dt.ToFileTime(); // DateTimeをファイルタイムスタンプの値に変換

    Console.WriteLine("{0:o} -> {1}", dt, ts);
    Console.WriteLine("{0} -> {1:o}", ts, DateTime.FromFileTime(ts));     // ファイルタイムスタンプの値をローカル時刻のDateTimeに変換
    Console.WriteLine("{0} -> {1:o}", ts, DateTime.FromFileTimeUtc(ts));  // ファイルタイムスタンプの値をUTCのDateTimeに変換
    Console.WriteLine();

    var dto = DateTimeOffset.Now;
    ts = dto.ToFileTime(); // DateTimeOffsetをファイルタイムスタンプの値に変換

    Console.WriteLine("{0} -> {1}", dto, ts);
    Console.WriteLine("{0} -> {1}", ts, DateTimeOffset.FromFileTime(ts)); // ファイルタイムスタンプの値をDateTimeOffsetに変換
  }
}
DateTime.ToFileTime/FromFileTimeメソッドで日時⇄ファイルタイムスタンプ値の変換をする
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now
    Dim ts As Long = dt.ToFileTime() ' DateTimeをファイルタイムスタンプの値に変換

    Console.WriteLine("{0:o} -> {1}", dt, ts)
    Console.WriteLine("{0} -> {1:o}", ts, DateTime.FromFileTime(ts))     ' ファイルタイムスタンプの値をローカル時刻のDateTimeに変換
    Console.WriteLine("{0} -> {1:o}", ts, DateTime.FromFileTimeUtc(ts))  ' ファイルタイムスタンプの値をUTCのDateTimeに変換
    Console.WriteLine()

    Dim dto As DateTimeOffset = DateTimeOffset.Now
    ts = dto.ToFileTime() ' DateTimeOffsetをファイルタイムスタンプの値に変換

    Console.WriteLine("{0} -> {1}", dto, ts)
    Console.WriteLine("{0} -> {1}", ts, DateTimeOffset.FromFileTime(ts)) ' ファイルタイムスタンプの値をDateTimeOffsetに変換
  End Sub
End Class
実行結果例
2013-04-01T15:00:30.1230000+09:00 -> 130092696301230000
130092696301230000 -> 2013-04-01T15:00:30.1230000+09:00
130092696301230000 -> 2013-04-01T06:00:30.1230000Z

2013/04/01 15:00:30 +09:00 -> 130092696301230000
130092696301230000 -> 2013/04/01 15:00:30 +09:00

なお、File.SetLastWriteTimeなどFileクラスのタイムスタンプを設定・取得を行うメソッドでは、引数の型がDateTimeとなっています。 そのため、これらのメソッドを使ってタイムスタンプを変更する場合は、わざわざToFileTime・FromFileTimeメソッドを使って値の変換を必要はありません。

ファイルタイムスタンプで表現できる最小(最古)の日時は1601年01月01日 00:00:00(UTC)でありDateTimeで扱える範囲よりも狭いため、その範囲を越える値を変換しようとした場合はArgumentOutOfRangeExceptionがスローされます。

ToBinary/FromBinary

ToBinaryFromBinaryメソッドは、日時の値をlong型(64ビット)の値に変換します。 このメソッドでは、DateTime.TicksプロパティおよびDateTime.Kindプロパティの値を64ビットのバイナリ値として格納したフォーマットが用いられます。 そのため、日時をバイナリデータとして保存・復元したい場合にはこのメソッドを使うことが出来ます。

DateTime.ToBinary/FromBinaryメソッドで日時⇄64ビットバイナリ値の変換をする
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now; // ローカル時刻
    var binary = dt.ToBinary();

    Console.WriteLine("{0:o} -> {1:x16}", dt, binary);
    Console.WriteLine("{0:x16} -> {1:o}", binary, DateTime.FromBinary(binary));
    Console.WriteLine();

    dt = DateTime.UtcNow; // UTC
    binary = dt.ToBinary();

    Console.WriteLine("{0:o} -> {1:x16}", dt, binary);
    Console.WriteLine("{0:x16} -> {1:o}", binary, DateTime.FromBinary(binary));
  }
}
DateTime.ToBinary/FromBinaryメソッドで日時⇄64ビットバイナリ値の変換をする
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now ' ローカル時刻
    Dim binary As Long = dt.ToBinary()

    Console.WriteLine("{0:o} -> {1:x16}", dt, binary)
    Console.WriteLine("{0:x16} -> {1:o}", binary, DateTime.FromBinary(binary))
    Console.WriteLine()

    dt = DateTime.UtcNow ' UTC
    binary = dt.ToBinary()

    Console.WriteLine("{0:o} -> {1:x16}", dt, binary)
    Console.WriteLine("{0:x16} -> {1:o}", binary, DateTime.FromBinary(binary))
  End Sub
End Class
実行結果例
2013-04-01T15:00:30.1230000+09:00 -> 88cffcb5595f57b0
88cffcb5595f57b0 -> 2013-04-01T15:00:30.1230000+09:00

2013-04-01T06:00:30.1230000Z -> 48cffcb5595f57b0
48cffcb5595f57b0 -> 2013-04-01T06:00:30.1230000Z

DateTimeOffsetにはToBinary・FromBinaryメソッドは用意されていません。 DateTimeOffsetのバイナリ表現が必要な場合は、DateTimeOffset.TicksプロパティおよびDateTimeOffset.Offsetプロパティの値をそれぞれ変換・復元します。

ローカル時刻(KindプロパティがDateTimeKind.Local)のDateTimeをToBinaryメソッドで変換し、その値を変換時とは異なるタイムゾーンの環境で復元する場合、復元する環境のタイムゾーンでのローカル時刻として復元される点に注意が必要です。 これを避けるには、あらかじめ日時をUTCに変換しておく必要があります。

ToOADate/FromOADate

ToOADateFromOADateメソッドは、日時の値をOLEオートメーション日時(double型・64ビット)の値に変換します。 このフォーマットでは時刻の種類は無視され、日時のみが変換されるという点に注意が必要です。 その他フォーマットの詳細などはToOADateメソッドのドキュメントを参照してください。

DateTime.ToOADate/FromOADateメソッドで日時⇄OLEオートメーション日時の変換をする
using System;

class Sample {
  static void Main()
  {
    var dt = DateTime.Now;
    var oadate = dt.ToOADate();

    Console.WriteLine("{0:o} -> {1}", dt, oadate);
    Console.WriteLine("{0} -> {1:o}", oadate, DateTime.FromOADate(oadate));
  }
}
DateTime.ToOADate/FromOADateメソッドで日時⇄OLEオートメーション日時の変換をする
Imports System

Class Sample
  Shared Sub Main()
    Dim dt As DateTime = DateTime.Now
    Dim oadate As Double = dt.ToOADate()

    Console.WriteLine("{0:o} -> {1}", dt, oadate)
    Console.WriteLine("{0} -> {1:o}", oadate, DateTime.FromOADate(oadate))
  End Sub
End Class
実行結果例
2013-04-01T15:00:30.1230000+09:00 -> 41365.6253486458
41365.6253486458 -> 2013-04-01T15:00:30.1230000

OLEオートメーション形式で表現できる最小(最古)の日時は0100年01月01日 00:00:00でありDateTimeで扱える範囲よりも狭いため、その範囲を越える値を変換しようとした場合はOverflowExceptionがスローされます。 (ArgumentOutOfRangeExceptionがスローされるToFileTimeメソッドとはスローされる例外が異なる点に注意してください)

アンマネージ呼び出し

DateTimeおよびDateTimeOffsetはアンマネージ呼び出しに使用することはできません。 Marshal.SizeOfメソッドによるサイズの取得や、Marshal.PtrToStructureメソッドによるポインタからの変換なども、例外エラーがスローされ、失敗します。

DateTime・DateTimeOffsetはアンマネージ呼び出しで使用することができない
using System;
using System.Runtime.InteropServices;

class Sample {
  static void Main()
  {
    // DateTimeのサイズを取得しようとする
    Console.WriteLine(Marshal.SizeOf(typeof(DateTime)));
    // ハンドルされていない例外: System.ArgumentException: 型 'System.DateTime' はアンマネージ構造体としてマーシャリングできません。有効なサイズ、またはオフセットの計算ができません。
    //    場所 System.Runtime.InteropServices.Marshal.SizeOfHelper(Type t, Boolean throwIfNotMarshalable)
    //    場所 Sample.Main()

    // ポインタからDateTimeに変換しようとする
    var ptr = Marshal.AllocHGlobal(32); // 適当なサイズの領域を確保 (何らかのデータが格納されていると仮定)

    var dt = (DateTime)Marshal.PtrToStructure(ptr, typeof(DateTime));
    // ハンドルされていない例外: System.ArgumentException: 指定された構造体は高速転送型か、またはレイアウト情報を含んでいなければなりません。
    // パラメーター名: structure
    //    場所 System.Runtime.InteropServices.Marshal.PtrToStructureHelper(IntPtr ptr, Object structure, Boolean allowValueClasses)
    //    場所 System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr, Type structureType)
    //    場所 Sample.Main()
  }
}
DateTime・DateTimeOffsetはアンマネージ呼び出しで使用することができない
Imports System
Imports System.Runtime.InteropServices

Class Sample
  Shared Sub Main()
    ' DateTimeのサイズを取得しようとする
    Console.WriteLine(Marshal.SizeOf(GetType(DateTime)))
    ' ハンドルされていない例外: System.ArgumentException: 型 'System.DateTime' はアンマネージ構造体としてマーシャリングできません。有効なサイズ、またはオフセットの計算ができません。
    '    場所 System.Runtime.InteropServices.Marshal.SizeOfHelper(Type t, Boolean throwIfNotMarshalable)
    '    場所 Sample.Main()

    ' ポインタからDateTimeに変換しようとする
    Dim ptr As IntPtr = Marshal.AllocHGlobal(32) ' 適当なサイズの領域を確保 (何らかのデータが格納されていると仮定)

    Dim dt As DateTime = CType(Marshal.PtrToStructure(ptr, GetType(DateTime)), DateTime)
    ' ハンドルされていない例外: System.ArgumentException: 指定された構造体は高速転送型か、またはレイアウト情報を含んでいなければなりません。
    ' パラメーター名: structure
    '    場所 System.Runtime.InteropServices.Marshal.PtrToStructureHelper(IntPtr ptr, Object structure, Boolean allowValueClasses)
    '    場所 System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr, Type structureType)
    '    場所 Sample.Main()
  End Sub
End Class

アンマネージ呼び出しで日時の値を扱いたい場合は、DateTime・DateTimeOffsetをToFileTimeToBinaryなどのメソッドで変換したり、Ticksプロパティなどの値を用いたりするなど、値を別のフォーマットに変換する必要があります。

TimeSpan

TimeSpan構造体は時間間隔、つまり時間の長さを扱うための型です。 ここでは、TimeSpanの機能と使い方について見ていきます。

インスタンスの作成

コンストラクタ

TimeSpanのコンストラクタでは、時分秒に負の値を指定したり、36時間90分といった値を指定することができます。 負数や大きな値を指定した場合でも、TimeSpanの最大・最小値を越えない限り例外はスローされません。 時間に負の値・分に正の値といった指定もすることが出来ます。 時分秒単位以外にも、DateTime・DateTimeOffsetの精度と同じ単位であるタイマ刻み数(=100ナノ秒)単位の値を指定することも出来ます。

コンストラクタを使ってTimeSpanインスタンスを作成する
using System;

class Sample {
  static void Main()
  {
    // 3日と1時間30分
    var a = new TimeSpan(3, 1, 30, 00);

    // -3時間+90分 (-1時間30分)
    var b = new TimeSpan(-3, 90, 0);

    // 1500ミリ秒
    var c = new TimeSpan(0, 0, 0, 0, 1500);

    // 30,000,000 × 100ナノ秒 = 3秒
    var d = new TimeSpan(30000000);

    Console.WriteLine(a);
    Console.WriteLine(b);
    Console.WriteLine(c);
    Console.WriteLine(d);
  }
}
コンストラクタを使ってTimeSpanインスタンスを作成する
Imports System

Class Sample
  Shared Sub Main()
     ' 3日と1時間30分
    Dim a As New TimeSpan(3, 1, 30, 00)

    ' -3時間+90分 (-1時間30分)
    Dim b As New TimeSpan(-3, 90, 0)

    ' 1500ミリ秒
    Dim c As New TimeSpan(0, 0, 0, 0, 1500)

    ' 30,000,000 × 100ナノ秒 = 3秒
    Dim d As New TimeSpan(30000000)

    Console.WriteLine(a)
    Console.WriteLine(b)
    Console.WriteLine(c)
    Console.WriteLine(d)
  End Sub
End Class
実行結果
3.01:30:00
-01:30:00
00:00:01.5000000
00:00:03

FromXXXメソッド

TimeSpanでは、次のようなメソッドを使うことにより、時間間隔の単位を指定してインスタンスを生成することも出来ます。 FromTicks以外はdouble型の値を指定できるため、「1.5日」や「9.5時間」といった時間間隔の指定も可能です。

TimeSpanインスタンスを作成するためのメソッド
メソッド 機能
TimeSpan.FromDays 日数を指定してTimeSpanを作成する
TimeSpan.FromHours 時間数を指定してTimeSpanを作成する
TimeSpan.FromMinutes 分数を指定してTimeSpanを作成する
TimeSpan.FromSeconds 秒数を指定してTimeSpanを作成する
TimeSpan.FromMilliseconds ミリ秒数を指定してTimeSpanを作成する
TimeSpan.FromTicks タイマ刻み数(100ナノ秒単位)を指定してTimeSpanを作成する
FromXxxメソッドを使ってTimeSpanインスタンスを作成する
using System;

class Sample {
  static void Main()
  {
    Console.WriteLine(TimeSpan.FromDays(1.5));    // 1.5日
    Console.WriteLine(TimeSpan.FromHours(9.5));   // 9.5時間
    Console.WriteLine(TimeSpan.FromMinutes(-80)); // -80分
  }
}
FromXxxメソッドを使ってTimeSpanインスタンスを作成する
Imports System

Class Sample
  Shared Sub Main()
    Console.WriteLine(TimeSpan.FromDays(1.5))    ' 1.5日
    Console.WriteLine(TimeSpan.FromHours(9.5))   ' 9.5時間
    Console.WriteLine(TimeSpan.FromMinutes(-80)) ' -80分
  End Sub
End Class
実行結果
1.12:00:00
09:30:00
-01:20:00

合計時間の取得

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.TotalXxxプロパティを使って時間間隔を日数・分数・秒数などに変換した値を取得する
using System;

class Sample {
  static void Main()
  {
    var ts = new TimeSpan(1, 2, 3, 4, 567);

    Console.WriteLine(ts);
    Console.WriteLine("= {0} 日", ts.TotalDays);
    Console.WriteLine("= {0} 時間", ts.TotalHours);
    Console.WriteLine("= {0} 分", ts.TotalMinutes);
    Console.WriteLine("= {0} 秒", ts.TotalSeconds);
    Console.WriteLine("= {0} ミリ秒", ts.TotalMilliseconds);
  }
}
TimeSpan.TotalXxxプロパティを使って時間間隔を日数・分数・秒数などに変換した値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim ts As New TimeSpan(1, 2, 3, 4, 567)

    Console.WriteLine(ts)
    Console.WriteLine("= {0} 日", ts.TotalDays)
    Console.WriteLine("= {0} 時間", ts.TotalHours)
    Console.WriteLine("= {0} 分", ts.TotalMinutes)
    Console.WriteLine("= {0} 秒", ts.TotalSeconds)
    Console.WriteLine("= {0} ミリ秒", ts.TotalMilliseconds)
  End Sub
End Class
実行結果
1.02:03:04.5670000
= 1.08546952546296 日
= 26.0512686111111 時間
= 1563.07611666667 分
= 93784.567 秒
= 93784567 ミリ秒

単位部分の取得

TimeSpanの表す時間間隔の日部分・秒部分の値が必要な場合は、次のプロパティを参照します。 これらのプロパティで得られる値はいずれも端数なしの正規化された整数値で、例えばHoursなら常に023の範囲、Minutes・Secondsなら059の範囲で値が得られます。

各単位部分を取得するプロパティ
プロパティ 取得できる値
TimeSpan.Days TimeSpanの表す時間の長さの日部分を取得する
TimeSpan.Hours TimeSpanの表す時間の長さの時間部分を取得する
TimeSpan.Minutes TimeSpanの表す時間の長さの分部分を取得する
TimeSpan.Seconds TimeSpanの表す時間の長さの秒部分を取得する
TimeSpan.Milliseconds TimeSpanの表す時間の長さのミリ秒部分を取得する

1時間30分間の時間間隔を表すTimeSpanから1.5時間あるいは90分という値を得たい場合のように、特定単位に変換された合計時間を取得したい場合にはTotalHours・TotalMinutesなどのプロパティを参照します。

TimeSpan.Days/Hours/Secondsプロパティを使って時間間隔の日数・時間・秒部分など時間単位ごとの値を取得する
using System;

class Sample {
  static void Main()
  {
    var seconds = 1234567.89;
    var ts = TimeSpan.FromSeconds(seconds);

    Console.WriteLine("{0}秒 = {1}日 {2}時間 {3}分 {4}秒 .{5}",
                      seconds,
                      ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
  }
}
TimeSpan.Days/Hours/Secondsプロパティを使って時間間隔の日数・時間・秒部分など時間単位ごとの値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim seconds As Double = 1234567.89
    Dim ts As TimeSpan = TimeSpan.FromSeconds(seconds)

    Console.WriteLine("{0}秒 = {1}日 {2}時間 {3}分 {4}秒 .{5}", _
                      seconds, _
                      ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds)
  End Sub
End Class
実行結果
1234567.89秒 = 14日 6時間 56分 7秒 .890

最小値・最大値・精度

TimeSpanでは、±Int64.MaxValue×100ナノ秒、おおよそ±10,675,199日の範囲の日時を扱うことが出来ます。 この最小値・最大値はMinValueフィールドおよびMaxValueフィールドを参照することで取得できます。 また、Zeroフィールドを参照することで長さ0の時間間隔を取得することも出来ます。

TimeSpan.MinValue/MaxValueプロパティで最小値・最大値を取得する
using System;

class Sample {
  static void Main()
  {
    Console.WriteLine(TimeSpan.MinValue);
    Console.WriteLine(TimeSpan.MaxValue);
    Console.WriteLine(TimeSpan.Zero);
  }
}
TimeSpan.MinValue/MaxValueプロパティで最小値・最大値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Console.WriteLine(TimeSpan.MinValue)
    Console.WriteLine(TimeSpan.MaxValue)
    Console.WriteLine(TimeSpan.Zero)
  End Sub
End Class
実行結果
-10675199.02:48:05.4775808
10675199.02:48:05.4775807
00:00:00

TimeSpanで扱える時間間隔の精度(タイマ刻み数)は、DateTime・DateTimeOffsetと同じく100ナノ秒となっています。 Ticksプロパティを参照すると、時間間隔を100ナノ秒単位での値で取得することが出来ます。

TimeSpan.Ticksプロパティで100ナノ秒単位での時間間隔を取得する
using System;

class Sample {
  static void Main()
  {
    var ts = TimeSpan.FromSeconds(1);

    Console.WriteLine("{0} = {1} ticks", ts, ts.Ticks);

    Console.WriteLine("1 tick = {0}", TimeSpan.FromTicks(1));
  }
}
TimeSpan.Ticksプロパティで100ナノ秒単位での時間間隔を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim ts As TimeSpan = TimeSpan.FromSeconds(1)

    Console.WriteLine("{0} = {1} ticks", ts, ts.Ticks)

    Console.WriteLine("1 tick = {0}", TimeSpan.FromTicks(1))
  End Sub
End Class
実行結果
00:00:01 = 10000000 ticks
1 tick = 00:00:00.0000001

1時間あたりや1秒あたりのタイマ刻み数を取得する定数として、TicksPerHourフィールドTicksPerSecondフィールドなどが用意されています。

TimeSpan.TicksPerXxxプロパティで1時間・1秒あたりなどでのタイマ刻み数を取得する
using System;

class Sample {
  static void Main()
  {
    Console.WriteLine("TicksPerMillisecond = {0}", TimeSpan.TicksPerMillisecond);
    Console.WriteLine("TicksPerSecond = {0}", TimeSpan.TicksPerSecond);
    Console.WriteLine("TicksPerMinute = {0}", TimeSpan.TicksPerMinute);
    Console.WriteLine("TicksPerHour = {0}", TimeSpan.TicksPerHour);
    Console.WriteLine("TicksPerDay = {0}", TimeSpan.TicksPerDay);
  }
}
TimeSpan.TicksPerXxxプロパティで1時間・1秒あたりなどでのタイマ刻み数を取得する
Imports System

Class Sample
  Shared Sub Main()
    Console.WriteLine("TicksPerMillisecond = {0}", TimeSpan.TicksPerMillisecond)
    Console.WriteLine("TicksPerSecond = {0}", TimeSpan.TicksPerSecond)
    Console.WriteLine("TicksPerMinute = {0}", TimeSpan.TicksPerMinute)
    Console.WriteLine("TicksPerHour = {0}", TimeSpan.TicksPerHour)
    Console.WriteLine("TicksPerDay = {0}", TimeSpan.TicksPerDay)
  End Sub
End Class
実行結果
TicksPerMillisecond = 10000
TicksPerSecond = 10000000
TicksPerMinute = 600000000
TicksPerHour = 36000000000
TicksPerDay = 864000000000

加減算

TimeSpanでは、TimeSpan同士の加減算を行うことが出来るようになっています。 Addメソッドで加算、Subtractメソッドで減算が行えます。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに加算演算子・減算演算子を使うことも出来ます。

加算/減算演算子・Add/SubtractメソッドでTimeSpan同士を加減算する
using System;

class Sample {
  static void Main()
  {
    var a = TimeSpan.FromHours(24);
    var b = TimeSpan.FromMinutes(90);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a.Add(b)      = {0}", a.Add(b));
    Console.WriteLine("a + b         = {0}", a + b);
    Console.WriteLine("a.Subtract(b) = {0}", a.Subtract(b));
    Console.WriteLine("a - b         = {0}", a - b);
  }
}
加算/減算演算子・Add/SubtractメソッドでTimeSpan同士を加減算する
Imports System

Class Sample
  Shared Sub Main()
    Dim a As TimeSpan = TimeSpan.FromHours(24)
    Dim b As TimeSpan = TimeSpan.FromMinutes(90)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a.Add(b)      = {0}", a.Add(b))
    Console.WriteLine("a + b         = {0}", a + b)
    Console.WriteLine("a.Subtract(b) = {0}", a.Subtract(b))
    Console.WriteLine("a - b         = {0}", a - b)
  End Sub
End Class
実行結果
a = 1.00:00:00
b = 01:30:00
a.Add(b)      = 1.01:30:00
a + b         = 1.01:30:00
a.Subtract(b) = 22:30:00
a - b         = 22:30:00

DateTime・DateTimeOffsetに対してTimeSpanを加減算することで、ある日時から一定時間経過した/遡った日時を求めることができます。

DateTime・DateTimeOffsetに対しては、DateTime.Add/Subtractなどのメソッドを使って加減算をすることもできます。

加算/減算演算子でDateTime/DateTimeOffsetとTimeSpanを加減算する
using System;

class Sample {
  static void Main()
  {
    // 現在日時
    var dt = DateTime.Now;
    var dto = DateTimeOffset.Now;

    var ts = new TimeSpan(1, 8, 0, 0);

    // 現在から1日と8時間後の時刻を求める
    Console.WriteLine(dt + ts);
    Console.WriteLine(dto + ts);

    // 現在より1日と8時間前の時刻を求める
    Console.WriteLine(dt - ts);
    Console.WriteLine(dto - ts);
  }
}
加算/減算演算子でDateTime/DateTimeOffsetとTimeSpanを加減算する
Imports System

Class Sample
  Shared Sub Main()
    ' 現在日時
    Dim dt As DateTime = DateTime.Now
    Dim dto As DateTimeOffset = DateTimeOffset.Now

    Dim ts As New TimeSpan(1, 8, 0, 0)

    ' 現在から1日と8時間後の時刻を求める
    Console.WriteLine(dt + ts)
    Console.WriteLine(dto + ts)

    ' 現在より1日と8時間前の時刻を求める
    Console.WriteLine(dt - ts)
    Console.WriteLine(dto - ts)
  End Sub
End Class
実行結果例
2013/04/02 23:00:30
2013/04/02 23:00:30 +09:00
2013/03/31 7:00:30
2013/03/31 7:00:30 +09:00

絶対値・符号反転

DurationメソッドでTimeSpanが表す時間の長さ、つまり符号を取り除いた絶対値を取得することができます。 Durationはプロパティではなくメソッドとなっています。

TimeSpan.Durationメソッドで時間間隔の絶対的な長さを取得する
using System;

class Sample {
  static void Main()
  {
    var ts = TimeSpan.FromHours(-27);

    Console.WriteLine(ts);
    Console.WriteLine(ts.Duration()); // tsの絶対値
  }
}
TimeSpan.Durationメソッドで時間間隔の絶対的な長さを取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim ts As TimeSpan = TimeSpan.FromHours(-27)

    Console.WriteLine(ts)
    Console.WriteLine(ts.Duration()) ' tsの絶対値
  End Sub
End Class
実行結果
-1.03:00:00
1.03:00:00

NegateメソッドでTimeSpanが表す時間の前後を逆転した値、つまり符号を反転した値を取得することができます。

TimeSpan.Negateメソッドで時間間隔の符号を反転した値を取得する
using System;

class Sample {
  static void Main()
  {
    var ts = TimeSpan.FromMinutes(54);

    Console.WriteLine(ts);
    Console.WriteLine(ts.Negate()); // tsの符号を反転した値
  }
}
TimeSpan.Negateメソッドで時間間隔の符号を反転した値を取得する
Imports System

Class Sample
  Shared Sub Main()
    Dim ts As TimeSpan = TimeSpan.FromHours(54)

    Console.WriteLine(ts)
    Console.WriteLine(ts.Negate()) ' tsの符号を反転した値
  End Sub
End Class
実行結果
00:54:00
-00:54:00

乗除算

.NET Standard 2.1/.NET Core 2.0以降のTimeSpanでは、TimeSpanに対してdoubleの値との乗除算を行うことが出来るようになっています。 Multiplyメソッドで乗算、Divideメソッドで除算が行えます。 C#・VB.NETなどオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに乗算演算子・除算演算子を使うことも出来ます。

乗算/除算演算子・Multiply/DivideメソッドでTimeSpanに対して乗除算を行う .NET Standard 2.1/.NET Core 2.0
using System;

class Sample {
  static void Main()
  {
    var ts = TimeSpan.FromSeconds(1);

    Console.WriteLine(ts.Multiply(2.0)); // Multiplyメソッドを使って乗算を行う(2を掛ける)
    Console.WriteLine(ts * 2.0); // 乗算演算子を用いることも可能

    Console.WriteLine(ts.Divide(2.0)); // Divideメソッドを使って除算を行う(2で割る)
    Console.WriteLine(ts / 2.0); // 除算演算子を用いることも可能
  }
}
乗算/除算演算子・Multiply/DivideメソッドでTimeSpanに対して乗除算を行う .NET Standard 2.1/.NET Core 2.0
Imports System

Class Sample
  Shared Sub Main()
    Dim ts = TimeSpan.FromSeconds(1)

    Console.WriteLine(ts.Multiply(2.0)) ' Multiplyメソッドを使って乗算を行う(2を掛ける)
    Console.WriteLine(ts * 2.0) ' 乗算演算子を用いることも可能

    Console.WriteLine(ts.Divide(2.0)) ' Divideメソッドを使って除算を行う(2で割る)
    Console.WriteLine(ts / 2.0) ' 除算演算子を用いることも可能
  End Sub
End Class
実行結果
00:00:02
00:00:02
00:00:00.5000000
00:00:00.5000000

これらのメソッドが使えない環境では、TimeSpan.TotalSecondsなどのプロパティで一旦数値に変換してから乗除算を行い、その後TimeSpan.FromSecondsなどのメソッドで再びTimeSpanに戻す、といった手順をとることにより乗除算を行うことができます。

等価性・大小関係の比較

TimeSpanでは、二つのTimeSpanの値が同じかどうか、その等価性の比較を行うメソッドとしてEqualsメソッドが用意されています。 また、二つのTimeSpanのどちらが大きいか、その大小関係の比較を行うメソッドとしてCompareメソッドCompareToメソッドが用意されています。 これらのメソッドはIEquatableインターフェイス・IComparableインターフェイスのメソッドとして提供されます。 これらのメソッド・インターフェイスについての詳細は等価性の定義と比較および大小関係の定義と比較をご覧ください。

これらのメソッドを使う他にも、等価演算子(==)・不等価演算子(!=)・比較演算子(<, >)を使うことでTimeSpan同士の比較をすることも出来ます。

等価演算子・比較演算子を使って2つのTimeSpanの等価・大小関係を比較する
using System;

class Sample {
  static void Main()
  {
    var a = new TimeSpan(3, 1, 30, 00);
    var b = new TimeSpan(-3, 90, 0);

    Console.WriteLine("a = {0}", a);
    Console.WriteLine("b = {0}", b);
    Console.WriteLine("a == b : {0}", a == b);
    Console.WriteLine("a != b : {0}", a != b);
    Console.WriteLine("a < b : {0}", a < b);
    Console.WriteLine("a > b : {0}", a > b);
  }
}
等価演算子・比較演算子を使って2つのTimeSpanの等価・大小関係を比較する
Imports System

Class Sample
  Shared Sub Main()
    Dim a As New TimeSpan(3, 1, 30, 00)
    Dim b As New TimeSpan(-3, 90, 0)

    Console.WriteLine("a = {0}", a)
    Console.WriteLine("b = {0}", b)
    Console.WriteLine("a = b : {0}", a = b)
    Console.WriteLine("a <> b : {0}", a <> b)
    Console.WriteLine("a < b : {0}", a < b)
    Console.WriteLine("a > b : {0}", a > b)
  End Sub
End Class
実行結果
a = 3.01:30:00
b = -01:30:00
a == b : False
a != b : True
a < b : False
a > b : True

ソート

TimeSpanはIComparableインターフェイスによって大小関係が定義されているため、ソートすることができます。 TimeSpanでは、負から正の方向にTimeSpanの表す時間間隔の短い順(Ticksプロパティの値の小さい順)でソートされます。

Array.Sortを使って複数のTimeSpanをソートする
using System;

class Sample {
  static void Main()
  {
    var arr = new TimeSpan[] {
      new TimeSpan(3, 1, 30, 00),
      new TimeSpan(-3, 90, 0),
      new TimeSpan(0, 0, 0, 0, 1500),
      new TimeSpan(30000000),
    };

    foreach (var ts in arr) {
      Console.WriteLine(ts);
    }
    Console.WriteLine();

    // Array.Sortを使ってTimeSpanをソート
    Console.WriteLine("[Sort]");

    Array.Sort(arr);

    foreach (var ts in arr) {
      Console.WriteLine(ts);
    }
    Console.WriteLine();
  }
}
Array.Sortを使って複数のTimeSpanをソートする
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As TimeSpan = New TimeSpan() { _
      New TimeSpan(3, 1, 30, 00), _
      New TimeSpan(-3, 90, 0), _
      New TimeSpan(0, 0, 0, 0, 1500), _
      New TimeSpan(30000000) _
    }

    For Each ts As TimeSpan In arr
      Console.WriteLine(ts)
    Next
    Console.WriteLine()

    ' Array.Sortを使ってTimeSpanをソート
    Console.WriteLine("[Sort]")

    Array.Sort(arr)

    For Each ts As TimeSpan In arr
      Console.WriteLine(ts)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
3.01:30:00
-01:30:00
00:00:01.5000000
00:00:03

[Sort]
-01:30:00
00:00:01.5000000
00:00:03
3.01:30:00

ソートについて詳しくは基本型のソートと昇順・降順でのソートをご覧ください。

文字列への/からの変換

ToStringメソッドを用いることで、TimeSpanの表す時間間隔を文字列形式に変換することができます。 さらに、.NET Framework 4からは書式を指定して文字列化することが可能になっています。 これにより値をゼロ埋めしたり、時分秒などの区切り文字を変更して文字列化することができます。

TimeSpan.ToStringメソッドで書式を指定して文字列化する
using System;

class Sample {
  static void Main()
  {
    var ts = new TimeSpan(1, 2, 34, 5, 678);

    Console.WriteLine(ts);
    Console.WriteLine(ts.ToString("g")); // 分秒のみ0埋めの書式
    Console.WriteLine(ts.ToString("G")); // 時分秒および秒未満の端数をすべて0埋めの書式
    Console.WriteLine("{0:g} {0:G}", ts);
    Console.WriteLine(ts.ToString(@"d' days 'h' hours 'm' minutes 's' seconds '")); // カスタム書式
  }
}
TimeSpan.ToStringメソッドで書式を指定して文字列化する
Imports System

Class Sample
  Shared Sub Main()
    Dim ts As New TimeSpan(1, 2, 34, 5, 678)

    Console.WriteLine(ts)
    Console.WriteLine(ts.ToString("g")) ' 分秒のみ0埋めの書式
    Console.WriteLine(ts.ToString("G")) ' 時分秒および秒未満の端数をすべて0埋めの書式
    Console.WriteLine("{0:g} {0:G}", ts)
    Console.WriteLine(ts.ToString("d' days 'h' hours 'm' minutes 's' seconds '")) ' カスタム書式
  End Sub
End Class
実行結果
1.02:34:05.6780000
1:2:34:05.678
1:02:34:05.6780000
1:2:34:05.678 1:02:34:05.6780000
1 days 2 hours 34 minutes 5 seconds

TimeSpanに対して指定可能な書式については、書式指定子 §.時間間隔の書式指定子および書式指定子 §.時間間隔のカスタム書式指定子をご覧ください。


文字列からTimeSpanに変換するには、ParseメソッドTryParseメソッドを使うことが出来ます。 また、厳密に書式を指定して文字列からTimeSpanへ変換するには、ParseExactメソッドTryParseExactメソッドを使うことが出来ます。 なお、これらのメソッドはいずれも.NET Framework 4から使用可能になっています。

TimeSpan.TryParse/TryParseExactメソッドで文字列からTimeSpanに変換する
using System;

class Sample {
  static void Main()
  {
    var arr = new string[] {
      "1.2:34:5.678",           // 日数と時間の区切りに '.' を用いた形式
      "1:2:34:5.678",           // 日数と時間の区切りに ':' を用いた形式
      "1日2時間34分5秒678",     // 時間単位に日本語を用いた形式
      "01日02時間34分05秒678",
    };

    Console.WriteLine("[TryParse]");

    foreach (var s in arr) {
      // TryParseメソッドで変換を試みる
      TimeSpan ts;

      if (TimeSpan.TryParse(s, out ts))
        // 変換できた場合は結果を表示
        Console.WriteLine("{0} -> {1}", s, ts);
      else
        Console.WriteLine("{0} -> (invalid format)", s);
    }

    Console.WriteLine();

    Console.WriteLine("[TryParseExact]");

    foreach (var s in arr) {
      // TryParseExactメソッドで書式を指定して変換を試みる
      var formats = new string[] {
        "G", // "一般的な形式"を表す書式指定子
        "d'日'h'時間'm'分's'秒'fff", // カスタム書式指定子の組み合わせ
      };

      TimeSpan ts;

      if (TimeSpan.TryParseExact(s, formats, null, out ts))
        // 変換できた場合は結果を表示
        Console.WriteLine("{0} -> {1}", s, ts);
      else
        Console.WriteLine("{0} -> (invalid format)", s);
    }
  }
}
TimeSpan.TryParse/TryParseExactメソッドで文字列からTimeSpanに変換する
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As String = New String() { _
      "1.2:34:5.678", _         
      "1:2:34:5.678", _
      "1日2時間34分5秒678", _
      "01日02時間34分05秒678" _
    }

    Console.WriteLine("[TryParse]")

    For Each s As String In arr
      ' TryParseメソッドで変換を試みる
      Dim ts As TimeSpan

      If TimeSpan.TryParse(s, ts) Then
        ' 変換できた場合は結果を表示
        Console.WriteLine("{0} -> {1}", s, ts)
      Else
        Console.WriteLine("{0} -> (invalid format)", s)
      End If
    Next

    Console.WriteLine()

    Console.WriteLine("[TryParseExact]")

    For Each s As String In arr
      ' TryParseExactメソッドで書式を指定して変換を試みる
      Dim formats() As String = New String() { _
        "G", _
        "d'日'h'時間'm'分's'秒'fff" _
      }
      Dim ts As TimeSpan

      If TimeSpan.TryParseExact(s, formats, Nothing, ts)
        ' 変換できた場合は結果を表示
        Console.WriteLine("{0} -> {1}", s, ts)
      Else
        Console.WriteLine("{0} -> (invalid format)", s)
        End If
    Next
  End Sub
End Class
実行結果
[TryParse]
1.2:34:5.678 -> 1.02:34:05.6780000
1:2:34:5.678 -> 1.02:34:05.6780000
1日2時間34分5秒678 -> (invalid format)
01日02時間34分05秒678 -> (invalid format)

[TryParseExact]
1.2:34:5.678 -> (invalid format)
1:2:34:5.678 -> 1.02:34:05.6780000
1日2時間34分5秒678 -> 1.02:34:05.6780000
01日02時間34分05秒678 -> 1.02:34:05.6780000

ToStringメソッドおよびParse*メソッドでは、現在のカルチャの影響を受けるもの(ローカライズされる書式)が存在します。 これらのメソッドと文字列化に関する詳細な動作については日時・文字列の変換と書式でも解説しているので、あわせてご覧ください。