Точность сравнения DateTime - PullRequest
25 голосов
/ 02 июня 2010

Я делаю сравнение DateTime, но я не хочу делать сравнение на уровне секунд, миллисекунд и тиков. Какой самый элегантный способ?

Если я просто сравниваю DateTime, то они редко равны из-за различий в тиках.

Ответы [ 10 ]

29 голосов
/ 02 июня 2010

Как насчет использования временного интервала.

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
}

Лично я думаю, что это более элегантно ...

7 голосов
/ 02 июня 2010

Используя TimeSpan, вы получаете всю необходимую гранулярность:

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;
7 голосов
/ 02 июня 2010

Одним из подходов может быть создание двух новых DateTimes из ваших значений, которые вы хотите сравнить, но игнорируйте все, начиная с секунд и затем сравнивайте их:

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

Я бы первым признал, что это не элегантно, но решает проблему.

5 голосов
/ 23 октября 2015
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);
    }
}

Пример использования:

new DateTimeComparer(DateTimeComparer.Prescision.Day).Compare(Date1, Date2)
4 голосов
/ 02 июня 2010

Вы можете преобразовать их в формат String и сравнить строки друг с другом.

Это также дает свободу выбора параметров сравнения, например, только время без даты и т. Д.

if (String.Format("{0:ddMMyyyyHHmmss}", date1) == String.Format("{0:ddMMyyyyHHmmss}", date2))
{
     // success
}
3 голосов
/ 02 июня 2010

Как насчет этого ComparerClass?

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

Может использоваться

List.Sort(new DateTimeComparer("hh:mm"));
0 голосов
/ 02 октября 2018

Очень простое решение из моего собственного кода:

TimeSpan timeDifference = presentLastSavedDate.Subtract(previousLastSavedDate);
if (timeDifference.Seconds > 0)
{
    return Content(HttpStatusCode.Conflict, ALREADY_CHANGED_MSG);
}
0 голосов
/ 30 декабря 2017

@ Решение ALZ выглядит хорошо, но оно слишком сложное и содержит ошибку. Поэтому я решил объединить это с решением @ 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);
        }
    }
0 голосов
/ 26 июня 2017

Другой способ - сначала конвертировать, обрабатывая на уровне тиков простым (не округляя) расчет:

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
0 голосов
/ 16 января 2015

Я написал это, чтобы помочь себе:

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

Допуск может быть установлен на (10d / 3d) для учета серверов SQL 1/300 мс. Если допуск превышен, делегируйте значение по умолчанию для сравнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...