Odpowiednik Math.Min i Math.Max ​​dla dat?


369

Jaki jest najszybszy i najłatwiejszy sposób na uzyskanie wartości Min (lub Max) między dwiema datami? Czy istnieje odpowiednik Math.Min (i Math.Max) dla dat?

Chcę zrobić coś takiego:

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

Oczywiście powyższe Math.Min nie działa, ponieważ są datami.

Odpowiedzi:


416

Nie ma przeciążenia wartości DateTime, ale można uzyskać długą wartość, Ticksktórą zawierają wartości, porównać je, a następnie utworzyć nową wartość DateTime z wyniku:

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

(Pamiętaj, że struktura DateTime zawiera również Kindwłaściwość, która nie jest zachowana w nowej wartości. Zwykle nie stanowi to problemu; jeśli porównasz różne wartości DateTime różnego rodzaju, porównanie i tak nie ma sensu).


2
Wydawało mi się, że jest to najbliższe jednokrotnej zamiany / ekwiwalentu dla Math.Min, ale inne odpowiedzi też były świetne, dla kompletności
hawbsl

6
-, całkowicie tracisz wszystkie informacje (z wyjątkiem System.DateTimetyknięć) oryginalnej
Andreas Niedermair

9
@AndreasNiedermair: Jeśli porównujesz różne rodzaje dat, i tak nie możesz ich od razu porównać. Omówiłem to już w odpowiedzi.
Guffa,

4
@Iain: Zawsze możesz je porównać, ale jeśli porównasz wartości, które nie są porównywalne, wynik jest bezużyteczny. Jest tak samo jak w przypadku innych wartości, które nie są porównywalne, jak na przykład porównywanie odległości w kilometrach z odległością w milach; możesz dobrze porównać wartości, ale to nic nie znaczy.
Guffa

4
-1 za falowanie ręczne o rodzaju. Jak pokazano w odpowiedzi @ user450, dość łatwo jest przekonwertować oba czasy na UTC i bezpiecznie je porównać bez odrzucania informacji.
piedar

484

Nie ma wbudowanej metody, aby to zrobić. Możesz użyć wyrażenia:

(date1 > date2 ? date1 : date2)

znaleźć maksimum z dwóch.

Możesz napisać ogólną metodę obliczania Minlub Maxdla dowolnego typu (pod warunkiem, że Comparer<T>.Defaultjest odpowiednio ustawiona):

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

Możesz także użyć LINQ:

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

15
TO jest właściwie odpowiedź, która zasługuje na akceptację.
Larry,

38

Co powiesz na:

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

Działa z każdym typem, który obsługuje IComparable<T>lub IComparable.

W przypadku LINQ kolejną alternatywą jest:

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

6
Głosuj na przykład LINQ.
Oundless,

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

Dzięki temu daty mogą mieć różne „rodzaje” i zwraca instancję, która została przekazana (nie zwracając nowego DateTime zbudowanego z Ticks lub Milisekund).

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

Pamiętaj, że ten test nie powiedzie się na wschód od Greenwich ...


Dlaczego nie po prostu upuścić części ToUniversalTime ()?
David Thielen,

18

Linq.Min()/ Linq.Max()podejście:

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

Jeśli chcesz nazwać to bardziej Math.Max, możesz zrobić coś takiego: to bardzo krótkie wyrażenie:

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

och, to geniusz! W ten sposób nie muszę porównywać za każdym razem, tylko raz po skończeniu z danymi. Dziękuję Ci bardzo!
tfrascaroli

To bardzo eleganckie rozwiązanie
pberggreen,

2

Co powiesz na DateTimemetodę rozszerzenia?

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

Stosowanie:

var maxDate = date1.MaxOf(date2);

Wolałbym go używać jako DateTime.MaxOf(dt1, dt2), ale nie wiem, jak to zrobić ...
Zach Smith

@ZachSmith Nie można przeciążać klasy DateTime, ponieważ nie jest ona częściowa. Może możemy użyć DateTimeHelper.Max (dt1, dt2)
shtse8

@ shtse8 - co rozumiesz przez przeciążanie? myślałem o dodaniu metody rozszerzenia. ale od tego czasu dowiedziałem się, że nie można tego zrobić bez instancji instancji. brzmi jak mówisz, że dodanie metody rozszerzenia jest formą przeciążenia? nigdy nie zastanawiałem się nad tym .. czy to prawda? teraz, gdy o tym myślę ... co dokładnie oznacza przeciążenie?
Zach Smith

@ZachSmith Oh, myślałem, że dodajesz rozszerzenie o nazwie „DateTime.MaxOf (dt1, dt2)” podobnie jak „DateTime.Now”, które jest oparte na elementach statycznych DateTime.
shtse8

-2

Teraz, gdy mamy LINQ, możesz utworzyć tablicę z dwiema wartościami (DateTimes, TimeSpans, cokolwiek), a następnie użyć metody rozszerzenia .Max ().

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

Ładnie brzmi, jest tak wydajny, jak to tylko możliwe, i może być używany do więcej niż 2 wartości porównania.

Cały problem poniżej martwiący się o. Rodzaj to wielka sprawa ... ale unikam tego, nigdy nie pracując w lokalnych czasach. Jeśli mam coś ważnego co do czasu, zawsze pracuję w UTC, nawet jeśli oznacza to więcej pracy, aby się tam dostać.


1
kopia mojej odpowiedzi
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/


Dobra sugestia (naprawdę), ale bez opisu trudno jest ustalić, dlaczego jest dobra. Proszę opisać, gdzie jest podstęp. Bez opisu jest to tylko blok kodu, a nie odpowiedź.
Artemix,

3
pytanie jest oznaczone .NET nie JavaScript
hawbsl

Przepraszamy, nie zauważyłem .NET. W każdym razie możemy znaleźć datę minimalną po stronie klienta i wysłać ją na serwer.
Siergiej Suworow

4
Zakładasz, że mówimy o boleniu, co niekoniecznie ma rację. Obliczenie różnicy na kliencie byłoby również głupie, ponieważ istnieje o wiele większe ryzyko (JavaScript wyłączony), generowałoby niepotrzebny ruch i byłoby (w zależności od prędkości sieci) wolniejsze
jalgames
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.