【问题标题】:How to compare DateTime without time via LINQ?如何通过 LINQ 比较没有时间的 DateTime?
【发布时间】:2012-03-26 10:46:23
【问题描述】:

我有

var q = db.Games.Where(t => t.StartDate >= DateTime.Now).OrderBy(d => d.StartDate);

但它比较包括DateTime 的时间部分。我真的不需要它。

没时间怎么办?

谢谢!

【问题讨论】:

    标签: c# .net linq datetime


    【解决方案1】:

    .Date 的答案具有误导性,因为您收到了前面提到的错误。除了提到DbFunctions.TruncateTime之外,另一种比较方式也可能是:

    DateTime today = DateTime.Now.date;
    var q = db.Games.Where(t => SqlFunctions.DateDiff("dayofyear", today, t.StartDate) <= 0
          && SqlFunctions.DateDiff("year", today, t.StartDate) <= 0)
    

    在生成的 SQL 查询中看起来更好(更易读)。但我承认它在 C# 代码中看起来更糟 XD。我正在测试一些东西,似乎TruncateTime 对我不起作用,不幸的是键盘和椅子之间出现了故障,但与此同时我找到了这个替代方案。

    【讨论】:

      【解决方案2】:

      我在遇到相同查询时发现了这个问题。我终于在没有使用 DbFunctions 的情况下找到了它。 试试这个:

      var q = db.Games.Where(t => t.StartDate.Day == DateTime.Now.Day && t.StartDate.Month == DateTime.Now.Month && t.StartDate.Year == DateTime. Now.Year ).OrderBy(d => d.StartDate);

      通过将日期部分分叉,我们可以有效地仅比较日期,从而忽略时间。

      希望对您有所帮助。请原谅我在答案中的格式,这是我的第一个答案。

      【讨论】:

      • Pronlem 是当您在多个过滤谓词中涉及同一列时,您最终会选择一个作为搜索谓词,其余的成为剩余谓词
      【解决方案3】:

      LINQ to Entities 不支持 Date 属性 - 如果您尝试在 LINQ to Entities 查询中的 DateTime 字段上使用它,则会收到错误消息。但是,您可以使用 DbFunctions.TruncateTime 方法修剪日期。

      var today = DateTime.Today;
      var q = db.Games.Where(t => DbFunctions.TruncateTime(t.StartDate) >= today);
      

      【讨论】:

      • 请注意,在实体框架的更高版本中,EntityFunctions 现在已替换为 DbFunctions
      • 我是唯一一个您的解决方案和 Jon 的解决方案向我提出错误“LINQ to Entities 不支持指定类型成员 'Date'”?
      • 第一次看到这个之后,看起来 System.Data.Entity.DbFunctions 还有许多有用的其他方法。很有帮助!
      • 如果不需要,不要使用动态或“var”。
      【解决方案4】:

      碰巧LINQ 不喜欢DateTime.Date 之类的属性。它只是无法转换为 SQL 查询。所以我想出了一种使用乔恩的答案比较日期的方法,但没有那个顽皮的DateTime.Date。像这样的:

      var q = db.Games.Where(t =&gt; t.StartDate.CompareTo(DateTime.Today) &gt;= 0).OrderBy(d =&gt; d.StartDate);

      这样,我们将完整的数据库 DateTime 与所有日期和时间的东西(例如 2015-03-04 11:49:45.000 或类似的东西)与代表实际第一毫秒的 DateTime 进行比较一天,例如 2015-03-04 00:00:00.0000。

      我们与DateTime.Today 比较的任何 DateTime 如果该日期更晚或相同,都会安全地返回给我们。除非您想在同一天进行逐字比较,否则我认为您应该选择凯撒的答案。

      DateTime.CompareTo() 方法只是花哨的面向对象的东西。如果参数早于您引用的 DateTime 它返回 -1,如果它是 LITERALLY EQUAL(包含所有那些时间的东西),则返回 0,如果它更晚,则返回 1。

      【讨论】:

        【解决方案5】:

        试试这个代码

        var today = DateTime.Today;
        var q = db.Games.Where(t => DbFunctions.TruncateTime(t.StartDate) <= today);
        

        【讨论】:

          【解决方案6】:
          DateTime dt=DateTime.Now.date;
          
          var q = db.Games.Where(
              t =>EntityFunction.TruncateTime(t.StartDate.Date >=EntityFunction.TruncateTime(dt)).OrderBy(d => d.StartDate
          );
          

          【讨论】:

            【解决方案7】:

            我发现在我的情况下这是唯一可行的方法:(在我的应用程序中,我想删除旧的日志条目)

             var filterDate = dtRemoveLogs.SelectedDate.Value.Date;
             var loadOp = context.Load<ApplicationLog>(context.GetApplicationLogsQuery()
                          .Where(l => l.DateTime.Year <= filterDate.Year
                                   && l.DateTime.Month <= filterDate.Month
                                   && l.DateTime.Day <= filterDate.Day));
            

            我不明白为什么 Jon 的解决方案不起作用....

            【讨论】:

            • 为什么要将一个DateTimeMonth 属性与另一个Year 属性进行比较?
            • 很棒的解决方案。为我在 Web API 中实现日期列比较工作!!!令人惊讶的是,5 年后它对我的帮助也更大。
            • 伟大的......聪明而简单的想法
            【解决方案8】:

            只需使用Date 属性:

            var today = DateTime.Today;
            
            var q = db.Games.Where(t => t.StartDate.Date >= today)
                            .OrderBy(t => t.StartDate);
            

            请注意,我已经明确评估了DateTime.Today一次,以便查询是一致的 - 否则每次执行查询时,甚至 within 执行,@ 987654328@ 可能会更改,因此您会得到不一致的结果。例如,假设您有以下数据:

            Entry 1: March 8th, 8am
            Entry 2: March 10th, 10pm
            Entry 3: March 8th, 5am
            Entry 4: March 9th, 8pm
            

            当然,both 条目 1 和 3 都应该在结果中,或者 都不 应该...但是如果您评估 DateTime.Today 并且它 在执行前两次检查后更改到 3 月 9 日,您最终可能会得到条目 1、2、4。

            当然,使用DateTime.Today 假设您对本地 时区的日期感兴趣。这可能不合适,你应该绝对确保你明白你的意思。例如,您可能想改用DateTime.UtcNow.Date。不幸的是,DateTime is a slippery beast...

            编辑:您可能还想完全摆脱对DateTime 静态属性的调用——它们使代码难以进行单元测试。在Noda Time 中,我们有一个专门用于此目的的接口(@98​​7654323@),我们希望它能够被适当地注入。有一个用于生产的“系统时间”实现和一个用于测试的“存根”实现,或者您可以自己实现。

            当然,您可以在不使用 Noda Time 的情况下使用相同的想法。要对这段特定的代码进行单元测试,您可能需要传入日期,但您将从 somewhere 获取它 - 注入时钟意味着您可以测试 all代码。

            【讨论】:

            • +1。 “可能需要使用 Utc”是个好点。除了缓存“now”的值之外,最好将它作为参数传递给函数,以便您可以对其进行单元测试(使用 DateTime.Today/DateTime.Now 测试代码并不容易)。
            • @AlexeiLevenkov:或者注入一个时钟,是的。将添加。
            • 在 LINQ to Entities 中不支持指定的类型成员“日期”。仅支持初始化器、实体成员和实体导航属性。
            • @SAR:确实 - 我希望在 SqlFunctions 中看到一些东西,但我看不到它......
            • @SAR:MVC 部分无关紧要,“在 LINQ 中”太模糊:您的具体意思是“在实体框架中”。快速搜索发现stackoverflow.com/questions/13539224 - 听起来你想要EntityFunctions.TruncateTime
            【解决方案9】:

            试试

            var q = db.Games.Where(t => t.StartDate.Date >= DateTime.Now.Date).OrderBy(d => d.StartDate);
            

            【讨论】:

            • 查看我的回答,了解为什么这不是一个好主意;此外,DateTime.Today 是一种更简单的方法。
            • @JonSkeet:好点。没听懂。这正是开发过程中永远不会发生的错误之一(因为您可能会在白天进行测试),而是稍后会回来困扰您!
            猜你喜欢
            • 1970-01-01
            • 2021-02-09
            • 1970-01-01
            • 1970-01-01
            • 2020-05-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多