Equivalente de Math.Min e Math.Max ​​para datas?


369

Qual é a maneira mais rápida e fácil de obter o valor mínimo (ou máximo) entre duas datas? Existe um equivalente a Math.Min (& Math.Max) para datas?

Eu quero fazer algo como:

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

Obviamente, o Math.Min acima não funciona porque são datas.

Respostas:


416

Não há sobrecarga para os valores DateTime, mas você pode obter o valor longo Ticksque é o que os valores contêm, compará-los e criar um novo valor DateTime a partir do resultado:

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

(Observe que a estrutura DateTime também contém uma Kindpropriedade que não é mantida no novo valor. Isso normalmente não é um problema; se você comparar valores DateTime de tipos diferentes, a comparação não fará sentido de qualquer maneira.)


2
isto pareceu-me ser mais próximo a uma substituição line / equivalente para Math.min mas as outras respostas foram ótimo também, para a completude
hawbsl

6
-, você perde completamente todas as informações (exceto os ticks) da System.DateTimeinstância original
Andreas Niedermair

9
@AndreasNiedermair: Se você estiver comparando datas de diferentes tipos, não poderá compará-las imediatamente. Eu já cobri isso na resposta.
Guffa

4
@ Iain: Você sempre pode compará-los, mas se você comparar valores que não são comparáveis, o resultado será inútil. É exatamente o mesmo que com outros valores que não são comparáveis, como comparar uma distância em quilômetros com uma distância em milhas; você pode comparar os valores perfeitamente, mas isso não significa nada.
Guffa

4
-1 para agitar a mão sobre Kind. Conforme mostrado na resposta do @ user450, é muito fácil converter os dois horários para o UTC e compará-los com segurança, sem descartar informações.
Piedar

484

Não existe um método incorporado para fazer isso. Você pode usar a expressão:

(date1 > date2 ? date1 : date2)

para encontrar o máximo dos dois.

Você pode escrever um método genérico para calcular Minou Maxpara qualquer tipo (desde que Comparer<T>.Defaultdefinido adequadamente):

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

Você também pode usar o LINQ:

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

15
Esta é realmente a resposta que merece ser aceita.
Larry

38

E se:

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 com qualquer tipo que suporte IComparable<T>ou IComparable.

Na verdade, com o LINQ, outra alternativa é:

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

6
Vote no exemplo 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;
    }
}

Isso permite que as datas tenham 'tipos' diferentes e retorna a instância que foi passada (sem retornar um novo DateTime construído a partir de Ticks ou Milissegundos).

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

Observe que este teste falharia a leste de Greenwich ...


Por que não apenas largar a parte ToUniversalTime ()?
David Thielen 12/09

18

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

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 você quiser chamá-lo mais como Math.Max, poderá fazer algo como esse corpo de expressão muito curta:

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

oh, isso é genial! Dessa forma, não preciso comparar todas as vezes, apenas uma vez depois de concluir os dados. Muito obrigado!
Tfrascaroli

Esta é uma solução muito elegante
pberggreen

2

Que tal um DateTimemétodo de extensão?

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

Uso:

var maxDate = date1.MaxOf(date2);

Eu preferiria usá-lo como DateTime.MaxOf(dt1, dt2), mas eu não sei como fazer isso ...
Zach Smith

@ZachSmith Você não pode sobrecarregar a classe DateTime porque ela não é parcial. Talvez possamos usar DateTimeHelper.Max (DT1, DT2)
shtse8

@ shtse8 - o que você quer dizer com sobrecarga? Eu estava pensando em adicionar um método de extensão. mas desde então aprendemos que isso não pode ser feito sem uma instância instanciada. Parece que você está dizendo que adicionar um método de extensão é uma forma de sobrecarga? eu nunca considerei isso .. isso está correto? agora que penso nisso ... o que exatamente significa sobrecarga?
Zach Smith

@ZachSmith Oh, pensei que você estivesse adicionando uma extensão chamada "DateTime.MaxOf (dt1, dt2)", assim como "DateTime.Now", que é baseado em membros estáticos do DateTime.
shtse8

-2

Agora que temos o LINQ, você pode criar uma matriz com seus dois valores (DateTimes, TimeSpans, qualquer que seja) e, em seguida, usar o método de extensão .Max ().

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

É bonito, é tão eficiente quanto o Max pode ser, e é reutilizável por mais de 2 valores de comparação.

Todo o problema abaixo se preocupar com .Kind é muito importante ... mas evito isso por nunca trabalhar nos horários locais. Se tenho algo importante em relação aos horários, sempre trabalho no UTC, mesmo que isso signifique mais trabalho para chegar lá.


11
cópia da minha resposta
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/


Boa sugestão (realmente), mas sem descrição é difícil descobrir por que é bom. Por favor, descreva onde está o truque. Sem a descrição, é apenas um bloco de código e não uma resposta.
Artemix

3
questão é etiquetada .NET não Javascript
hawbsl

Desculpe, não percebi o .NET. De qualquer forma, podemos encontrar a data mínima no lado do cliente e enviá-la ao servidor.
Sergey Suvorov

4
Você assume que estamos falando de asp, o que não é necessariamente certo. Também seria muito estúpido para calcluate a diferença no cliente, porque há muito mais riscos (JavaScript desabilitado), geraria tráfego desnecessário e seria (dependendo da velocidade da rede) mais lentas
jalgames
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.