Еквівалент Math.Min & Math.Max ​​для дат?


369

Який найшвидший і найпростіший спосіб отримати значення Min (або Max) між двома датами? Чи є еквівалент Math.Min (& Math.Max) за датами?

Я хочу зробити щось на кшталт:

 if (Math.Min(Date1, Date2) < MINIMUM_ALLOWED_DATE) {
      //not allowed to do this
 }

Очевидно, що вищевказаний Math.Min не працює, оскільки вони є датами.

Відповіді:


416

Для значень DateTime немає перевантаження, але ви можете отримати довге значення Ticks, яке містять ці значення, порівняти їх, а потім створити нове значення DateTime з результату:

new DateTime(Math.Min(Date1.Ticks, Date2.Ticks))

(Зверніть увагу, що структура DateTime також містить Kindвластивість, яка не зберігається в новому значенні. Це, як правило, не проблема; якщо порівнювати значення DateTime різних видів, порівняння все одно не має сенсу.)


2
мені здалося, це найближче до заміни однієї лінії / еквівалента для Math.Min, але інші відповіді теж були чудовими, для повноти
hawbsl

6
-, ви повністю втрачаєте будь-яку інформацію (крім кліщів) оригінальної System.DateTimeречовини
Андреас Нідермайр

9
@AndreasNiedermair: Якщо ви порівнюєте дати різних видів, ви не можете просто порівняти їх у будь-якому випадку. Я вже висвітлював це у відповіді.
Гуффа

4
@Iain: Ви завжди можете їх порівняти, але якщо порівнювати значення, які не можна порівняти, результат марний. Це так само, як і будь-які інші значення, які не можна порівняти, як порівняння відстані в кілометрах з відстані в милях; ви можете порівняти значення просто чудово, але це нічого не означає.
Guffa

4
-1 для рукоділля про Добрий. Як показано у відповіді @ user450, досить просто перетворити обидва рази на UTC та безпечно порівняти їх, не відкидаючи інформацію.
пієдар

484

Не існує вбудованого методу для цього. Ви можете використовувати вираз:

(date1 > date2 ? date1 : date2)

щоб знайти максимум двох.

Ви можете написати загальний метод для обчислення Minабо Maxдля будь-якого типу (за умови, що Comparer<T>.Defaultвстановлено відповідним чином):

public static T Max<T>(T first, T second) {
    if (Comparer<T>.Default.Compare(first, second) > 0)
        return first;
    return second;
}

Ви також можете використовувати LINQ:

new[]{date1, date2, date3}.Max()

15
Це насправді відповідь, яка заслуговує на те, щоб її прийняти.
Ларрі

38

Як щодо:

public static T Min<T>(params T[] values)
{
    if (values == null) throw new ArgumentNullException("values");
    var comparer = Comparer<T>.Default;
    switch(values.Length) {
        case 0: throw new ArgumentException();
        case 1: return values[0];
        case 2: return comparer.Compare(values[0],values[1]) < 0
               ? values[0] : values[1];
        default:
            T best = values[0];
            for (int i = 1; i < values.Length; i++)
            {
                if (comparer.Compare(values[i], best) < 0)
                {
                    best = values[i];
                }
            }
            return best;
    }        
}
// overload for the common "2" case...
public static T Min<T>(T x, T y)
{
    return Comparer<T>.Default.Compare(x, y) < 0 ? x : y;
}

Працює з будь-яким типом, який підтримує IComparable<T>або IComparable.

Насправді, з LINQ, ще одна альтернатива:

var min = new[] {x,y,z}.Min();

6
Проголосуйте за приклад LINQ.
Безвісти

20
public static class DateTool
{
    public static DateTime Min(DateTime x, DateTime y)
    {
        return (x.ToUniversalTime() < y.ToUniversalTime()) ? x : y;
    }
    public static DateTime Max(DateTime x, DateTime y)
    {
        return (x.ToUniversalTime() > y.ToUniversalTime()) ? x : y;
    }
}

Це дозволяє датам мати різні "види" і повертає переданий екземпляр (не повертаючи новий DateTime, побудований з Ticks або Milliseconds).

