Equivalente a Math.Min & Math.Max ​​para fechas?

369

¿Cuál es la forma más rápida y fácil de obtener el valor Min (o Max) entre dos fechas? ¿Hay un equivalente a Math.Min (& Math.Max) para las fechas?

Quiero hacer algo como:

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

Obviamente, el Math.Min anterior no funciona porque son fechas.

hawbsl
fuente

Respuestas:

416

No hay sobrecarga para los valores de DateTime, pero puede obtener el valor largo Ticksque es lo que contienen los valores, compararlos y luego crear un nuevo valor de DateTime a partir del resultado:

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

(Tenga en cuenta que la estructura DateTime también contiene una Kindpropiedad, que no se retiene en el nuevo valor. Esto normalmente no es un problema; si compara los valores DateTime de diferentes tipos, la comparación no tiene sentido de todos modos).

Guffa
fuente
2
esto me pareció más cercano a un reemplazo / equivalente de una línea para Math.Min pero las otras respuestas también fueron geniales, para completar
hawbsl
66
-, pierde completamente toda la información (excepto los ticks) de la System.DateTimeinstancia original
Andreas Niedermair
99
@AndreasNiedermair: Si está comparando fechas de diferentes tipos, no puede compararlas directamente de todos modos. Ya cubrí esto en la respuesta.
Guffa
44
@Iain: Siempre puedes compararlos, pero si comparas valores que no son comparables, el resultado es inútil. Es igual que con cualquier otro valor que no sea comparable, como comparar una distancia en kilómetros con una distancia en millas; puedes comparar los valores bien, pero no significa nada.
Guffa
44
-1 para saludar a mano sobre Kind. Como se muestra en la respuesta de @ user450, es bastante fácil convertir ambas veces a UTC y compararlas de forma segura sin descartar información.
piedar
484

No hay un método integrado para hacer eso. Puedes usar la expresión:

(date1 > date2 ? date1 : date2)

para encontrar el máximo de los dos.

Puede escribir un método genérico para calcular Mino Maxpara cualquier tipo (siempre que Comparer<T>.Defaultesté configurado correctamente):

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

También puedes usar LINQ:

new[]{date1, date2, date3}.Max()
Mehrdad Afshari
fuente
15
ESTA es realmente la respuesta que merece ser aceptada.
Larry
38

Qué tal si:

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

Funciona con cualquier tipo que soporte IComparable<T>o IComparable.

En realidad, con LINQ, otra alternativa es:

var min = new[] {x,y,z}.Min();
Marc Gravell
fuente
66
Vote por el ejemplo de LINQ.
Infinito
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;
    }
}

Esto permite que las fechas tengan diferentes 'tipos' y devuelve la instancia que se pasó (sin devolver un nuevo DateTime construido a partir de Ticks o Milisegundos).

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

Tenga en cuenta que esta prueba fallaría al este de Greenwich ...

usuario450
fuente
¿Por qué no simplemente soltar la parte ToUniversalTime ()?
David Thielen
18

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

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(); 
Toshi
fuente
17

Si desea llamarlo más como Math.Max, puede hacer algo como este cuerpo de expresión muy breve:

public static DateTime Max(params DateTime[] dates) => dates.Max();
[...]
var lastUpdatedTime = DateMath.Max(feedItemDateTime, assemblyUpdatedDateTime);
R. Salisbury
fuente
oh, eso es genial! De esta manera, no tengo que comparar cada vez, solo una vez después de haber terminado con los datos. ¡Muchas gracias!
tfrascaroli
Esta es una solución muy elegante
pberggreen
2

¿Qué tal un DateTimemétodo de extensión?

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

Uso:

var maxDate = date1.MaxOf(date2);
Sin fin
fuente
Preferiría usarlo como DateTime.MaxOf(dt1, dt2), pero no sé cómo hacerlo ...
Zach Smith
@ZachSmith No puede sobrecargar la clase DateTime porque no es parcial. Tal vez podamos usar DateTimeHelper.Max (dt1, dt2)
shtse8
@ shtse8: ¿qué quiere decir con sobrecarga? Estaba pensando en agregar un método de extensión. pero desde entonces he aprendido que no se puede hacer sin una instancia instanciada. ¿Parece que estás diciendo que agregar un método de extensión es una forma de sobrecarga? Nunca he considerado eso ... ¿es correcto? ahora que lo pienso ... ¿qué significa exactamente sobrecargar?
Zach Smith
@ZachSmith Oh, pensé que estaba agregando una extensión llamada "DateTime.MaxOf (dt1, dt2)" al igual que "DateTime.Now" que se basa en miembros estáticos DateTime.
shtse8
-2

Ahora que tenemos LINQ, puede crear una matriz con sus dos valores (DateTimes, TimeSpans, lo que sea) y luego usar el método de extensión .Max ().

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

Se lee bien, es tan eficiente como Max puede ser, y es reutilizable para más de 2 valores de comparación.

Todo el problema a continuación preocuparse por .Kind es un gran problema ... pero lo evito al nunca trabajar en horarios locales, nunca. Si tengo algo importante con respecto a los tiempos, siempre trabajo en UTC, incluso si eso significa más trabajo para llegar allí.

Craig Brunetti
fuente
1
copia de mi respuesta
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/

Sergey Suvorov
fuente
Buena sugerencia (realmente), pero sin descripción es difícil encontrar por qué es buena. Describe dónde está el truco. Sin la descripción es solo un bloque de código y no una respuesta.
Artemix
3
pregunta está etiquetada .NET no Javascript
hawbsl
Lo sentimos, no noté .NET. De todos modos, podemos encontrar la fecha mínima en el lado del cliente y enviarla al servidor.
Sergey Suvorov
44
Asumes que estamos hablando de asp, que no es necesariamente correcto. También sería bastante estúpido calcular la diferencia en el Cliente, porque hay muchos más riesgos (JavaScript deshabilitado), generaría tráfico innecesario y sería (dependiendo de la velocidad de la red) más lento
jalgames