498

What's the quickest and easiest way to get the Min (or Max) value between two dates? Is there an equivalent to Math.Min (& Math.Max) for dates?

I want to do something like:

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

Obviously the above Math.Min doesn't work because they're dates.

0

11 Answers 11

652

There's no built in method to do that. You can use the expression:

(date1 > date2 ? date1 : date2)

to find the maximum of the two.

You can write a generic method to calculate Min or Max for any type (provided that Comparer<T>.Default is set appropriately):

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

You can use LINQ too:

new[]{date1, date2, date3}.Max()
4
  • 3
    The LINQ way is the best way!
    – Serj Sagan
    Commented Feb 14, 2023 at 6:15
  • 4
    @SerjSagan LINQ is the worst way. It has the slowest speed and allocates additional memory. See my post regarding benchmarking: stackoverflow.com/a/75869992/9232174 Commented Mar 28, 2023 at 18:52
  • 4
    It's not always about performance, in fact, if performance is not an issue then clean readable code is FAR more important.
    – Serj Sagan
    Commented Mar 30, 2023 at 9:59
  • 1
    All of these options are extremely simple, clean and readable. There is no reason whatsoever to initialise an array to perform this comparison.
    – 0b101010
    Commented Jan 30 at 16:41
506

There is no overload for DateTime values, but you can get the long value Ticks that is what the values contain, compare them and then create a new DateTime value from the result:

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

(Note that the DateTime structure also contains a Kind property, that is not retained in the new value. This is normally not a problem; if you compare DateTime values of different kinds the comparison doesn't make sense anyway.)

11
  • 2
    this seemed to me to be closest to a one line replacement/equivalent for Math.Min but the other answers were great too, for completeness
    – hawbsl
    Commented Jan 4, 2010 at 10:07
  • 8
    -, you completely loose every information (except the ticks) of the original System.DateTime-instance
    – user57508
    Commented May 8, 2012 at 8:15
  • 11
    @AndreasNiedermair: If you are comparing dates of different kinds, you can't just compare them straight off anyway. I already covered this in the answer.
    – Guffa
    Commented May 8, 2012 at 9:13
  • 6
    @Iain: You always can compare them, but if you compare values that are not comparable, the outcome is useless. It's just the same as with any other values that are not comparable, like comparing a distance in kilometers with a distance in miles; you can compare the values just fine, but it doesn't mean anything.
    – Guffa
    Commented Jan 2, 2013 at 12:36
  • 5
    -1 for handwaving about Kind. As shown in @user450 's answer, it's quite easy to convert both times to UTC and compare them safely without discarding information.
    – piedar
    Commented Mar 3, 2017 at 17:29
61

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

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(); 
0
42

How about:

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

Works with any type that supports IComparable<T> or IComparable.

Actually, with LINQ, another alternative is:

var min = new[] {x,y,z}.Min();
1
  • For the first method, it can just be return values.Min(); after the null check.
    – Him
    Commented Aug 12, 2020 at 1:51
30

If you want to use use Linq.Max() but call it more like Math.Max, you can do something like this very short expression body:

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

For anybody wondering about the performance of some of the answers previously provided, I ran benchmarks on a few of them. I used ternary operators, LINQ, and Math.max to determine the best solution for speed and memory.

Ternary

return a > b ? a : b;
  • Average Speed: 0.0198 nanoseconds
  • Additional Memory Allocation: none
  • Garbage Collection Time: none

Math.max

return new DateTime(Math.Max(a.Ticks, b.Ticks));
  • Average Speed: 2.4346 nanoseconds
  • Additional Memory Allocation: none
  • Garbage Collection Time: none

LINQ

return new[]{a, b}.Max();
  • Average Speed: 22.8383 nanoseconds
  • Additional Memory Allocation: 72 bytes
  • Garbage Collection Time: 0.0057 nanoseconds
Environment

.Net Version: 6.0

C# Version: 10.0

Configuration: Release

References

Benchmarking was done using BenchmarkDotNet 0.13.5

DateTime comparison benchmarks


TLDR

A ternary operator is the most performant method by far. It performs over 100x faster than the runner-up and allocates no additional memory.

2
  • what about about a basic if statement? Why use ternary?
    – john k
    Commented Dec 27, 2023 at 18:23
  • 1
    The c# compiler converts ternary arguments into simple if statements. It's effectively the same thing. return a > b ? a : b; becomes if (a > b) { return a; } else { return b; } Commented Dec 28, 2023 at 22:25
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;
    }
}

