DateTime構造体/文字列を使って表されている「日付」を比較する方法を解説。また、DateTimeOffset構造体を使っているときの注意点も取り上げる。
日付を比較するにはどうしたらよいだろうか? 本稿では、2つの日付が同じ日なのか、違うならどちらが新しい(または、古い)日付なのかを判定する方法を解説する。
特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。
なお、いずれの方法も.NET Frameworkバージョン2.0から利用できるが、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2015以降が必要である。また、サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。
using System;
using static System.Console;
Imports System.Console
日付や時刻をDateTime構造体(System名前空間)で表現しているのなら、Dateプロパティを比較すればよい(次のコード)。.NET Frameworkに日付のみを表す型はないが、その代わりとしてDateプロパティは時刻を切り捨ててその日の午前0時にしたDateTime構造体を返してくれる。
var datetime1 = new DateTime(2018, 3, 1, 3, 0, 0);
var datetime2 = new DateTime(2018, 3, 1, 15, 0, 0); // datetime1と同じ日
var datetime3 = new DateTime(2018, 3, 3, 0, 0, 0); // datetime1の2日後
// datetime1とdatetime2は同じ日か?
bool compare1and2 = (datetime1.Date == datetime2.Date);
WriteLine($"(datetime1.Date == datetime2.Date) ⇒ {compare1and2}");
// 出力:(datetime1.Date == datetime2.Date) ⇒ True
// datetime2はdatetime3より前の日か?
bool compare2and3 = (datetime2.Date < datetime3.Date);
WriteLine($"(datetime2.Date < datetime3.Date) ⇒ {compare2and3}");
// 出力:(datetime2.Date < datetime3.Date) ⇒ True
Dim datetime1 = New DateTime(2018, 3, 1, 3, 0, 0)
Dim datetime2 = New DateTime(2018, 3, 1, 15, 0, 0) ' datetime1と同じ日
Dim datetime3 = New DateTime(2018, 3, 3, 0, 0, 0) ' datetime1の2日後
' datetime1とdatetime2は同じ日か?
Dim compare1and2 As Boolean = (datetime1.Date = datetime2.Date)
WriteLine($"(datetime1.Date = datetime2.Date) ⇒ {compare1and2}")
' 出力:(datetime1.Date == datetime2.Date) ⇒ True
' datetime2はdatetime3より前の日か?
Dim compare2and3 As Boolean = (datetime2.Date < datetime3.Date)
WriteLine($"(datetime2.Date < datetime3.Date) ⇒ {compare2and3}")
' 出力:(datetime2.Date < datetime3.Date) ⇒ True
なお、DateプロパティではなくDateTime構造体のインスタンス自体を比較してしまうと、時刻も含めた比較になってしまって、「同じ日かどうか」という意味では判定を間違えるので注意しよう(次のコード)。
var datetime1 = new DateTime(2018, 3, 1, 3, 0, 0);
var datetime2 = new DateTime(2018, 3, 1, 15, 0, 0); // datetime1と同じ日
// 同じ日なのに時刻が違うと別の日だと間違えてしまう
WriteLine($"(datetime1 == datetime2) ⇒ {datetime1 == datetime2}");
// 出力:(datetime1 == datetime2) ⇒ False
Dim datetime1 = New DateTime(2018, 3, 1, 3, 0, 0)
Dim datetime2 = New DateTime(2018, 3, 1, 15, 0, 0) ' datetime1と同じ日
' 同じ日なのに時刻が違うと別の日だと間違えてしまう
WriteLine($"(datetime1 = datetime2) ⇒ {datetime1 = datetime2}")
' 出力:(datetime1 = datetime2) ⇒ False
同じ日か違う日かを判定するだけなら前項のように単純に比較すればよいのだが、3通りの判定(同じ/前/後)をしたいこともある。そのようなときは、DateTime構造体のDateプロパティをCompareToメソッドで比較する(次のコード)。
var datetime1 = new DateTime(2018, 3, 1, 3, 0, 0);
var datetime2 = new DateTime(2018, 3, 1, 15, 0, 0); // datetime1と同じ日
var datetime3 = new DateTime(2018, 3, 3, 0, 0, 0); // datetime1の2日後
// datetime1とdatetime2の前後関係は?(0:同じ日)
int compare1and2 = datetime1.Date.CompareTo(datetime2.Date);
WriteLine($"datetime1.Date.CompareTo(datetime2.Date) ⇒ {compare1and2}");
// 出力:datetime1.Date.CompareTo(datetime2.Date) ⇒ 0
// datetime2とdatetime3の前後関係は?(-1:datetime2が小さい=前)
int compare2and3 = datetime2.Date.CompareTo(datetime3.Date);
WriteLine($"datetime2.Date.CompareTo(datetime3.Date) ⇒ {compare2and3}");
// 出力:datetime2.Date.CompareTo(datetime3.Date) ⇒ -1
// datetime3とdatetime1の前後関係は?(1:datetime3が大きい=後)
int compare3and1 = datetime3.Date.CompareTo(datetime1.Date);
WriteLine($"datetime3.Date.CompareTo(datetime1.Date) ⇒ {compare3and1}");
// 出力:datetime3.Date.CompareTo(datetime1.Date) ⇒ 1
Dim datetime1 = New DateTime(2018, 3, 1, 3, 0, 0)
Dim datetime2 = New DateTime(2018, 3, 1, 15, 0, 0) ' datetime1と同じ日
Dim datetime3 = New DateTime(2018, 3, 3, 0, 0, 0) ' datetime1の2日後
' datetime1とdatetime2の前後関係は?(0:同じ日)
Dim compare1and2 As Integer = datetime1.Date.CompareTo(datetime2.Date)
WriteLine($"datetime1.Date.CompareTo(datetime2.Date) ⇒ {compare1and2}")
' 出力:datetime1.Date.CompareTo(datetime2.Date) ⇒ 0
' datetime2とdatetime3の前後関係は?(-1:datetime2が小さい=前)
Dim compare2and3 As Integer = datetime2.Date.CompareTo(datetime3.Date)
WriteLine($"datetime2.Date.CompareTo(datetime3.Date) ⇒ {compare2and3}")
' 出力:datetime2.Date.CompareTo(datetime3.Date) ⇒ -1
' datetime3とdatetime1の前後関係は?(1:datetime3が大きい=後)
Dim compare3and1 As Integer = datetime3.Date.CompareTo(datetime1.Date)
WriteLine($"datetime3.Date.CompareTo(datetime1.Date) ⇒ {compare3and1}")
' 出力:datetime3.Date.CompareTo(datetime1.Date) ⇒ 1
あるいは、2つの日付の間に何日の差があるかを求めてもよい(次のコード)。
var datetime1 = new DateTime(2018, 3, 1, 3, 0, 0);
var datetime2 = new DateTime(2018, 3, 1, 15, 0, 0); // datetime1と同じ日
var datetime3 = new DateTime(2018, 3, 3, 0, 0, 0); // datetime1の2日後
// datetime1とdatetime2の日数差は?(0:同じ日)
double days1and2 = (datetime1.Date - datetime2.Date).TotalDays;
WriteLine($"(datetime1.Date - datetime2.Date).TotalDays ⇒ {days1and2}");
// 出力:(datetime1.Date - datetime2.Date).TotalDays ⇒ 0
// datetime2とdatetime3の日数差は?(-2:datetime2が2日前)
double days2and3 = (datetime2.Date - datetime3.Date).TotalDays;
WriteLine($"(datetime2.Date - datetime3.Date).TotalDays ⇒ {days2and3}");
// 出力:(datetime2.Date - datetime3.Date).TotalDays ⇒ -2
// datetime3とdatetime1の日数差は?(2:datetime3が2日後)
double days3and1 = (datetime3.Date - datetime1.Date).TotalDays;
WriteLine($"(datetime3.Date - datetime1.Date).TotalDays ⇒ {days3and1}");
// 出力:(datetime3.Date - datetime1.Date).TotalDays ⇒ 2
Dim datetime1 = New DateTime(2018, 3, 1, 3, 0, 0)
Dim datetime2 = New DateTime(2018, 3, 1, 15, 0, 0) ' datetime1と同じ日
Dim datetime3 = New DateTime(2018, 3, 3, 0, 0, 0) ' datetime1の2日後
' datetime1とdatetime2の日数差は?(0:同じ日)
Dim days1and2 As Double = (datetime1.Date - datetime2.Date).TotalDays
WriteLine($"(datetime1.Date - datetime2.Date).TotalDays ⇒ {days1and2}")
' 出力:(datetime1.Date - datetime2.Date).TotalDays ⇒ 0
' datetime2とdatetime3の日数差は?(-2:datetime2が2日前)
Dim days2and3 As Double = (datetime2.Date - datetime3.Date).TotalDays
WriteLine($"(datetime2.Date - datetime3.Date).TotalDays ⇒ {days2and3}")
' 出力:(datetime2.Date - datetime3.Date).TotalDays ⇒ -2
' datetime3とdatetime1の日数差は?(2:datetime3が2日後)
Dim days3and1 As Double = (datetime3.Date - datetime1.Date).TotalDays
WriteLine($"(datetime3.Date - datetime1.Date).TotalDays ⇒ {days3and1}")
' 出力:(datetime3.Date - datetime1.Date).TotalDays ⇒ 2
日数差の正負の符号は、前掲のCompareToメソッドの正負と同じだ。
なお、引き算の代わりに、DateTime構造体のSubtractメソッドを使ってもよい。
日付を「yyyyMMdd」というフォーマットの8桁整数の文字列として保持しているシステムもある。その場合は、StringクラスのCompareToメソッドを使って比較できる(次のコード)。
string date1 = "20180228";
string date2 = "20180228"; // date1と同じ日
string date3 = "20180302"; // date1の2日後
// date1とdate2の前後関係は?(0:同じ日)
WriteLine($"date1.CompareTo(date2) ⇒ {date1.CompareTo(date2)}");
// 出力:date1.CompareTo(date2) ⇒ 0
// date2とdate3の前後関係は?(-1:date2が小さい=前)
WriteLine($"date2.CompareTo(date3) ⇒ {date2.CompareTo(date3)}");
// 出力:date2.CompareTo(date3) ⇒ -1
// date3とdate1の前後関係は?(1:date3が大きい=後)
WriteLine($"date3.CompareTo(date1) ⇒ {date3.CompareTo(date1)}");
// 出力:date3.CompareTo(date1) ⇒ 1
Dim date1 As String = "20180228"
Dim date2 As String = "20180228" ' date1と同じ日
Dim date3 As String = "20180302" ' date1の2日後
' date1とdate2の前後関係は?(0:同じ日)
WriteLine($"date1.CompareTo(date2) ⇒ {date1.CompareTo(date2)}")
' 出力:date1.CompareTo(date2) ⇒ 0
' date2とdate3の前後関係は?(-1:date2が小さい=前)
WriteLine($"date2.CompareTo(date3) ⇒ {date2.CompareTo(date3)}")
' 出力:date2.CompareTo(date3) ⇒ -1
' date3とdate1の前後関係は?(1:date3が大きい=後)
WriteLine($"date3.CompareTo(date1) ⇒ {date3.CompareTo(date1)}")
' 出力:date3.CompareTo(date1) ⇒ 1
また、日数差を求めるには、DateTime型に変換してから計算する(次のコード)。この例の「yyyy/M/d」フォーマットのようにCompareToメソッドで比較しても正しく前後関係を求められない日付文字列の場合は、DateTime型に変換して比較するしかない。
なお、日付文字列をDateTime型に変換する方法については、次の.NET TIPSをご覧いただきたい。
var date1 = "2018/2/28";
var date2 = "2018/2/28"; // date1と同じ日
var date3 = "2018/3/2"; // date1の2日後
// DateTime型に変換する
DateTime dt1 = DateTime.ParseExact(date1, "yyyy/M/d", null);
DateTime dt2 = DateTime.ParseExact(date2, "yyyy/M/d", null);
DateTime dt3 = DateTime.ParseExact(date3, "yyyy/M/d", null);
// date1とdate2の日数差は?(0:同じ日)
WriteLine($"(dt1 - dt2).TotalDays ⇒ {(dt1 - dt2).TotalDays}");
// 出力:(dt1 - dt2).TotalDays ⇒ 0
// date2とdate3の日数差は?(-2:date2が2日前)
WriteLine($"(dt2 - dt3).TotalDays ⇒ {(dt2 - dt3).TotalDays}");
// 出力:(dt2 - dt3).TotalDays ⇒ -2
// date3とdate1の日数差は?(2:date3が2日後)
WriteLine($"(dt3 - dt1).TotalDays ⇒ {(dt3 - dt1).TotalDays}");
// 出力:(dt3 - dt1).TotalDays ⇒ 2
Dim date1 As String = "2018/2/28"
Dim date2 As String = "2018/2/28" ' date1と同じ日
Dim date3 As String = "2018/3/2" ' date1の2日後
' DateTime型に変換する
Dim dt1 As DateTime = DateTime.ParseExact(date1, "yyyy/M/d", Nothing)
Dim dt2 As DateTime = DateTime.ParseExact(date2, "yyyy/M/d", Nothing)
Dim dt3 As DateTime = DateTime.ParseExact(date3, "yyyy/M/d", Nothing)
' date1とdate2の日数差は?(0:同じ日)
WriteLine($"(dt1 - dt2).TotalDays ⇒ {(dt1 - dt2).TotalDays}")
' 出力:(dt1 - dt2).TotalDays ⇒ 0
' date2とdate3の日数差は?(-2:date2が2日前)
WriteLine($"(dt2 - dt3).TotalDays ⇒ {(dt2 - dt3).TotalDays}")
' 出力:(dt2 - dt3).TotalDays ⇒ -2
' date3とdate1の日数差は?(2:date3が2日後)
WriteLine($"(dt3 - dt1).TotalDays ⇒ {(dt3 - dt1).TotalDays}")
' 出力:(dt3 - dt1).TotalDays ⇒ 2
タイムゾーンを考慮したシステムでは、日時をDateTimeOffset構造体で表現しているだろう。その場合も、前述したようなDateプロパティを使った比較をすればよい。ただし、比較する前に特定のタイムゾーンのDateTimeOffset構造体にそろえておく必要がある(次のコード)。
DateTimeOffset dto1
= new DateTimeOffset(new DateTime(2018, 3, 1, 3, 0, 0), TimeSpan.FromHours(9.0));
DateTimeOffset dto2
= new DateTimeOffset(new DateTime(2018, 2, 28, 21, 0, 0), TimeSpan.FromHours(0.0));
DateTimeOffset dto3
= new DateTimeOffset(new DateTime(2018, 3, 2, 0, 0, 0), TimeSpan.FromHours(9.0));
// 日本標準時(JST)にそろえてから日付を求める
TimeSpan offsetJST = TimeSpan.FromHours(9.0);
DateTime date1 = dto1.ToOffset(offsetJST).Date;
DateTime date2 = dto2.ToOffset(offsetJST).Date;
DateTime date3 = dto3.ToOffset(offsetJST).Date;
WriteLine($"dto1の日付(JST) = {date1:yyyy/MM/dd}");
// 出力:dto1の日付(JST) = 2018/03/01
WriteLine($"dto2の日付(JST) = {date2:yyyy/MM/dd}");
// 出力:dto2の日付(JST) = 2018/03/01
WriteLine($"dto3の日付(JST) = {date3:yyyy/MM/dd}");
// 出力:dto3の日付(JST) = 2018/03/02
// モルディブ標準時(MVT)にそろえてから日付を求める
TimeSpan offsetMVT = TimeSpan.FromHours(5.0);
date1 = dto1.ToOffset(offsetMVT).Date;
date2 = dto2.ToOffset(offsetMVT).Date;
date3 = dto3.ToOffset(offsetMVT).Date;
WriteLine($"dto1の日付(MVT) = {date1:yyyy/MM/dd}");
// 出力:dto1の日付(MVT) = 2018/02/28
WriteLine($"dto2の日付(MVT) = {date2:yyyy/MM/dd}");
// 出力:dto2の日付(MVT) = 2018/03/01
WriteLine($"dto3の日付(MVT) = {date3:yyyy/MM/dd}");
// 出力:dto3の日付(MVT) = 2018/03/01
Dim dto1 As DateTimeOffset _
= New DateTimeOffset(New DateTime(2018, 3, 1, 3, 0, 0), TimeSpan.FromHours(9.0))
Dim dto2 As DateTimeOffset _
= New DateTimeOffset(New DateTime(2018, 2, 28, 21, 0, 0), TimeSpan.FromHours(0.0))
Dim dto3 As DateTimeOffset _
= New DateTimeOffset(New DateTime(2018, 3, 2, 0, 0, 0), TimeSpan.FromHours(9.0))
' 日本標準時(JST)にそろえてから日付を求める
Dim offsetJST As TimeSpan = TimeSpan.FromHours(9.0)
Dim date1 As DateTime = dto1.ToOffset(offsetJST).Date
Dim date2 As DateTime = dto2.ToOffset(offsetJST).Date
Dim date3 As DateTime = dto3.ToOffset(offsetJST).Date
WriteLine($"dto1の日付(JST) = {date1:yyyy/MM/dd}")
' 出力:dto1の日付(JST) = 2018/3/1
WriteLine($"dto2の日付(JST) = {date2:yyyy/MM/dd}")
' 出力:dto2の日付(JST) = 2018/3/1
WriteLine($"dto3の日付(JST) = {date3:yyyy/MM/dd}")
' 出力:dto3の日付(JST) = 2018/3/2
' モルディブ標準時(MVT)にそろえてから日付を求める
Dim offsetMVT As TimeSpan = TimeSpan.FromHours(5.0)
date1 = dto1.ToOffset(offsetMVT).Date
date2 = dto2.ToOffset(offsetMVT).Date
date3 = dto3.ToOffset(offsetMVT).Date
WriteLine($"dto1の日付(MVT) = {date1:yyyy/MM/dd}")
' 出力:dto1の日付(MVT) = 2018/2/28
WriteLine($"dto2の日付(MVT) = {date2:yyyy/MM/dd}")
' 出力:dto2の日付(MVT) = 2018/3/1
WriteLine($"dto3の日付(MVT) = {date3:yyyy/MM/dd}")
' 出力:dto3の日付(MVT) = 2018/3/1
日付がDateTime構造体/DateTimeOffset構造体で表現されているときは、Dateプロパティで日付を取り出して、等値演算子/関係演算子かCompareToメソッドで比較する。ただし、DateTimeOffset構造体では先にタイムゾーンをそろそろえておく。
日付を文字列で表現している場合で、文字列のまま比較できるフォーマットのときはCompareToメソッドで比較する。直接比較できないフォーマットのときは、DateTime構造体に変換してから比較する。
利用可能バージョン:.NET Framework 2.0以降
カテゴリ:クラス・ライブラリ 処理対象:日付と時刻
使用ライブラリ:DateTime構造体(System名前空間)
使用ライブラリ:DateTimeOffset構造体(System名前空間)
使用ライブラリ:TimeSpan構造体(System名前空間)
関連TIPS:日付や時刻の文字列をDateTimeオブジェクトに変換するには?
関連TIPS:日時や時間間隔の加減算を行うには?
関連TIPS:DateTimeとDateTimeOffsetの違いとは?[C#、VB]
関連TIPS:n日後、nカ月後、n年後の日付を求めるには?[C#、VB]
関連TIPS:年齢を計算するには?[C#/VB]
関連TIPS:毎月のプレミアムフライデーを算出するには?[C#/VB]
関連TIPS:月初/月末の日付を求めるには?[C#、VB]
関連TIPS:週の始まりの日付を求めるには?
関連TIPS:指定した日の曜日を取得するには?[C#/VB]
関連TIPS:指定した月から特定の曜日の日付を取得するには?[C#、VB]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]
Copyright© Digital Advantage Corp. All Rights Reserved.