[TestMethod()]
    public void MinTest2()
    {
        DateTime x = new DateTime(2001, 1, 1, 1, 1, 2, DateTimeKind.Utc);
        DateTime y = new DateTime(2001, 1, 1, 1, 1, 1, DateTimeKind.Local);

        //Presumes Local TimeZone adjustment to UTC > 0
        DateTime actual = DateTool.Min(x, y);
        Assert.AreEqual(x, actual);
    }

Зауважте, що цей тест не вдасться на схід від Грінвічу ...


Чому б просто не скинути частину ToUniversalTime ()?
Девід Тілен

18

Linq.Min()/ Linq.Max()підхід:

DateTime date1 = new DateTime(2000,1,1);
DateTime date2 = new DateTime(2001,1,1);

DateTime minresult = new[] { date1,date2 }.Min();
DateTime maxresult = new[] { date1,date2 }.Max(); 

17

Якщо ви хочете назвати це більше як Math.Max, ви можете зробити щось на кшталт цього дуже короткого виразу тіла:

public static DateTime Max(params DateTime[] dates) => dates.Max();
[...]
var lastUpdatedTime = DateMath.Max(feedItemDateTime, assemblyUpdatedDateTime);

о, це геній! Таким чином, мені не доведеться порівнювати кожен раз, лише один раз після того, як я закінчу з даними. Дуже дякую!
tfrascaroli

Це дуже елегантне рішення
pberggreen

2

Як щодо DateTimeспособу розширення?

public static DateTime MaxOf(this DateTime instance, DateTime dateTime)
{
    return instance > dateTime ? instance : dateTime;
}

Використання:

var maxDate = date1.MaxOf(date2);

Я вважаю за краще використовувати його як DateTime.MaxOf(dt1, dt2), але не знаю, як це зробити ...
Зах Сміт

@ZachSmith Ви не можете перевантажувати клас DateTime, оскільки він не є частковим. Можливо, ми можемо використовувати DateTimeHelper.Max (dt1, dt2)
shtse8

@ shtse8 - що ви маєте на увазі під перевантаженням? Я думав додати метод розширення. але з тих пір дізналися, що це неможливо зробити без екземпляра. звучить так, як ви говорите, що додавання методу розширення є формою перевантаження? я ніколи цього не вважав .. це правильно? тепер, коли я думаю про це ... що саме означає перевантаження?
Зак Сміт

@ZachSmith О, я думав, ви додаєте розширення під назвою "DateTime.MaxOf (dt1, dt2)" так само, як "DateTime.Now", яке базується на статичних членах DateTime.
шце8

-2

Тепер, коли у нас є LINQ, ви можете створити масив з вашими двома значеннями (DateTimes, TimeSpans, що завгодно), а потім скористатися методом розширення .Max ().

var values = new[] { Date1, Date2 }; 
var max = values.Max(); 

Він читає приємно, він настільки ж ефективний, як Макс, і він може використовуватись повторно для більш ніж двох значень порівняння.

Вся проблема внизу турбується. Добре - це велика справа ... але я уникаю цього, ніколи не працюючи в місцеві часи, ніколи. Якщо у мене є щось важливе щодо часу, я завжди працюю в UTC, навіть якщо це означає більше роботи, щоб потрапити туди.


1
копія моєї відповіді
Toshi

-3
// Two different dates
var date1 = new Date(2013, 05, 13); 
var date2 = new Date(2013, 04, 10) ;
// convert both dates in milliseconds and use Math.min function
var minDate = Math.min(date1.valueOf(), date2.valueOf());
// convert minDate to Date
var date = new Date(minDate); 

http://jsfiddle.net/5CR37/


Гарна пропозиція (справді), але без опису важко знайти, чому це добре. Опишіть, будь ласка, де трюк. Без опису це лише код коду, а не відповідь.
Артемікс

3
питання позначено тегом .NET not Javascript
hawbsl

Вибачте, не помітили .NET. У будь-якому випадку ми можемо знайти мінімальну дату на стороні клієнта та надіслати її на сервер.
Сергій Суворов

4
Ви припускаєте, що ми говоримо про asp, що не обов'язково правильно. Також було б досить нерозумно підрахувати різницю на Клієнта, оскільки існує набагато більше ризиків (відключений JavaScript), це генерує зайвий трафік, і буде (залежно від швидкості мережі) повільніше
jalgames
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.