C# 日期时间比较精度

C# 日期时间比较精度,c#,datetime,comparison,C#,Datetime,Comparison,我正在进行日期时间比较,但我不想在秒、毫秒和滴答级别进行比较。最优雅的方式是什么 如果我只是比较DateTime,那么由于刻度不同,它们很少相等。一种方法可以是根据要比较的值创建两个新的DateTime,但忽略从秒开始的任何内容,然后比较它们: DateTime compare1 = new DateTime(year1, month1, day1, hour1, minute1, 0); DateTime compare2 = new DateTime(year2, month2, day2,

我正在进行日期时间比较,但我不想在秒、毫秒和滴答级别进行比较。最优雅的方式是什么


如果我只是比较DateTime,那么由于刻度不同,它们很少相等。

一种方法可以是根据要比较的值创建两个新的DateTime,但忽略从秒开始的任何内容,然后比较它们:

DateTime compare1 = new DateTime(year1, month1, day1, hour1, minute1, 0);
DateTime compare2 = new DateTime(year2, month2, day2, hour2, minute2, 0);

int result = DateTime.Compare(compare1, compare2);

我会第一个承认它并不优雅,但它解决了问题。

您可以将它们转换为字符串格式,并相互比较字符串

这也让您可以自由选择比较参数,比如只选择时间而不选择日期等

if (String.Format("{0:ddMMyyyyHHmmss}", date1) == String.Format("{0:ddMMyyyyHHmmss}", date2))
{
     // success
}

使用时间跨度怎么样

if (Math.Truncate((A - B).TotalMinutes) == 0)
{
    //There is less than one minute between them
}
可能不是最优雅的方式,但它允许案件是一秒钟的间隔,但有不同的天/小时/分钟的部分,如超过午夜

编辑:我突然想到截断是不必要的

if (Math.Abs((A - B).TotalMinutes) < 1)
{
    //There is less than one minute between them
}
if(Math.Abs((A-B).TotalMinutes)<1)
{
//他们之间只有不到一分钟的时间
}

就个人而言,我认为这更优雅…

这个比较器类怎么样

public class DateTimeComparer : Comparer<DateTime>
{
    private string _Format;

    public DateTimeComparer(string format)
    {
        _Format = format;
    }

    public override int Compare(DateTime x, DateTime y)
    {
        if(x.ToString(_Format) == y.ToString(_Format))
            return 0;

        return x.CompareTo(y);
    }
}

使用时间跨度,您可以获得所需的所有粒度:

DateTime dt1, dt2;
double d = (dt2 - dt1).TotalDays;
double h = (dt2 - dt1).TotalHours;
double m = (dt2 - dt1).TotalMinutes;
double s = (dt2 - dt1).TotalSeconds;
double ms = (dt2 - dt1).TotalMilliseconds;
double ticks = (dt2 - dt1).Ticks;

我写这篇文章是为了帮助自己:

    internal class ImpreciseCompareDate : IComparer<DateTime>
{
    private readonly double _Tolerance;

    public ImpreciseCompareDate(double MillisecondsTolerance)
    {
        _Tolerance = MillisecondsTolerance;
    }

    public int Compare(DateTime x, DateTime y)
    {
        return Math.Abs((x - y).TotalMilliseconds) < _Tolerance ? 0 : x.CompareTo(y);
    }
}
内部类不精确比较:IComparer
{
私有只读双U容差;
公共不精确比较(双毫秒公差)
{
_公差=毫秒公差;
}
公共整数比较(日期时间x,日期时间y)
{
返回Math.Abs((x-y).total毫秒)<\u公差?0:x.CompareTo(y);
}
}

可以将公差设置为(10d/3d)以说明SQL Server的1/300毫秒。如果超过公差,请委托给默认比较器。

另一种方法是首先通过简单(非舍入)计算在刻度级别上进行处理进行转换:

public class DateTimeComparer : Comparer<DateTime>
{
    private Prescision _Prescision;

