【问题标题】:Compare two nullable dates比较两个可以为空的日期
【发布时间】:2013-02-07 14:47:48
【问题描述】:

我有两个日期属性,它们与我从一个对象映射到另一个对象完全相同。如果我将它们进行如下比较,则返回 false:

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

他们都是{01/06/2011 15:44:32}

我不能使用DateTime.Compare,因为它们可以为空。比较可空日期的最佳方法是什么?

【问题讨论】:

  • Ticks 是否也相同?因为我无法重现该问题,两个 Nullable<DateTime>-objects 彼此分开创建但具有相同的值...
  • 除非我遗漏了其他东西,否则它应该可以工作吗?
  • @Spontifixus 你是对的,蜱虫不同......

标签: c# datetime comparison nullable


【解决方案1】:

检查这些日期的实际刻度,它们可能不同。请注意,DateTime 将 100 ns 间隔记录为其最小单位。格式化 DateTime 时不会显示这些内容。

【讨论】:

  • 你是对的,蜱是不同的..我可以比较没有蜱..而且它们都来自同一个数据库列
  • @Sam1 如果刻度不同,那么它们在数据库中就不一样了。您只是在查看四舍五入的输出到最接近的秒数。如果您想在不考虑毫秒的情况下进行比较,则必须先将值四舍五入。
  • @MattJohnson 感谢您的评论。你能解释一下你所说的四舍五入是什么意思吗?
  • 你可以比较Math.Round(TotalSeconds)或者Math.Truncate来代替。
  • @Sam1 查看我的答案以获得比较舍入日期的完整解决方案
【解决方案2】:

您可以使用Nullable.Compare<T>() 方法比较可空对象,包括可空日期。

if(Nullable.Compare(obj1.d1, obj2.d1) == 0)
{
}

【讨论】:

    【解决方案3】:

    应该可以,请检查:

    var now = DateTime.Now;
    DateTime? d1 = now;
    DateTime? d2 = now;
    
    Console.WriteLine(d1 == d2); // Output: True
    

    我假设它们实际上完全相同,即它们以毫秒或滴答为单位不同。

    【讨论】:

    • 不,刻度不一样.....但是奇怪的是,当它们都来自同一个数据库字段时,它们有什么不同
    • 我可以忽略刻度并只比较日期和时间吗
    • @Sam1 滴答是时间的一部分。您可以将日期四舍五入到最接近的秒或毫秒,或者其他答案/cmets 中提到的任何您想要的值。
    【解决方案4】:

    正如其他答案所表明的那样,默认比较器对于可为空的 DateTime 对象工作得很好。您在 cmets 中询问了如何比较日期的四舍五入形式。你会想要这样的东西:

    if (dt1.EqualsRounded(dt2))
    

    以下是执行此操作所需的所有代码。它完全支持可空和不可空的日期时间。它同时实现了IComparer<T>IEqualityComparer<T>,因此您也可以在排序列表时使用它(例如)。像上面这样的简单情况有扩展方法,并且有重载来提供不同的舍入间隔。如果不指定一个,则默认舍入到最接近的整秒。享受吧!

    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;
        }
    }
    

    【讨论】:

      【解决方案5】:

      您不能在使用.Compare 之前检查它们是否为空吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-01
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多