EFでDateTimeの日付コンポーネントのみを比較する方法は?


116

2つの日付値があります。1つは既にデータベースに保存されており、もう1つはユーザーがDatePickerを使用して選択しました。ユースケースは、データベースから特定の日付を検索することです。

以前にデータベースに入力された値には常に12:00:00の時間コンポーネントがありますが、ピッカーから入力された日付には異なる時間コンポーネントがあります。

日付コンポーネントのみに関心があり、時間コンポーネントは無視したいと思います。

C#でこの比較を行う方法は何ですか?

また、LINQでこれを行う方法は?

更新:LINQ to Entitiesでは、以下が正常に機能します。

e => DateTime.Compare(e.FirstDate.Value, SecondDate) >= 0

1
また、このSOの質問を見てみることができます: stackoverflow.com/questions/683037/how-to-compare-dates-in-c/...
Quintinのロビンソン

回答:


121

注:この回答を書いている時点では、EFの関係は不明確でした(これが書かれた後に質問に編集されました)。EFでの正しいアプローチについては、Mandeepsの回答を確認してください。


DateTime.Dateプロパティを使用して、日付のみの比較を実行できます。

DateTime a = GetFirstDate();
DateTime b = GetSecondDate();

if (a.Date.Equals(b.Date))
{
    // the dates are equal
}

34
日付を比較するのは簡単ですが、質問は.DateプロパティをSQLに変換できないLINQ to Entitiesに関連しています。
ミカエル・カーペンティア

1
@MichaëlCarpentier:良い点。どうやら、それはまだOPの問題を解決しました。
FredrikMörk2013年

6
これはデータベースにクエリを実行するのではなく、事後CLR /アプリケーションレイヤーのデータを処理します。実際の解決策は、クエリをデータベースに送信し、ストレージレイヤーで処理を実行できるようにするため、以下の回答で指定されているEntityFunctions.TruncateTime(..)関数を使用することです。これがないと、Where / Count句で日付比較ロジックを使用できず、フィルター処理されたデータでさらにクエリを実行できません。これは、最初に部分的な結果をアプリケーションレイヤーにプルする必要があるためです。大量のデータを処理します。
2013年

6
@Marchyはい、EntityFunctions.TruncateTime確かに最近行く方法のようです(この質問が尋ねられた翌年にリリースされた.NET 4で利用可能になりました)。
FredrikMörk2013年

1
System.Data.Entity.DbFunctions.TruncateTime()メソッドを使用します。EntityFrameworkへの参照を追加する必要があります
adeel41

132

クラスEntityFunctionsを使用して時間部分をトリミングします。

using System.Data.Objects;    

var bla = (from log in context.Contacts
           where EntityFunctions.TruncateTime(log.ModifiedDate) ==  EntityFunctions.TruncateTime(today.Date)
           select log).FirstOrDefault();

出典:http : //social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/84d4e18b-7545-419b-9826-53ff1a0e2a62/

更新

EF 6.0以降では、EntityFunctionsはDbFunctionsに置き換えられています


37
(少なくとも)EF6をEntityFunctions支持するSystem.Data.Entity.DbFunctionsため、メモは非推奨になりました。これよりも早いかもしれません。
pquest

4
:それは、ゆっくりと本当に多くの情報であるように私は、このソリューションにジャンプするために迅速ではないでしょうstackoverflow.com/questions/22776843/...
pajicsを

SQLiteデータベースでは動作しないようです。「SQLロジックエラーまたはデータベースがないため、そのような関数はありません:TruncateTime」と表示されます。
shadowsora 2017年

24

これはあなたに役立つと思います。

EFデータで満たされたリポジトリの日付を比較する必要があるため、拡張子を作成しました。LinqToEntities変換には実装されていないため、.Dateはオプションではありませんでした。

これがコードです:

        /// <summary>
    /// Check if two dates are same
    /// </summary>
    /// <typeparam name="TElement">Type</typeparam>
    /// <param name="valueSelector">date field</param>
    /// <param name="value">date compared</param>
    /// <returns>bool</returns>
    public Expression<Func<TElement, bool>> IsSameDate<TElement>(Expression<Func<TElement, DateTime>> valueSelector, DateTime value)
    {
        ParameterExpression p = valueSelector.Parameters.Single();

        var antes = Expression.GreaterThanOrEqual(valueSelector.Body, Expression.Constant(value.Date, typeof(DateTime)));

        var despues = Expression.LessThan(valueSelector.Body, Expression.Constant(value.AddDays(1).Date, typeof(DateTime)));

        Expression body = Expression.And(antes, despues);

        return Expression.Lambda<Func<TElement, bool>>(body, p);
    }

このように使用できます。

 var today = DateTime.Now;
 var todayPosts = from t in turnos.Where(IsSameDate<Turno>(t => t.MyDate, today))
                                      select t);

10

DateDBエンティティのプロパティを使用すると、例外が発生します。

"The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."

次のようなものを使用できます。

  DateTime date = DateTime.Now.Date;

  var result = from client in context.clients
               where client.BirthDate >= date
                     && client.BirthDate < date.AddDays(1)
               select client;


8

これを行う別の方法がありますが、SecondDateが渡した変数である場合にのみ役立ちます。

DateTime startDate = SecondDate.Date;
DateTime endDate = startDate.AddDays(1).AddTicks(-1);
...
e => e.FirstDate.Value >= startDate && e.FirstDate.Value <= endDate

うまくいくと思います


