Эквивалент 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, но другие ответы были также
хороши

6
- вы полностью теряете всю информацию (кроме System.DateTimeотметок ) исходного экземпляра
Андреас Нидермайр,

9
@AndreasNiedermair: Если вы сравниваете даты разных типов, вы все равно не можете просто сравнить их сразу. Я уже освещал это в ответе.
Guffa

4
@ Iain: Вы всегда можете сравнить их, но если вы сравниваете значения, которые не сопоставимы, результат бесполезен. Это так же, как и с любыми другими несопоставимыми значениями, например, сравнение расстояния в километрах с расстоянием в милях; Вы можете сравнить значения просто отлично, но это ничего не значит.
Гуффа

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, созданный из тиков или миллисекунд).

[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.
shtse8

-2

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

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

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

Вся проблема, описанная ниже, беспокоит. Вид - это большое дело ... но я избегаю этого, никогда не работая по местному времени. Если у меня есть что-то важное в отношении времени, я всегда работаю в UTC, даже если для этого нужно больше работать.


1
копия моего ответа
Тоши

-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 не Javascript
hawbsl

Извините, не заметил .NET. В любом случае, мы можем найти минимальную дату на стороне клиента и отправить ее на сервер.
Сергей Суворов

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