Equivalent of Math.Min & Math.Max for Dates?

.Net

.Net Problem Overview


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.

.Net Solutions


Solution 1 - .Net

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()

Solution 2 - .Net

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.)

Solution 3 - .Net

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

Solution 4 - .Net

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

Solution 5 - .Net

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

Solution 6 - .Net

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

Solution 7 - .Net

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

Solution 8 - .Net

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

Solution 9 - .Net

Now that we have LINQ, you can create an array with your two values (DateTimes, TimeSpans, whatever) and then use the .Max() extension method.

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

It reads nice, it's as efficient as Max can be, and it's reusable for more than 2 values of comparison.

The whole problem below worrying about .Kind is a big deal... but I avoid that by never working in local times, ever. If I have something important regarding times, I always work in UTC, even if it means more work to get there.

Solution 10 - .Net

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()]);

Solution 11 - .Net

// 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/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhawbslView Question on Stackoverflow
Solution 1 - .NetmmxView Answer on Stackoverflow
Solution 2 - .NetGuffaView Answer on Stackoverflow
Solution 3 - .NetToshiView Answer on Stackoverflow
Solution 4 - .NetMarc GravellView Answer on Stackoverflow
Solution 5 - .NetR. SalisburyView Answer on Stackoverflow
Solution 6 - .Netuser450View Answer on Stackoverflow
Solution 7 - .NetOundlessView Answer on Stackoverflow
Solution 8 - .NetralofpatelView Answer on Stackoverflow
Solution 9 - .NetCraig BrunettiView Answer on Stackoverflow
Solution 10 - .NetimstoopidView Answer on Stackoverflow
Solution 11 - .NetSergey SuvorovView Answer on Stackoverflow