1
優れた。私のために働いた。それはDateTime = x.Date;私が行方不明だったのは明白でした。を使用した場合var、または比較で値をインライン化した場合、例外が報告されて失敗しました。ありがとう。
Tim Croydon、2012年

うまくいったよティム。返答が遅れてすみません-しばらくの間、実際にSOにログインしていません。
John Kaster、2012年

1
に変更e.FirstDate.Value <= endDateしたe.FirstDate.Value < endDate場合は、を削除できます.AddTicks(-1)
Marco de Zeeuw、2015

@MarcodeZeeuwあなたが正しい、それは間違いなくうまくいくでしょう。示されている条件式は、正確な開始日時と終了日時の包括的な日付比較を目的としています(日付範囲の値がコードフラグメントで設定されるのではなく、条件に渡されると想定しています)。IOW、条件は日時値とは別と見なされます。 。
John Kaster

6

これを使用することもできます:

DbFunctions.DiffDays(date1, date2) == 0


4

これにはDbFunctions.TruncateTime()メソッドを使用できます。

e => DbFunctions.TruncateTime(e.FirstDate.Value) == DbFunctions.TruncateTime(SecondDate);

3

完全な日付時刻ではなく、常にDateTime のDateプロパティを比較するだけです。

LINQクエリを作成するときは、クエリでdate.Dateを使用します。

var results = from c in collection
              where c.Date == myDateTime.Date
              select c;

10
「指定された型メンバー 'Date'はLINQ to Entitiesでサポートされていません。初期化子、エンティティメンバー、およびエンティティナビゲーションプロパティのみがサポートされています。」というエラーが発生します。何かご意見は?
鉛筆版2009

ええ-あなたのプロバイダーは.Dateプロパティを直接処理しません。それを引き出して、後で日付を比較する必要があります。
リードコプシー

.Dateは、残念ながらLinq Toエンティティでは使用できません。うまくいけば、MSがすぐにそのオーバーロードのサポートを追加することになるでしょう
John Kaster

1
常に Dateプロパティを比較しますか?それがベストプラクティスかどうか疑問に思ったので、私はこのコメントをグーグルで調べました。常にそれはのようなものだ場合でも、日付プロパティを使用しますcandidate.Date >= base.Date。理論的には、candidate.Date時間は12:00:00以上でなければならないので、Dateプロパティを使用することは冗長ですが、リードのアドバイスを使用します。
スティーブンホスキング2012

3

これが私のやり方です。

DateTime date_time_to_compare = DateTime.Now;
//Compare only date parts
context.YourObject.FirstOrDefault(r =>
                EntityFunctions.TruncateTime(r.date) == EntityFunctions.TruncateTime(date_to_compare));

2

// Linqユーザー/コーダーに関する注意

これにより、ユーザーからの入力を処理するときに日付が範囲内にあるかどうかを確認するための正確な比較が得られます。たとえば、日付ピッカー:

((DateTime)ri.RequestX.DateSatisfied).Date >= startdate.Date &&
        ((DateTime)ri.RequestX.DateSatisfied).Date <= enddate.Date

ここで、startdateとenddateは日付ピッカーからの値です。


1

時間がないので、次のように試してください:

TimeSpan ts = new TimeSpan(23, 59, 59);
toDate = toDate.Add(ts);
List<AuditLog> resultLogs = 
    _dbContext.AuditLogs
    .Where(al => al.Log_Date >= fromDate && al.Log_Date <= toDate)
    .ToList();
return resultLogs;

1

以下のリンクを使用して、2つの日付を時間なしで比較できます。

private bool DateGreaterOrEqual(DateTime dt1, DateTime dt2)
        {
            return DateTime.Compare(dt1.Date, dt2.Date) >= 0;
        }

private bool DateLessOrEqual(DateTime dt1, DateTime dt2)
        {
            return DateTime.Compare(dt1.Date, dt2.Date) <= 0;
        }

Compare関数は3つの異なる値を返します:-1 0 1つまり、dt1> dt2、dt1 = dt2、dt1を意味します


単にDateTime.Compare(dt1.Date、dt2.Date)を返さないのはなぜですか?これで必要なものがすべて揃います。
ジョニーグレイバー

0

これを試してください... 2つのDateTimes型のDateプロパティを比較するとうまくいきます。

PS。これは一時的な解決策であり、本当に悪い習慣です。データベースが数千のレコードをもたらす可能性があることがわかっている場合は使用しないでください...

query = query.ToList()
             .Where(x => x.FirstDate.Date == SecondDate.Date)
             .AsQueryable();

1
PS:通常、DateTimeにTime値があり、Dateのみを比較する場合に、この方法を使用します。
Raskunho、2012

2
これは非常に悪い解決策です。クエリはすべてのレコードを取得してから、日付のみをフィルタリングします。データベースに数百万のレコードがある場合、すべてのレコードが取得され、日付のみがフィルタリングされます。非常に悪い習慣。
認知症、2015年

1
これは一時的な解決策であり、本当に悪い習慣です。データベースが数千のレコードをもたらす可能性があることがわかっている場合は使用しないでください。
Raskunho

回答にコメントを追加する場合は、反対票を削除します。あなたが提案した解決策はコメントを読む必要がない悪いものであることは、このページを訪問する誰にとっても明白であるべきです。
2015

一般に悪い考えですが、EFが日付の比較をSQLに変換するのがおかしいので、このアプローチは小さなレコードセット(<1000レコードなど)のパフォーマンスを大幅に向上させます。SQL EFが生成するものではなく、メモリ内で日付の比較を行うだけで、クエリが1分以上から1秒未満に進むのを見てきました。
Extragorey、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.