How to compare two dates in C# on just year, month, day, hour, minute, second?

Viewed 629

I have two dates and I only want to make sure they match on these 6 fields: year, month, day, hour, minute and second.

I have noticed that if I perform a simple equality == comparison if(d1 == d2) that match on these fields, I still get 'false'. I'm assuming this has to do with other fields under the hood that relate to ticks, milliseconds etc. How can I ignore everything and just make sure they match on the 6 fields above?

I have created the prototype function below but to me this feels amateurish and inefficient for production-level code. Furthermore, date1 has to be a nullable datetime.

Does anyone else have any better suggestions?

    private static bool DatesAreEqual(DateTime date1, DateTime date2)
    {

        var d1 = new DateTime(date1.Year, date1.Month, date1.Day,
                    date1.Hour, date1.Minute, date1.Second);

        var d2 = new DateTime(date2.Year, date2.Month, date2.Day,
                    date2.Hour, date2.Minute, date2.Second);

        return d1 == d2;
    }
3 Answers

You can remove fractional part of the dates (please, note, that fractional part is longer then just milliseconds):

DateTime date = DateTime.Now;

// 28 02 2022 22:19:56.3704625 
Console.WriteLine($"{date:dd MM yyyy HH:mm:ss.fffffff}"); 

date -= TimeSpan.FromTicks(date.Ticks % 10_000_000);

// 28 02 2022 22:19:56.0000000
Console.WriteLine($"{date:dd MM yyyy HH:mm:ss.fffffff}");

Code:

DateTime date1 = ...
DateTime date2 = ...

...

if (date1 - TimeSpan.FromTicks(date1.Ticks % 10_000_000) == 
    date2 - TimeSpan.FromTicks(date2.Ticks % 10_000_000)) {
  //TODO: Relevant code here
}

You can implement extension class to keep main code shorter and more readable:

public partial static class DateTimeExtensions {
  public static DateTime TrimToSeconds(this DateTime value) => 
    value - TimeSpan.FromTicks(value.Ticks % 10_000_000)
}

And then

DateTime date1 = ...
DateTime date2 = ...

...

if (date1.TrimToSeconds() == date2.TrimToSeconds()) {
  //TODO: Relevant code here
}

If you check on the TimeSpam, we have the TimeSpan.TicksPerSecond that is the minimum that you want to be the same (the seconds), so we reset that part to zero and we make the compare using ticks (that is the faster) as:

pubic static bool DatesAreEqual(DateTime d1, DateTime d2)
{
    return (d1.Ticks - (d1.Ticks % TimeSpan.TicksPerSecond)) == (d2.Ticks - (d2.Ticks % TimeSpan.TicksPerSecond));
}

With this way you just make some number compare and its the faster way.

More Than That

Base on the above code I also make two more functions with selected Precision and Equal, or Compare functions

public enum DateTimeComparePrecision : long
{
    Millisecond  = TimeSpan.TicksPerMillisecond,
    Second = TimeSpan.TicksPerSecond,
    Minute = TimeSpan.TicksPerMinute,
    Hour = TimeSpan.TicksPerHour,
    Day = TimeSpan.TicksPerDay,
}


public static bool DatesAreEqual(DateTime d1, DateTime d2, DateTimeComparePrecision Precision)
{
    return (d1.Ticks - (d1.Ticks % (long)Precision)) == (d2.Ticks - (d2.Ticks % (long)Precision));
}        


public static int DatesCompare(DateTime d1, DateTime d2, DateTimeComparePrecision Precision)
{
    long Day1 = (d1.Ticks - (d1.Ticks % (long)Precision));
    long Day2 = (d2.Ticks - (d2.Ticks % (long)Precision));

    if (Day2 > Day1) 
        return 1;            

    if (Day2 < Day1)            
        return -1;            

    return 0;
}

Simple Visual Test

DateTime NowIs = DateTime.UtcNow;
Console.WriteLine($"{NowIs:dd MM yyyy HH:mm:ss.fffffff}");

DateTime d1 = new DateTime((NowIs.Ticks - (NowIs.Ticks % TimeSpan.TicksPerMillisecond)));
Console.WriteLine($"{d1:dd MM yyyy HH:mm:ss.fffffff}");

d1 = new DateTime((NowIs.Ticks - (NowIs.Ticks % TimeSpan.TicksPerSecond)));
Console.WriteLine($"{d1:dd MM yyyy HH:mm:ss.fffffff}");

d1 = new DateTime((NowIs.Ticks - (NowIs.Ticks % TimeSpan.TicksPerMinute)));
Console.WriteLine($"{d1:dd MM yyyy HH:mm:ss.fffffff}");

d1 = new DateTime((NowIs.Ticks - (NowIs.Ticks % TimeSpan.TicksPerHour)));
Console.WriteLine($"{d1:dd MM yyyy HH:mm:ss.fffffff}");

d1 = new DateTime((NowIs.Ticks - (NowIs.Ticks % TimeSpan.TicksPerDay)));
Console.WriteLine($"{d1:dd MM yyyy HH:mm:ss.fffffff}");

output

01 03 2022 12:51:26.7237323
01 03 2022 12:51:26.7230000
01 03 2022 12:51:26.0000000
01 03 2022 12:51:00.0000000
01 03 2022 12:00:00.0000000
01 03 2022 00:00:00.0000000
Related