    public enum Prescision : sbyte
    {
        Millisecons,
        Seconds,
        Minutes,
        Hour,
        Day,
        Month,
        Year,
        Ticks
    }

    Func<DateTime, DateTime>[] actions = new Func<DateTime, DateTime>[]
        {
            (x) => { return x.AddMilliseconds(-x.Millisecond);},
            (x) => { return x.AddSeconds(-x.Second);},
            (x) => { return x.AddMinutes(-x.Minute);},
            (x) => { return x.AddHours(-x.Hour);},
            (x) => { return x.AddDays(-x.Day);},
            (x) => { return x.AddMonths(-x.Month);},
        };

    public DateTimeComparer(Prescision prescision = Prescision.Ticks)
    {
        _Prescision = prescision;
    }

    public override int Compare(DateTime x, DateTime y)
    {
        if (_Prescision == Prescision.Ticks)
        {
            return x.CompareTo(y);
        }

        for (sbyte i = (sbyte)(_Prescision - 1); i >= 0; i--)
        {
            x = actions[i](x);
            y = actions[i](y);
        }

        return x.CompareTo(y);
    }
}
var now = DateTime.UtcNow;
// 636340541021531973, 2017-06-26T06:08:22.1531973Z

var millisecondsPrecision = new DateTime(now.Ticks / 10000 * 10000, now.Kind);
// 636340541021530000, 2017-06-26T06:08:22.1530000Z

var secondsPrecision = new DateTime(now.Ticks / 10000000 * 10000000, now.Kind);
// 636340541020000000, 2017-06-26T06:08:22.0000000Z

var minutePrecision = new DateTime(now.Ticks / (10000000*60) * (10000000*60), now.Kind);
// 636340541000000000, 2017-06-26T06:08:00.0000000Z

@ALZ的解决方案看起来不错,但是太复杂了,并且有一个bug。 所以我决定把它和@ChrisF的解决方案结合起来

    public class DateTimeComparer : Comparer<DateTime>
    {
        public enum Precision
        {
            Years = 0,
            Months,
            Days,
            Hours,
            Minutes,
            Seconds,
            Millisecons,
            Ticks
        }

        private Precision _precision;

        public DateTimeComparer(Precision precision =  Precision.Ticks)
        {
            _precision = precision;
        }

        public override int Compare(DateTime x, DateTime y)
        {
            if (_precision == Precision.Ticks)
            {
                return x.CompareTo(y);
            }

            var xx = AssembleValue(x, _precision);
            var yy = AssembleValue(y, _precision);

            return xx.CompareTo(yy);
        }

        private static DateTime AssembleValue(DateTime input, Precision precision)
        {
            var p = (int)precision;
            var i = 1;
            return new DateTime(input.Year,
                                p >= i++ ? input.Month : 1,
                                p >= i++ ? input.Day : 1,
                                p >= i++ ? input.Hour : 0,
                                p >= i++ ? input.Minute : 0,
                                p >= i++ ? input.Second : 0,
                                p >= i++ ? input.Millisecond : 0);
        }
    }
公共类DateTimeComparer:Comparer
{
公共枚举精度
{
年=0,
月,
天,
小时,
会议记录,
秒,
毫秒,
滴答声
}
私人精度(private Precision);;
公共日期时间比较器(Precision=Precision.Ticks)
{
_精度=精度;
}
公共覆盖整型比较(日期时间x,日期时间y)
{
if(_precision==precision.Ticks)
{
返回x.CompareTo(y);
}
var xx=汇编值(x,_精度);
var yy=汇编值(y,_精度);
返回xx.CompareTo(yy);
}
专用静态DateTime AssembleValue(日期时间输入,精度)
{
var p=(int)精度;
var i=1;
返回新的日期时间(input.Year,
p>=i++?输入。月份:1,
p>=i++?输入。日期:1,
p>=i++?输入。小时:0,
p>=i++?输入。分钟:0,
p>=i++?输入。秒:0,
p>=i++?输入。毫秒:0);
}
}

