如何仅比较EF中DateTime中的日期组件?


116

我有两个日期值,一个已经存储在数据库中,另一个由用户使用DatePicker选择。用例是从数据库中搜索特定日期。

先前在数据库中输入的值始终具有12:00:00的时间分量,而从选择器输入的日期具有不同的时间分量。

我只对日期部分感兴趣,并且想忽略时间部分。

在C#中进行这种比较的方法是什么?

另外,如何在LINQ中做到这一点?

更新:在LINQ to Entities上,以下工作正常。

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

Answers:


121

注意:在编写此答案时,尚不清楚EF关系(在编写此问题后已将其编辑到问题中)。对于使用EF的正确方法,请检查Mandeeps答案


您可以使用该DateTime.Date属性执行仅日期比较。

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

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

34
比较日期很容易,但是问题与LINQ to Entities有关,后者无法将.Date属性转换为SQL。
迈克尔卡彭铁尔

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
EntityFunctions支持System.Data.Entity.DbFunctions(至少)EF6 的注释已被弃用。可能早于此。
pquest

4
我也不会快速跳转到该解决方案,因为它实在是太慢了,更多的信息:stackoverflow.com/questions/22776843/...
pajics

似乎不适用于SQLite数据库。我收到“ SQL逻辑错误或缺少数据库,没有这样的功能:TruncateTime”。
shadowsora

24

我认为这可以为您提供帮助。

我进行了扩展,因为我必须比较填充EF数据的存储库中的日期,因此.Date不是一个选择,因为它未在LinqToEntities转换中实现。

这是代码:

        /// <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

如果将Date属性用于数据库实体,则会出现异常:

"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

要在LINQ to Entities中做到这一点,您必须使用受支持的方法

var year = someDate.Year;
var month = ...
var q = from r in Context.Records
        where Microsoft.VisualBasic.DateAndTime.Year(r.SomeDate) == year 
              && // month and day

丑陋,但是可以工作,并且已经在数据库服务器上完成了。


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,或者在比较中具有内联值,则失败,并报告异常。谢谢。
蒂姆·克罗伊登

很高兴,蒂姆。很抱歉延迟回复-我实际上已经有一段时间没有登录SO了。
约翰·卡斯特

1
如果更改e.FirstDate.Value <= endDatee.FirstDate.Value < endDate,则可以删除.AddTicks(-1)
Marco de Zeeuw,2015年

@MarcodeZeeuw你是对的,那肯定也可以。所示条件表达式旨在用于精确开始日期和结束日期时间的包含性日期比较(假设日期范围值将传递给条件,而不是在代码片段中设置。)IOW,条件条件被认为与日期时间值分开。
约翰·卡斯特

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
我收到错误消息:“ LINQ to Entities不支持指定的类型成员'Date'。仅支持初始化程序,实体成员和实体导航属性。”。有什么想法吗?
Pencilslate

是的-您的提供者不会直接处理.Date属性。您必须将其拔出,然后再比较日期。
Reed Copsey

很遗憾,.Date不能在Linq To Entities中使用。希望MS将很快补充说,超载支持
约翰·卡斯特

1
总是比较Date属性?我搜索了此评论,因为我想知道这是否是最佳实践。要始终使用日期属性,即使它的喜欢的东西时candidate.Date >= base.Date。从理论上讲,candidate.Date时间必须大于等于12:00:00,因此使用Date属性是多余的,但我会坚持Reed的建议。
Stephen Hosking

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

您可以使用下面的链接来比较两个没有时间的日期:

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;
        }

比较函数返回3个不同的值:-1 0 1,这意味着dt1> dt2,dt1 = dt2,dt1


为什么不只返回DateTime.Compare(dt1.Date,dt2.Date)?这满足了您的所有需求。
约翰尼·格拉伯

0

尝试一下...比较两个DateTimes类型之间的Date属性可以很好地工作:

PS。这是权宜之计,而且是一种非常糟糕的做法,当您知道数据库可以带来数千条记录时,永远不要使用它。

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

1
PS:当DateTimes具有Time值并且我只想比较Date时,我通常使用这种方式。
Raskunho 2012年

2
这是一个非常糟糕的解决方案,查询将获取所有记录,然后才过滤出日期。如果数据库中有数百万条记录,它将捕获所有记录,然后才过滤日期。非常糟糕的做法。
痴呆症患者

1
这是权宜之计,而且是一个非常糟糕的做法,当您知道数据库可以带来数千条记录时,绝对不要使用它。
Raskunho 2015年

如果您将评论添加到答案中,我将删除我的不赞成票。任何访问此页面的人都应该知道,您提出的解决方案很糟糕,无需阅读注释。
Dementic 2015年

虽然这通常是一个坏主意,但是由于EF将日期比较转换为SQL的愚蠢方式,这种方法可大大改善小记录集(<1000条左右的记录)的性能。我已经看到查询只是通过在内存中而不是在SQL EF生成的数据中进行日期比较而从一分钟到不到一秒。
Extragorey,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.