How to truncate milliseconds off of a .NET DateTime

.net, c#, datetime

Solution

The following will work for a DateTime that has fractional milliseconds, and also preserves the Kind property (Local, Utc or Undefined).

DateTime dateTime = ... anything ...
dateTime = new DateTime(
    dateTime.Ticks - (dateTime.Ticks % TimeSpan.TicksPerSecond), 
    dateTime.Kind
    );

or the equivalent and shorter:

dateTime = dateTime.AddTicks( - (dateTime.Ticks % TimeSpan.TicksPerSecond));

This could be generalized into an extension method:

public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan)
{
    if (timeSpan == TimeSpan.Zero) return dateTime; // Or could throw an ArgumentException

    // Some comments suggest removing the following line.  I think the check
    // for MaxValue makes sense - it's often used to represent an indefinite expiry date.
    // (The check for DateTime.MinValue has no effect, because DateTime.MinValue % timeSpan
    // is equal to DateTime.MinValue for any non-zero value of timeSpan.  But I think
    // leaving the check in place makes the intent clearer).
    // YMMV and the fact that different people have different expectations is probably
    // part of the reason such a method doesn't exist in the Framework.
    if (dateTime == DateTime.MinValue || DateTime.MaxValue) return dateTime; // do not modify "guard" values

    return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks));
}

which is used as follows:

dateTime = dateTime.Truncate(TimeSpan.FromMilliseconds(1)); // Truncate to whole ms
dateTime = dateTime.Truncate(TimeSpan.FromSeconds(1)); // Truncate to whole second
dateTime = dateTime.Truncate(TimeSpan.FromMinutes(1)); // Truncate to whole minute
...

Problem

I'm trying to compare a time stamp from an incoming request to a database stored value. SQL Server of course keeps some precision of milliseconds on the time, and when read into a .NET DateTime, it includes those milliseconds. The incoming request to the system, however, does not offer that precision, so I need to simply drop the milliseconds. I feel like I'm missing something obvious, but I haven't found an elegant way to do it (C#).

Original source

Related problems