2

I have two date properties and they are exactly the same as i am mapping from one object to another. If I compare them as below it returns false:

if(obj1.d1 == obj2.d1)
{
}

both of them are {01/06/2011 15:44:32}.

I cannot use DateTime.Compare as they are nullable. what would be the best way to compare nullable dates?

Zaki
  • 5,540
  • 7
  • 54
  • 91

5 Answers5

7

Check the actual ticks of those dates, they might be different. Note that DateTime records 100 ns intervals as its smallest unit. Those aren't shown when you format the DateTime.

Joey
  • 344,408
  • 85
  • 689
  • 683
  • you are right the ticks are different.. can i compare without ticks..also they both come from same database column – Zaki Feb 07 '13 at 15:01
  • 1
    @Sam1 If the ticks are different, then they're not the same in the database. You are just looking at the rounded output to the nearest second. If you want to compare without regard to milliseconds, you'll have to round the values first. – Matt Johnson-Pint Feb 07 '13 at 15:04
  • @MattJohnson thanks for the comment. can you please explain what you mean by round up? – Zaki Feb 07 '13 at 15:07
  • You can compare `Math.Round(TotalSeconds)` or maybe `Math.Truncate` instead. – Joey Feb 07 '13 at 16:38
  • @Sam1 see my answer for a complete solution to comparing rounded dates – Matt Johnson-Pint Feb 07 '13 at 23:38
3

You can compare nullable objects, including nullable dates, with the Nullable.Compare<T>() method.

if(Nullable.Compare(obj1.d1, obj2.d1) == 0)
{
}
Brad Rem
  • 6,036
  • 2
  • 25
  • 50
1

That should work, please check:

var now = DateTime.Now;
DateTime? d1 = now;
DateTime? d2 = now;

Console.WriteLine(d1 == d2); // Output: True

I assume that they are actually not exactly the same, i.e. they differ in milliseconds or ticks.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • no the ticks are not the same.....but strange how they are different when they both come from same database field – Zaki Feb 07 '13 at 14:58
  • can i ignore the ticks and compare date and time only – Zaki Feb 07 '13 at 15:00
  • @Sam1 ticks are a part of the time. You can round the dates to the nearest second, or millisecond, or whatever you want as mentioned in other answers/comments. – Servy Feb 07 '13 at 16:59
1

As the other answers have indicated, the default comparer will work just fine for nullable DateTime objects. You have asked in comments how to compare a rounded form of the dates. You would want something like:

if (dt1.EqualsRounded(dt2))

Below is all the code you will need to do this. It fully supports nullable and non-nullable DateTimes. It implements both IComparer<T> and IEqualityComparer<T> so you can also use this when sorting lists (for example). There are extension methods for the simple case like the one above, and there are overloads to provide a different rounding interval. Without specifying one, it defaults to round to the nearest whole second. Enjoy!

public static class DateTimeExtensions
{
    public static DateTime RoundToNearestInterval(this DateTime dateTime, TimeSpan interval)
    {
        // Adapted from http://stackoverflow.com/questions/1393696/c-rounding-datetime-objects

        // do the rounding
        var intervalTicks = interval.Ticks;
        var ticks = (dateTime.Ticks + (intervalTicks / 2) + 1) / intervalTicks;
        var totalTicks = ticks * intervalTicks;

        // make sure the result is not to low
        if (totalTicks < 0)
            totalTicks = 0;

        // make sure the result is not to high
        const long maxTicks = 0x2bca2875f4373fffL; // DateTime.MaxTicks
        if (totalTicks > maxTicks)
            totalTicks = maxTicks;

        // return the new date from the result
        return new DateTime(totalTicks, dateTime.Kind);
    }

    public static bool EqualsRounded(this DateTime x, DateTime y)
    {
        return x.EqualsRounded(y, TimeSpan.FromSeconds(1));
    }

    public static bool EqualsRounded(this DateTime x, DateTime y, TimeSpan interval)
    {
        var comparer = new RoundedDateTimeComparer(interval);
        return comparer.Equals(x, y);
    }

    public static bool EqualsRounded(this DateTime? x, DateTime? y)
    {
        return x.EqualsRounded(y, TimeSpan.FromSeconds(1));
    }

    public static bool EqualsRounded(this DateTime? x, DateTime? y, TimeSpan interval)
    {
        var comparer = new RoundedDateTimeComparer(interval);
        return comparer.Equals(x, y);
    }

    public static int CompareRounded(this DateTime x, DateTime y)
    {
        return x.CompareRounded(y, TimeSpan.FromSeconds(1));
    }

    public static int CompareRounded(this DateTime x, DateTime y, TimeSpan interval)
    {
        var comparer = new RoundedDateTimeComparer(interval);
        return comparer.Compare(x, y);
    }

    public static int CompareRounded(this DateTime? x, DateTime? y)
    {
        return x.CompareRounded(y, TimeSpan.FromSeconds(1));
    }

    public static int CompareRounded(this DateTime? x, DateTime? y, TimeSpan interval)
    {
        var comparer = new RoundedDateTimeComparer(interval);
        return comparer.Compare(x, y);
    }
}

public class RoundedDateTimeComparer : 
    IComparer<DateTime>, IComparer<DateTime?>,
    IEqualityComparer<DateTime>, IEqualityComparer<DateTime?>
{
    private readonly TimeSpan _interval;

    public RoundedDateTimeComparer(TimeSpan interval)
    {
        _interval = interval;
    }

    public int Compare(DateTime x, DateTime y)
    {
        var roundedX = x.RoundToNearestInterval(_interval);
        var roundedY = y.RoundToNearestInterval(_interval);
        return roundedX.CompareTo(roundedY);
    }

    public int Compare(DateTime? x, DateTime? y)
    {
        return x.HasValue && y.HasValue ? Compare(x.Value, y.Value) : (y.HasValue ? 1 : (x.HasValue ? -1 : 0));
    }

    public bool Equals(DateTime x, DateTime y)
    {
        var roundedX = x.RoundToNearestInterval(_interval);
        var roundedY = y.RoundToNearestInterval(_interval);
        return roundedX.Equals(roundedY);
    }

    public bool Equals(DateTime? x, DateTime? y)
    {
        return x.HasValue && y.HasValue ? Equals(x.Value, y.Value) : x.Equals(y);
    }

    public int GetHashCode(DateTime obj)
    {
        var rounded = obj.RoundToNearestInterval(_interval);
        return rounded.GetHashCode();
    }

    public int GetHashCode(DateTime? obj)
    {
        return obj.HasValue ? GetHashCode(obj.Value) : 0;
    }
}
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
0

Can't you just check if they're null before you use .Compare?

Ian Jacobs
  • 5,456
  • 1
  • 23
  • 38