371
votes

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#).

17
(3rd try...) Since 20% of the answers (1, 2, 3) describe how to omit or remove the milliseconds component from the formatted string representation of a DateTime, perhaps an edit is needed to make it clear that to "truncate"/"drop" milliseconds means "produce a DateTime value where all date/time components are the same except TimeOfDay.TotalMilliseconds is 0." People don't read, of course, but just to eliminate any ambiguity. - Lance U. Matthews

17 Answers

614
votes

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
    if (dateTime == DateTime.MinValue || dateTime == 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
...
166
votes
var date = DateTime.Now;

date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind);
72
votes

Here is an extension method based on a previous answer that will let you truncate to any resolution...

Usage:

DateTime myDateSansMilliseconds = myDate.Truncate(TimeSpan.TicksPerSecond);
DateTime myDateSansSeconds = myDate.Truncate(TimeSpan.TicksPerMinute)

Class:

public static class DateTimeUtils
{
    /// <summary>
    /// <para>Truncates a DateTime to a specified resolution.</para>
    /// <para>A convenient source for resolution is TimeSpan.TicksPerXXXX constants.</para>
    /// </summary>
    /// <param name="date">The DateTime object to truncate</param>
    /// <param name="resolution">e.g. to round to nearest second, TimeSpan.TicksPerSecond</param>
    /// <returns>Truncated DateTime</returns>
    public static DateTime Truncate(this DateTime date, long resolution)
    {
        return new DateTime(date.Ticks - (date.Ticks % resolution), date.Kind);
    }
}
31
votes
DateTime d = DateTime.Now;
d = d.AddMilliseconds(-d.Millisecond);
12
votes

Sometimes you want to truncate to something calendar-based, like year or month. Here's an extension method that lets you choose any resolution.

public enum DateTimeResolution
{
    Year, Month, Day, Hour, Minute, Second, Millisecond, Tick
}

public static DateTime Truncate(this DateTime self, DateTimeResolution resolution = DateTimeResolution.Second)
{
    switch (resolution)
    {
        case DateTimeResolution.Year:
            return new DateTime(self.Year, 1, 1, 0, 0, 0, 0, self.Kind);
        case DateTimeResolution.Month:
            return new DateTime(self.Year, self.Month, 1, 0, 0, 0, self.Kind);
        case DateTimeResolution.Day:
            return new DateTime(self.Year, self.Month, self.Day, 0, 0, 0, self.Kind);
        case DateTimeResolution.Hour:
            return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerHour));
        case DateTimeResolution.Minute:
            return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerMinute));
        case DateTimeResolution.Second:
            return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerSecond));
        case DateTimeResolution.Millisecond:
            return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerMillisecond));
        case DateTimeResolution.Tick:
            return self.AddTicks(0);
        default:
            throw new ArgumentException("unrecognized resolution", "resolution");
    }
}
9
votes

Instead of dropping the milliseconds then comparing, why not compare the difference?

DateTime x; DateTime y;
bool areEqual = (x-y).TotalSeconds == 0;

or

TimeSpan precision = TimeSpan.FromSeconds(1);
bool areEqual = (x-y).Duration() < precision;
7
votes

Less obvious but more than 2 times faster :

// 10000000 runs

DateTime d = DateTime.Now;

// 484,375ms
d = new DateTime((d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);

// 1296,875ms
d = d.AddMilliseconds(-d.Millisecond);
6
votes

To round down to the second:

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

Replace with TicksPerMinute to round down to the minute.


If your code is performance sensitive, be cautious about

new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second)

My app was spending 12% of CPU time in System.DateTime.GetDatePart.

4
votes

Not the fastest solution but simple and easy to understand:

DateTime d = DateTime.Now;
d = d.Date.AddHours(d.Hour).AddMinutes(d.Minute).AddSeconds(d.Second)
3
votes

A way for easy reading is...

//Remove milliseconds
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH:mm:ss"), "yyyy-MM-dd HH:mm:ss", null);

And more...

//Remove seconds
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH:mm"), "yyyy-MM-dd HH:mm", null);

//Remove minutes
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH"), "yyyy-MM-dd HH", null);

//and go on...
1
votes

