2010-06-02 3 views
22

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

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

+0

Я думаю, что здесь нет пули сивера ... Это полностью зависит от ваших предпочтений ...В любом случае, спасибо, что задали этот вопрос ... Я многое узнал из этого вопроса. 0: –

+1

Я просто хотел указать, что на основе выбранного ответа этот вопрос неверен. Вы не просите сравнить * абсолютное время * с точностью до минуты, вы просите проверить, прошло ли * истекшее время *, чем определенный порог. – ErikE

ответ

25

Что об использовании отрезок времени.

if (Math.Truncate((A - B).TotalMinutes) == 0) 
{ 
    //There is less than one minute between them 
} 

Вероятно, не самый изящный способ, но он позволяет в тех случаях, которые один второй друг от друга, и все же разные дни/часы/минуты такие детали, как происходит в течение ночи.

Edit: это произошло со мной, что усечение является ненужным ...

if (Math.Abs((A - B).TotalMinutes) < 1) 
{ 
    //There is less than one minute between them 
} 

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

+0

Я думаю .. он должен читаться как будто ((A - B) .TotalMinutes <= 1) –

+0

Да, вы правы, я тоже удалил равных, так как комментарий говорит меньше. –

+0

Чтобы ваше редактирование работало, вам нужно вызвать 'Math.Abs', прежде чем проверять, меньше ли он, потому что иначе вы могли бы иметь ** огромную ** разницу в значениях 2' DateTime'. Например, '(DateTime.Now - DateTime.Now.AddMinutes (10)). TotalMinutes' будет меньше 1, но имеет общую разницу в 10 минут. –

6

Одним из подходов может быть создание двух новых 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); 

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

+0

Это решение хорошо, потому что оно обнаруживает, что это одна и та же минута (тогда как некоторые другие решения могут возвращать true для разных минут, которые разделены только на несколько секунд, например, 11:59:59 и 12:00:01). И он должен работать лучше, чем сравнение на основе строк. –

3

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

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

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

Как об этом 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")); 
6

Использование 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; 
+0

Может быть удобен время от времени ... –

+0

Тестирование показывает TimeSpan, созданный из 2 равных значений DateTime до той же миллисекунды, дает всевозможные значения> 1 для всего, кроме TotalMilliseconds. – dudeNumber4

+0

@ dudeNumber4 Можете ли вы показать свой тестовый код? – hoang

0

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

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

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

+0

Преимущество этого подхода, очевидно, заключается в возможности устанавливать произвольный допуск, независимо от уровней, уже предоставленных datetime (секунда, мс и т. Д.), Поскольку толерантность SQL-сервера не прерывается даже на одном из них. то есть. 1/300th секунды. – Sprague

4
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) 
0

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

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

@ решение 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); 
     } 
    } 
Смежные вопросы