ここでは.NETにおける日付と時刻に関連するデータ型であるDateTime構造体・DateTimeOffset構造体・TimeSpan構造体と、それらの型を使った日付と時刻の操作について見ていきます。
なお、本文中にあるいくつかのサンプルコードについて、実行環境に設定されているタイムゾーン・言語・書式等によって実行結果・出力内容が変わるものもが存在します。 特に明記していない場合は、日本標準時(UTC+9)・日本語の環境での実行結果となります。
以下この文書では、年月日のみ(date)を表すために日付、時分秒のみ(time)を表すために時刻、日付と時刻の組み合わせ(date and time)を表すために日時、2つの日時間の差を表すために時間間隔の各用語を用います。
日付・時刻・時間間隔と型
まずは.NETで使用出来る日付と時刻を扱う型について大まかに見ていきます。
日付と時刻
.NETでは日時を表す値を扱うデータ型としてDateTime構造体およびがDateTimeOffset構造体が用意されています。 DateTime・DateTimeOffset構造体は特定の日付と時刻を表すだけでなく、日時の加減算や日時同士の大小(前後)関係の比較を行うための機能、ローカル時刻と世界協定時刻(UTC)との変換を行うための機能などが用意されています。
DateTime
DateTime構造体は、日付と時刻をひとまとめにして扱うデータ型ですが、単に日時の値を表すだけではなく、DateTimeでは時刻がローカル時刻とUTCのどちらかを表すのか、時刻の種類を明示することができるようになっていて、日時をローカル時刻もしくは世界協定時刻(UTC)として取り扱うことができるようになっています。
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();
}
}
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では任意のタイムゾーンの日時が扱えるという違いがあります。
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));
}
}
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を使えばオフセット値を維持したまま格納することができるため、「時刻は東部標準時である」という情報は維持されます。
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);
}
}
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ミリ秒」といった時間の長さを一つの型で表すために使います。
時間の長さをint
・double
などの数値型で表そうとした場合、それが秒を表すのか、分を表すのか、といった単位の扱いや変換が煩雑になりがちですが、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);
}
}
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プロパティを参照します。
using System;
class Sample {
static void Main()
{
// ローカル時刻での現在日時
Console.WriteLine(DateTime.Now);
Console.WriteLine(DateTimeOffset.Now);
// UTCでの現在日時
Console.WriteLine(DateTime.UtcNow);
Console.WriteLine(DateTimeOffset.UtcNow);
}
}
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となります。
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);
}
}
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プロパティの値を取得することで、次の例のように処理の経過時間を計測することも出来ます。
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);
}
}
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フィールドを参照することで取得できます。
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);
}
}
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秒に指定した値を加えた値がインスタンスの表す日時となります。
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));
}
}
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が表す日時の時分秒を参照するには、Hour・Minute・Secondの各プロパティを参照します。 Millisecondプロパティで秒の端数(ミリ秒部分)も取得することが出来ます。
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); // 現在時刻のミリ秒部分を取得
}
}
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で取得することが出来ます。
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);
}
}
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ナノ秒です。
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に変換した時刻での経過時間
}
}
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が表す日時の年月日を参照するには、Year・Month・Dayの各プロパティを参照します。 DayOfWeekプロパティで日付の曜日を取得することが出来ます。
日付が1月の場合、Monthプロパティは1
を返します。 C言語のtm構造体など、1月が0
となる言語・処理系とは異なる点に注意してください。
また、DayOfWeekプロパティが返す曜日は数値ではなく、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); // 現在日付の曜日部分を取得
}
}
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.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型で取得することが出来ます。
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); // 日付部分のみを取得
}
}
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
月名・曜日名・年号の表記
月名を英語や他の外国語表記にしたり、曜日名を日本語表記にしたり、和暦での年号を付記したりするには、書式を指定した文字列化や特定カルチャの指定を行うことで出来ます。
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();
}
}
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 星期一
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));
}
}
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年の各年について、その年がうるう年かどうかを調べて表示しています。
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));
}
}
}
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の表す日時がその年の通算何日目かを取得することが出来ます。
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); // 今年の何日目か取得する
}
}
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に対して、その年がうるう年かどうかと、その日までの通算日数を表示しています。
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);
}
}
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年の各月ごとの日数を表示しています。
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));
}
}
}
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クラスで参照することが出来ます。
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());
}
}
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
StandardName: 東京 (標準時) DaylightName: 東京 (夏時間) 2013/01/01 0:00:00 False 2013/07/01 0:00:00 False
StandardName: アメリカ太平洋標準時 DaylightName: アメリカ太平洋夏時間 2013/01/01 0:00:00 False 2013/07/01 0:00:00 True
StandardName: JST DaylightName: JDT 2013/01/01 0:00:00 False 2013/07/01 0:00:00 False
StandardName: PST DaylightName: PDT 2013/01/01 0:00:00 False 2013/07/01 0:00:00 True
実行環境に設定されているものとは異なるタイムゾーンにおける日時が夏時間の期間内かどうかを調べるには、TimeZoneInfo.IsDaylightSavingTimeメソッドを使います。
日時の値の変更・加減算
年月日や時分秒を表すHour・Day・Monthなどのプロパティは参照専用で、インスタンスを作成した後は一切変更することができません。 年月日・時分秒の一部分だけを変更したい場合は、変更したい値をコンストラクタに指定して新たにインスタンスを作成する必要があります。
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);
}
}
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メソッドを使用するとインスタンスに指定した日数を足した日時を取得することが出来るため、このメソッドを使うと上記の例は次のように書き換えることが出来ます。
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);
}
}
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*メソッドではうるう年での日数の違いも考慮された上で日時が計算されます。
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);
}
}
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メソッドを使う場合と同じです。
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)
}
}
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日にはなりません)。
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));
}
}
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日となります。
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));
}
}
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日となります。
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));
}
}
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メソッドを呼び出す必要があります。
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);
}
}
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に変換した上でその差が求められます。
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);
}
}
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メソッドを使う場合と同じです。
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)
}
}
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のどちらかに合わせた上で比較を行う必要があります。
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();
}
}
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メソッドを使うことが出来ます。
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));
}
}
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の大小関係を求めるためのメソッド・演算子の一覧です。
メソッド・演算子 | 動作 |
---|---|
x > y | x が y よりも後の日時の場合に真(true)となる |
x >= y | x が y よりも後、もしくは等しい日時の場合に真(true)となる |
x < y | x が y よりも前の日時の場合に真(true)となる |
x <= y | x が y よりも前、もしくは等しい日時の場合に真(true)となる |
DateTime.Compare(x, y) DateTimeOffset.Compare(x, y) x.Compare(y) x.Compare(y) |
x が y よりも後の日時(x > y)の場合、正の値を返す x と y が同じ日時(x = y)の場合、0を返す x が y よりも前の日時(x < y)の場合、負の値を返す |
Compare・CompareToメソッド(および比較演算子)でDateTime同士の比較を行う場合、DateTime同士の減算の場合と同様に時刻の種類(Kindプロパティの値)は考慮されないため、常に同一タイムゾーンの時刻として比較される点に注意が必要です。 二つのDateTime同士の比較結果は、両者のTicksプロパティの値の大小を比較したものと同じとなります。 DateTimeに設定されている時刻の種類も考慮して比較するには、ToUniversalTime・ToLocalTimeメソッドで日時の種類をローカル時刻かUTCのどちらかに合わせた上で比較を行う必要があります。
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();
}
}
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に変換した上で比較が行われます。
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));
}
}
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に設定されているオフセット値を加算した上での日付を返す点に注意が必要です。
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();
}
}
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
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));
}
}
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のかわりに比較演算子を使って比較することもできます)。
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));
}
}
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
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));
}
}
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メソッドに渡すようにします。
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();
}
}
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.ToUnixTimeSeconds・FromUnixTimeSecondsメソッドは、日時の値をUNIX時間(UNIXタイムスタンプ)として使われるlong型(64ビット)の値に変換します。
UNIX時間はUTCでの時刻と定義されているため、ToUnixTimeSecondsではUTCに変換された上での値が返されます。 また、FromUnixTimeSecondsメソッドでこの値を変換すると、Offsetプロパティが+00:00
のDateTimeOffsetが返されます。 UNIX時間からDateTimeOffsetに変換した値を、さらにローカル時間として取得したい場合はToLocalTimeメソッドを使用することができます。
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());
}
}
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以降で使用することができます。
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より前の日時です");
}
}
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
ToFileTime・FromFileTimeメソッドは、日時の値をWindowsのファイルタイムスタンプで使われるlong型(64ビット)の値に変換します。
タイムスタンプはUTCでの時刻とされているため、ToFileTimeメソッドではUTCに変換された上での値が返されます。 FromFileTimeメソッドでこの値を変換すると、UTCからローカル時刻に変換された(KindプロパティがDateTimeKind.Localの)DateTimeが返されます。 一方、FromFileTimeUtcメソッドで変換すると、UTC(KindプロパティがDateTimeKind.Utc)のDateTimeが返されます。
DateTimeOffset.FromFileTimeメソッドでは、返されるDateTimeOffsetのOffsetプロパティには常にローカル時刻のオフセットが設定されます。
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に変換
}
}
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
ToBinary・FromBinaryメソッドは、日時の値をlong型(64ビット)の値に変換します。 このメソッドでは、DateTime.TicksプロパティおよびDateTime.Kindプロパティの値を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));
}
}
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
ToOADate・FromOADateメソッドは、日時の値をOLEオートメーション日時(double型・64ビット)の値に変換します。 このフォーマットでは時刻の種類は無視され、日時のみが変換されるという点に注意が必要です。 その他フォーマットの詳細などはToOADateメソッドのドキュメントを参照してください。
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));
}
}
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メソッドによるポインタからの変換なども、例外エラーがスローされ、失敗します。
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()
}
}
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をToFileTimeやToBinaryなどのメソッドで変換したり、Ticksプロパティなどの値を用いたりするなど、値を別のフォーマットに変換する必要があります。
TimeSpan
TimeSpan構造体は時間間隔、つまり時間の長さを扱うための型です。 ここでは、TimeSpanの機能と使い方について見ていきます。
インスタンスの作成
コンストラクタ
TimeSpanのコンストラクタでは、時分秒に負の値を指定したり、36時間90分といった値を指定することができます。 負数や大きな値を指定した場合でも、TimeSpanの最大・最小値を越えない限り例外はスローされません。 時間に負の値・分に正の値といった指定もすることが出来ます。 時分秒単位以外にも、DateTime・DateTimeOffsetの精度と同じ単位であるタイマ刻み数(=100ナノ秒)単位の値を指定することも出来ます。
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);
}
}
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.FromDays | 日数を指定してTimeSpanを作成する |
TimeSpan.FromHours | 時間数を指定してTimeSpanを作成する |
TimeSpan.FromMinutes | 分数を指定してTimeSpanを作成する |
TimeSpan.FromSeconds | 秒数を指定してTimeSpanを作成する |
TimeSpan.FromMilliseconds | ミリ秒数を指定してTimeSpanを作成する |
TimeSpan.FromTicks | タイマ刻み数(100ナノ秒単位)を指定して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分
}
}
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などのプロパティを参照します。
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);
}
}
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なら常に0
〜23
の範囲、Minutes・Secondsなら0
〜59
の範囲で値が得られます。
プロパティ | 取得できる値 |
---|---|
TimeSpan.Days | TimeSpanの表す時間の長さの日部分を取得する |
TimeSpan.Hours | TimeSpanの表す時間の長さの時間部分を取得する |
TimeSpan.Minutes | TimeSpanの表す時間の長さの分部分を取得する |
TimeSpan.Seconds | TimeSpanの表す時間の長さの秒部分を取得する |
TimeSpan.Milliseconds | TimeSpanの表す時間の長さのミリ秒部分を取得する |
1時間30分間の時間間隔を表すTimeSpanから1.5時間あるいは90分という値を得たい場合のように、特定単位に変換された合計時間を取得したい場合にはTotalHours・TotalMinutesなどのプロパティを参照します。
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);
}
}
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の時間間隔を取得することも出来ます。
using System;
class Sample {
static void Main()
{
Console.WriteLine(TimeSpan.MinValue);
Console.WriteLine(TimeSpan.MaxValue);
Console.WriteLine(TimeSpan.Zero);
}
}
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ナノ秒単位での値で取得することが出来ます。
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));
}
}
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フィールドなどが用意されています。
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);
}
}
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などオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに加算演算子・減算演算子を使うことも出来ます。
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);
}
}
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などのメソッドを使って加減算をすることもできます。
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);
}
}
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はプロパティではなくメソッドとなっています。
using System;
class Sample {
static void Main()
{
var ts = TimeSpan.FromHours(-27);
Console.WriteLine(ts);
Console.WriteLine(ts.Duration()); // tsの絶対値
}
}
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が表す時間の前後を逆転した値、つまり符号を反転した値を取得することができます。
using System;
class Sample {
static void Main()
{
var ts = TimeSpan.FromMinutes(54);
Console.WriteLine(ts);
Console.WriteLine(ts.Negate()); // tsの符号を反転した値
}
}
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などオーバーロードされた演算子を使用できる言語では、これらのメソッドを使う代わりに乗算演算子・除算演算子を使うことも出来ます。
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); // 除算演算子を用いることも可能
}
}
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同士の比較をすることも出来ます。
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);
}
}
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プロパティの値の小さい順)でソートされます。
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();
}
}
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からは書式を指定して文字列化することが可能になっています。 これにより値をゼロ埋めしたり、時分秒などの区切り文字を変更して文字列化することができます。