This allows the dates to have different 'kinds' and returns the instance that was passed in (not returning a new DateTime constructed from Ticks or Milliseconds).

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

Note that this test would fail East of Greenwich...

2
  • 2
    Why not just drop the ToUniversalTime() part? Commented Sep 12, 2018 at 15:17
  • Using ToUniversalTime allows the comparison of mixed DateTime Kinds. Commented Jul 18, 2022 at 20:30
7

How about a DateTime extension method?

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

Usage:

var maxDate = date1.MaxOf(date2);
4
  • I would prefer to use it as DateTime.MaxOf(dt1, dt2), but I don't know how to do that...
    – Zach Smith
    Commented Jul 3, 2018 at 12:01
  • 1
    @ZachSmith You cannot overload the DateTime class because it is not partial. Maybe we can use DateTimeHelper.Max(dt1, dt2)
    – shtse8
    Commented Aug 6, 2018 at 22:16
  • 1
    @shtse8 - what do you mean by overloading? i was thinking of adding an extension method. but have since learnt that cannot be done without an instantiated instance. sounds like you are saying that adding an extension method is a form of overloading? i've never considered that.. is that correct? now that I think about it... what exactly does overloading mean?
    – Zach Smith
    Commented Aug 8, 2018 at 9:51
  • @ZachSmith Oh, I thought you are adding an extension called "DateTime.MaxOf(dt1, dt2)" just like "DateTime.Now" which is based on DateTime static members.
    – shtse8
    Commented Aug 8, 2018 at 10:34
2

Put these two methods in a Utility class and use them to get Min/Max of any number of DateTimes:

public static DateTime Min(params DateTime[] dates)
{
    if (dates.Length == 1) return dates[0];

    long minTicks = dates[0].Ticks;

    for (int i = 1; i < dates.Length; i++)
    {
        minTicks = Math.Min(minTicks, dates[i].Ticks);
    }

    return new DateTime(minTicks);
}

public static DateTime Max(params DateTime[] dates)
{
    if (dates.Length == 1) return dates[0];

    long maxTicks = dates[0].Ticks;

    for (int i = 1; i < dates.Length; i++)
    {
        maxTicks = Math.Max(maxTicks, dates[i].Ticks);
    }

    return new DateTime(maxTicks);
}
-1

We can convert dates into Number primitive with Date.parse(), then we can use Math.min() and Math.max() for processing and storing. With that primitive we can render in any format we want. It's a 2-3 steps process, but we virtually eliminates the risk of getting funky results.

const unixTimeZero = Date.parse('01 Jan 1970 00:00:00 GMT');
const javaScriptRelease = Date.parse('04 Dec 1995 00:12:00 GMT');
const today = Date.parse(new Date());
const d1 = Date.parse(new Date("2004-02-01"));
const d2 = Date.parse(new Date("2017-01"));
const d3 = Date.parse(new Date("2018"))
const t = [unixTimeZero, d1, d2, d3, today, javaScriptRelease];
const min = Math.min(...t)
const max = Math.max(...t)
console.log(unixTimeZero); // expected output: 0
console.log(javaScriptRelease); // expected output: 818035920000
console.log(today);
console.log(t);
console.log(["unixMin: " + min, "earliestDate: " + new Date(min).toUTCString()]);
console.log(["unixMax: " + max, "latestDate: " + new Date(max).toDateString()]);

2
  • 4
    the question is about C#
    – Sasha
    Commented Dec 16, 2021 at 13:43
  • My bad.. Didn't see that. i'm stoopid
    – imstoopid
    Commented Dec 16, 2021 at 23:31
-7
// 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/

5
  • Good suggestion (really), but without description it's hard to find why it is good. Please describe where the trick is. Without the description it's just a block of code and not an answer.
    – Artemix
    Commented Nov 7, 2013 at 10:44
  • 4
    question is tagged .NET not Javascript
    – hawbsl
    Commented Nov 7, 2013 at 11:37
  • Sorry, didn't notice .NET. Anyway, we can find min date on client side and send it to server. Commented Nov 8, 2013 at 11:46
  • 4
    You assume that we are talking about asp, which is not necessarily right. It also would be quite stupid to calcluate the difference on the Client, because there are far more risks (JavaScript disabled) , it would generate unnecessary traffic and it would be (depending on the network speed) slower
    – jalgames
    Commented Jul 21, 2014 at 14:03
  • 1
    Create a datecomparison microservice running in node.js and then you can call it to answer the original question
    – stannius
    Commented Jan 12, 2021 at 1:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.