我自己的代码提供了非常简单的解决方案:

TimeSpan timeDifference = presentLastSavedDate.Subtract(previousLastSavedDate);
if (timeDifference.Seconds > 0)
{
    return Content(HttpStatusCode.Conflict, ALREADY_CHANGED_MSG);
}

我想这里没有西弗子弹。。。这完全取决于你的喜好。。。无论如何,谢谢你问这个问题。。。我从这个问题中学到了很多东西。我只是想指出,根据选定的答案,这个问题是错误的。你不是要比较每分钟的绝对时间,而是要检查经过的时间是否小于某个阈值。我认为。。它应该读起来像((A-B)。TotalMinutes是的,你是对的,我也删除了等号,因为评论中说小于。为了使编辑工作正常,你需要在检查它是否小于1之前调用
Math.Abs
,否则你可能会在2
DateTime
值中有巨大差异。例如
(DateTime.Now-DateTime.Now.AddMinutes(10)).TotalMinutes
将小于1,但总差为10分钟。对于两个不同小时的不同分钟,此解决方案可以返回
true
。我认为此答案不正确。例如:
DateTime A=new DateTime(2016,10,26,10,59,40),B=new DateTime(2016,10,26,11,00,20);
。这种方法的优点显然是能够设置任意公差,而不依赖于datetime已经提供的级别(秒、毫秒等)SQL server的容差在其中一个上是不平衡的。例如,1/300秒。测试显示从2个相等的DateTime值创建的时间跨度下降到同一毫秒,除了TotalMillistics之外,所有类型的值都大于1。@hoang I放弃;我是不正确的。我只是看到您永远无法比较这些值直接;总是会有细微的差别。@hoang现在我很困惑。我确实看到了很大的差别。DateTime d1=DateTime.Now;DateTime d2=new DateTime(d1.Year,d1.Month,d1.Day,d1.Hour,d1.minute,d1.Second,d1.Millists);TimeSpan diff=d2-d1;Debug.Print($“Days:{diff.TotalDays});这是因为有“几个”毫秒后不考虑的刻度。试试这个:DateTime d2=new DateTime(d1.ticks);这个解决方案很好,因为它可以检测它是否为同一分钟(而其他一些解决方案可能会在相隔仅几秒的不同分钟返回true,例如11:59:59和12:00:01)。而且,它的性能应该优于基于字符串的比较。谢谢,这是个好主意。不过,我觉得编写它更优雅,比如
date1.ToString(“ddmmyyyyhmmss”)==date2.ToString(“ddmmyyyyhmmss”)
    public class DateTimeComparer : Comparer<DateTime>
    {
        public enum Precision
        {
            Years = 0,
            Months,
            Days,
            Hours,
            Minutes,
            Seconds,
            Millisecons,
            Ticks
        }

        private Precision _precision;

        public DateTimeComparer(Precision precision =  Precision.Ticks)
        {
            _precision = precision;
        }

        public override int Compare(DateTime x, DateTime y)
        {
            if (_precision == Precision.Ticks)
            {
                return x.CompareTo(y);
            }

            var xx = AssembleValue(x, _precision);
            var yy = AssembleValue(y, _precision);

            return xx.CompareTo(yy);
        }

        private static DateTime AssembleValue(DateTime input, Precision precision)
        {
            var p = (int)precision;
            var i = 1;
            return new DateTime(input.Year,
                                p >= i++ ? input.Month : 1,
                                p >= i++ ? input.Day : 1,
                                p >= i++ ? input.Hour : 0,
                                p >= i++ ? input.Minute : 0,
                                p >= i++ ? input.Second : 0,
                                p >= i++ ? input.Millisecond : 0);
        }
    }
TimeSpan timeDifference = presentLastSavedDate.Subtract(previousLastSavedDate);
if (timeDifference.Seconds > 0)
{
    return Content(HttpStatusCode.Conflict, ALREADY_CHANGED_MSG);
}