C#
LINQ
DateTime
Programming
Code Comparison

How to compare DateTime without time via LINQ?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When comparing DateTime values in C# LINQ queries, the time component (hours, minutes, seconds) is included by default. Two records from the same day but different times will not be considered equal. To compare only the date portion, use the .Date property (which zeros out the time), DateOnly (.NET 6+), or DbFunctions.TruncateTime in Entity Framework. The approach depends on whether the query runs in memory (LINQ to Objects) or is translated to SQL (LINQ to Entities/EF Core).

The Problem

csharp
1var orders = new List<Order>
2{
3    new Order { Id = 1, CreatedAt = new DateTime(2025, 3, 15, 9, 30, 0) },
4    new Order { Id = 2, CreatedAt = new DateTime(2025, 3, 15, 14, 45, 0) },
5    new Order { Id = 3, CreatedAt = new DateTime(2025, 3, 16, 8, 0, 0) },
6};
7
8var targetDate = new DateTime(2025, 3, 15, 0, 0, 0);
9
10// WRONG — only matches exact time (midnight)
11var exact = orders.Where(o => o.CreatedAt == targetDate).ToList();
12// Returns empty list — no orders at exactly midnight

LINQ to Objects: Use .Date Property

For in-memory collections, DateTime.Date returns a new DateTime with the time set to 00:00:00.

csharp
1var targetDate = new DateTime(2025, 3, 15);
2
3// Compare date portions only
4var result = orders
5    .Where(o => o.CreatedAt.Date == targetDate.Date)
6    .ToList();
7// Returns orders 1 and 2 (both on March 15)
8
9// Date range comparison
10var startDate = new DateTime(2025, 3, 15);
11var endDate = new DateTime(2025, 3, 16);
12
13var range = orders
14    .Where(o => o.CreatedAt.Date >= startDate.Date && o.CreatedAt.Date <= endDate.Date)
15    .ToList();
16// Returns all three orders

Entity Framework Core: .Date in Queries

EF Core can translate .Date to SQL for most database providers.

csharp
1// EF Core translates .Date to SQL CAST or CONVERT
2var result = dbContext.Orders
3    .Where(o => o.CreatedAt.Date == targetDate.Date)
4    .ToList();
5
6// Generated SQL (SQL Server):
7// WHERE CONVERT(date, [o].[CreatedAt]) = @targetDate

Entity Framework 6: DbFunctions.TruncateTime

In older Entity Framework 6, .Date is not supported in LINQ queries. Use DbFunctions.TruncateTime instead.

csharp
1using System.Data.Entity;
2
3var result = dbContext.Orders
4    .Where(o => DbFunctions.TruncateTime(o.CreatedAt) == DbFunctions.TruncateTime(targetDate))
5    .ToList();
6
7// Older EF versions used EntityFunctions.TruncateTime (now obsolete)

Range-Based Comparison (Most Efficient for SQL)

Instead of stripping the time, use a range that covers the entire day. This is index-friendly because it does not wrap the column in a function.

csharp
1var dayStart = targetDate.Date;                    // 2025-03-15 00:00:00
2var dayEnd = targetDate.Date.AddDays(1);           // 2025-03-16 00:00:00
3
4var result = dbContext.Orders
5    .Where(o => o.CreatedAt >= dayStart && o.CreatedAt < dayEnd)
6    .ToList();
7
8// Generated SQL:
9// WHERE [o].[CreatedAt] >= @dayStart AND [o].[CreatedAt] < @dayEnd
10// This uses the index on CreatedAt efficiently

Using DateOnly (.NET 6+)

csharp
1// .NET 6+ introduces DateOnly which has no time component
2DateOnly targetDate = new DateOnly(2025, 3, 15);
3
4// Convert DateTime to DateOnly for comparison
5var result = orders
6    .Where(o => DateOnly.FromDateTime(o.CreatedAt) == targetDate)
7    .ToList();
8
9// EF Core 8+ supports DateOnly columns directly
10// Map your entity property as DateOnly instead of DateTime
11public class Order
12{
13    public int Id { get; set; }
14    public DateOnly OrderDate { get; set; }  // No time component stored
15}

Grouping by Date (Ignoring Time)

csharp
1// Group orders by date, ignoring time
2var grouped = orders
3    .GroupBy(o => o.CreatedAt.Date)
4    .Select(g => new
5    {
6        Date = g.Key,
7        Count = g.Count(),
8        TotalAmount = g.Sum(o => o.Amount)
9    })
10    .OrderBy(g => g.Date)
11    .ToList();

Common Pitfalls

  • Using .Date in Entity Framework 6 queries: EF6 cannot translate DateTime.Date to SQL and throws NotSupportedException. Use DbFunctions.TruncateTime() in EF6 queries. EF Core handles .Date correctly.
  • Function-wrapped columns preventing index use: WHERE CONVERT(date, CreatedAt) = @date cannot use an index on CreatedAt. For large tables, use range comparison (>= dayStart AND < dayEnd) instead, which allows the database to use indexes.
  • Time zone mismatches: Comparing DateTime.Date when values are in different time zones gives wrong results. A UTC timestamp of 2025-03-15T23:00:00Z is March 16 in UTC+2. Normalize to the same time zone before comparing dates.
  • Comparing DateTime with DateTime? (nullable): If the column is nullable, o.CreatedAt.Value.Date throws NullReferenceException when the value is null. Filter nulls first: .Where(o => o.CreatedAt.HasValue && o.CreatedAt.Value.Date == target).
  • Off-by-one in day-end boundary: Using <= dayEnd instead of < dayEnd includes records at exactly midnight of the next day. Always use exclusive upper bound: CreatedAt < targetDate.AddDays(1).

Summary

  • Use .Date property in LINQ to Objects to strip the time component
  • Use DbFunctions.TruncateTime() in Entity Framework 6 queries
  • Use range comparison (>= start AND < end) for index-friendly SQL queries
  • Use DateOnly (.NET 6+) for columns that should never have a time component
  • Always consider time zones when comparing dates across different systems

Course illustration
Course illustration

All Rights Reserved.