Regarding Diadistis response. This worked for me, except I had to use Floor to remove the fractional part of the division before the multiplication. So,

d = new DateTime((d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);

becomes

d = new DateTime(Math.Floor(d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);

I would have expected the division of two Long values to result in a Long, thus removing the decimal part, but it resolves it as a Double leaving the exact same value after the multiplication.

Eppsy

1
votes

2 Extension methods for the solutions mentioned above

    public static bool LiesAfterIgnoringMilliseconds(this DateTime theDate, DateTime compareDate, DateTimeKind kind)
    {
        DateTime thisDate = new DateTime(theDate.Year, theDate.Month, theDate.Day, theDate.Hour, theDate.Minute, theDate.Second, kind);
        compareDate = new DateTime(compareDate.Year, compareDate.Month, compareDate.Day, compareDate.Hour, compareDate.Minute, compareDate.Second, kind);

        return thisDate > compareDate;
    }


    public static bool LiesAfterOrEqualsIgnoringMilliseconds(this DateTime theDate, DateTime compareDate, DateTimeKind kind)
    {
        DateTime thisDate = new DateTime(theDate.Year, theDate.Month, theDate.Day, theDate.Hour, theDate.Minute, theDate.Second, kind);
        compareDate = new DateTime(compareDate.Year, compareDate.Month, compareDate.Day, compareDate.Hour, compareDate.Minute, compareDate.Second, kind);

        return thisDate >= compareDate;
    }

usage:

bool liesAfter = myObject.DateProperty.LiesAfterOrEqualsIgnoringMilliseconds(startDateTime, DateTimeKind.Utc);
1
votes

This is my version of the extension methods posted here and in similar questions. This validates the ticks value in an easy to read way and preserves the DateTimeKind of the original DateTime instance. (This has subtle but relevant side effects when storing to a database like MongoDB.)

If the true goal is to truncate a DateTime to a specified value (i.e. Hours/Minutes/Seconds/MS) I recommend implementing this extension method in your code instead. It ensures that you can only truncate to a valid precision and it preserves the important DateTimeKind metadata of your original instance:

public static DateTime Truncate(this DateTime dateTime, long ticks)
{
    bool isValid = ticks == TimeSpan.TicksPerDay 
        || ticks == TimeSpan.TicksPerHour 
        || ticks == TimeSpan.TicksPerMinute 
        || ticks == TimeSpan.TicksPerSecond 
        || ticks == TimeSpan.TicksPerMillisecond;

    // https://stackguides.com/questions/21704604/have-datetime-now-return-to-the-nearest-second
    return isValid 
        ? DateTime.SpecifyKind(
            new DateTime(
                dateTime.Ticks - (dateTime.Ticks % ticks)
            ),
            dateTime.Kind
        )
        : throw new ArgumentException("Invalid ticks value given. Only TimeSpan tick values are allowed.");
}

Then you can use the method like this:

DateTime dateTime = DateTime.UtcNow.Truncate(TimeSpan.TicksPerMillisecond);

dateTime.Kind => DateTimeKind.Utc
0
votes
DateID.Text = DateTime.Today.ToShortDateString();

Use ToShortDateString() //Date 2-02-2016
Use ToShortDateString() // Time 

And By Use Of

ToLongDateString() // its show 19 February 2016.

:P

0
votes

New Method

String Date = DateTime.Today.ToString("dd-MMM-yyyy"); 

// define String pass parameter dd-mmm-yyyy return 24-feb-2016

Or shown on textbox

txtDate.Text = DateTime.Today.ToString("dd-MMM-yyyy");

// put on PageonLoad

0
votes

In my case, I was aiming to save TimeSpan from datetimePicker tool without saving the seconds and the milliseconds, and here is the solution.

First convert the datetimePicker.value to your desired format, which mine is "HH:mm" then convert it back to TimeSpan.

var datetime = datetimepicker1.Value.ToString("HH:mm");
TimeSpan timeSpan = Convert.ToDateTime(datetime).TimeOfDay;
-1
votes

I know the answer is quite late, but the best way to get rid of milliseconds is

var currentDateTime = DateTime.Now.ToString("s");

Try printing the value of the variable, it will show the date time, without milliseconds.