Equivalente di Math.Min e Math.Max ​​per le date?


369

Qual è il modo più rapido e semplice per ottenere il valore Min (o Max) tra due date? Esiste un equivalente a Math.Min (& Math.Max) per le date?

Voglio fare qualcosa del tipo:

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

Ovviamente il precedente Math.Min non funziona perché sono date.

Risposte:


416

Non c'è sovraccarico per i valori di DateTime, ma puoi ottenere il valore lungo Ticksche è quello che contengono i valori, confrontarli e quindi creare un nuovo valore DateTime dal risultato:

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

(Si noti che la struttura DateTime contiene anche una Kindproprietà, che non viene mantenuta nel nuovo valore. Questo di solito non è un problema; se si confrontano valori DateTime di tipi diversi, il confronto non ha comunque senso.)


2
questo mi è sembrato più vicino alla sostituzione di una riga / equivalente per Math.Min, ma anche le altre risposte sono state fantastiche, per completezza
hawbsl

6
-, si perde completamente ogni informazione (tranne le zecche) dell'originale System.DateTime-instance
Andreas Niedermair

9
@AndreasNiedermair: se stai confrontando date di diverso tipo, non puoi semplicemente confrontarle immediatamente. Ho già trattato questo nella risposta.
Guffa,

4
@Iain: È sempre possibile confrontarli, ma se si confrontano i valori che non sono comparabili, il risultato è inutile. È lo stesso di qualsiasi altro valore non confrontabile, come confrontare una distanza in chilometri con una distanza in miglia; puoi confrontare i valori bene, ma non significa nulla.
Guffa,

4
-1 per le onde a mano su Kind. Come mostrato nella risposta di @ user450, è abbastanza facile convertire entrambe le volte in UTC e confrontarle in modo sicuro senza eliminare le informazioni.
Piedar

484

Non esiste un metodo integrato per farlo. Puoi usare l'espressione:

(date1 > date2 ? date1 : date2)

per trovare il massimo dei due.

È possibile scrivere un metodo generico per calcolare Mino Maxper qualsiasi tipo (a condizione che Comparer<T>.Defaultsia impostato in modo appropriato):

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

Puoi anche usare LINQ:

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

15
Questa è in realtà la risposta che merita di essere accettata.
Larry,

38

Che ne dite di:

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

Funziona con qualsiasi tipo che supporti IComparable<T>o IComparable.

In realtà, con LINQ, un'altra alternativa è:

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

6
Vota per l'esempio 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;
    }
}

Ciò consente alle date di avere "tipi" diversi e restituisce l'istanza che è stata passata (non restituendo un nuovo DateTime costruito da tick o millisecondi).

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

Nota che questo test fallirebbe ad est di Greenwich ...


Perché non rilasciare semplicemente la parte ToUniversalTime ()?
David Thielen,

18

Linq.Min()/ Linq.Max()approccio:

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

Se vuoi chiamarlo più come Math.Max, puoi fare qualcosa come questo corpo di espressione molto breve:

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

oh, è geniale! In questo modo non devo confrontare ogni volta, solo una volta dopo aver finito con i dati. Grazie mille!
tfrascaroli,

Questa è una soluzione molto elegante
pberggreen

2

Che ne dici di un DateTimemetodo di estensione?

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

Uso:

var maxDate = date1.MaxOf(date2);

Preferirei usarlo come DateTime.MaxOf(dt1, dt2), ma non so come farlo ...
Zach Smith

@ZachSmith Non è possibile sovraccaricare la classe DateTime perché non è parziale. Forse possiamo usare DateTimeHelper.Max (dt1, dt2)
shtse8

@ shtse8 - cosa intendi per sovraccarico? stavo pensando di aggiungere un metodo di estensione. ma da allora ho imparato che non si può fare senza un'istanza istanziata. sembra che tu stia dicendo che l'aggiunta di un metodo di estensione è una forma di sovraccarico? non l'ho mai considerato ... è corretto? ora che ci penso ... cosa significa esattamente sovraccarico?
Zach Smith,

@ZachSmith Oh, ho pensato che stai aggiungendo un'estensione chiamata "DateTime.MaxOf (dt1, dt2)" proprio come "DateTime.Now" che si basa sui membri statici DateTime.
shtse8,

-2

Ora che abbiamo LINQ, puoi creare un array con i tuoi due valori (DateTimes, TimeSpans, qualunque cosa) e quindi utilizzare il metodo di estensione .Max ().

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

Sembra bello, è efficiente quanto Max può essere ed è riutilizzabile per più di 2 valori di confronto.

L'intero problema di seguito preoccupante per Kind è un grosso problema ... ma lo evito non lavorando mai in orari locali, mai. Se ho qualcosa di importante per quanto riguarda i tempi, lavoro sempre in UTC, anche se ciò significa più lavoro per arrivarci.


1
copia della mia risposta
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/


Un buon suggerimento (davvero), ma senza descrizione è difficile capire perché sia ​​buono. Descrivi dov'è il trucco. Senza la descrizione è solo un blocco di codice e non una risposta.
Artemix,

3
la domanda è taggata .NET non Javascript
hawbsl

Spiacenti, non ho notato .NET. Ad ogni modo, possiamo trovare la data minima sul lato client e inviarla al server.
Sergey Suvorov,

4
Supponi che stiamo parlando di asp, che non è necessariamente giusto. Sarebbe anche abbastanza stupido calcolare la differenza sul Cliente, perché ci sono molti più rischi (JavaScript disabilitato), genererebbe traffico non necessario e sarebbe (a seconda della velocità della rete) più lento
jalgames
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.