-1

I am trying get the closest date from a list of DateTime. I want to compare the DateTime item present in the list to DateTime.Now and get the closest date.

So far I tried: DateTime.Compare(item, DateTime.Now) but this doesn't work in UiPath as I am unable to find Just DATE type in the UiPath.

Rajat Pandit
  • 63
  • 2
  • 9
  • comparing only by date? not also by time? – Mong Zhu Apr 30 '20 at 17:39
  • it seems that you are looking for a linq solution. Have you tried solving it with a loop? – Mong Zhu Apr 30 '20 at 17:44
  • @MongZhu In my case time will be 00:00:00 for all the dates present in the list, So either way I am not considering the time but however I didn't find **Date** format in UiPath so the **DateTime** format was pretty close – Rajat Pandit Apr 30 '20 at 17:59

5 Answers5

1

Is there anything wrong with just subtracting the date times in your list with the datetime.now gives you? it returns a TimeSpan but you can get the seconds from that (all the way down to ms if you want that accuracy). Then just take the absolute value of the difference between the two if you are expecting to receive date times that are in the future in your list of DateTimes. Then use linq to order and grab the first one.

    public static void Main(string[] args)
    {
        var now = DateTime.Now;
        var dates = new List<DateTime> 
        { 
            new DateTime(2014, 1, 1),
            new DateTime(2015, 1, 1),
            new DateTime(2016, 1, 1),
            new DateTime(2017, 1, 1),
            new DateTime(2018, 1, 1),
            new DateTime(2019, 1, 1),
            new DateTime(2020, 1, 1),
            new DateTime(2020, 4, 30),
            new DateTime(2021, 1, 1)

        };

        var minDate = dates.OrderBy(x => Math.Abs((now - x).TotalSeconds)).First();


    }
Cory Melendez
  • 224
  • 1
  • 8
1

With Linq, you can run into an issue with lazy evaluation. In this case since you are using time objects and DateTime.Now, that could be a very bad thing, as the Linq expresion may not evaluate for a return value until the value is required by other code. This may not be an issue for you, and other users have answered on this post for the Linq version. Otherwise, the tried and true For loop approach like in the method below will solve the issue, and return a Datetime object for later use.

public DateTime ReturnClosest(List<DateTime> dateTimes)
{
    //Establish Now for simpler code below
    var now = DateTime.Now;

    //Start by assuming the first in the list is the closest
    var closestDateToNow = dateTimes[0];

    //Set up initial interval value, accounting for dates before and after Now
    TimeSpan shortestInterval = now > dateTimes[0] ? now - dateTimes[0] : dateTimes[0] - now;

    //Loop through the rest of the list and correct closest item if appropriate
    //Note this starts at index 1, which is the SECOND value, we've evaluated the first above
    for (var i = 1; i < dateTimes.Count; i++)
    {
        TimeSpan testinterval = now > dateTimes[i] ? now - dateTimes[i] : dateTimes[i] - now;

        if(testinterval < shortestInterval)
        {
            shortestInterval = testinterval;
            closestDateToNow = dateTimes[i];
        }
    }

    //return the closest Datetime object
    return closestDateToNow;
}
Nik P
  • 2,693
  • 9
  • 21
0

You can compare two DateTime simply using the difference as follows: TimeSpan interval = DateTime.Now - otherdate;. Once you have TimeSpans, select the smaller one

sim1
  • 722
  • 7
  • 12
0

In a non-very optimal way you can do it using LINQ, something like:

        var dates = new DateTime[]
        {
            new DateTime(2011, 5, 8),
            new DateTime(2011, 5, 9),
            new DateTime(2001, 6, 21)                
        };

        var input = new DateTime(2011, 5, 8, 13, 8, 58);
        var closest = dates
            .Select(x => new { date = x, diff = Math.Abs((x - input).Ticks)})
            .OrderBy(x => x.diff)
            .First();

        Console.WriteLine(closest.date);

Output:

5/9/2011 12:00:00 AM
0

There is simple way using LINQ but has O(n*log(n)) complexity. DateTime.Subtraction Operator subtracts a specified date and time from another specified date and time and returns a time interval. TimeSpan.Duration() returns a new TimeSpan object whose value is the absolute value of the current TimeSpan object. So, you an just order source value by durations and take first value with First().

DateTime closestDate = dates.OrderBy(d => (d - DateTime.Now).Duration()).First();

There is solution with O(n) complexity:

var closestDate = (date: new DateTime(), duration: TimeSpan.MaxValue);
foreach (var date in dates)
{
    var duration = (date - DateTime.Now).Duration();
    if (duration < closestDate.duration)
        closestDate = (date, duration);
}
return closestDate.date;

Also you can do the same with LINQ and O(n) complexity but in an unobvious way:

DateTime closestDate = dates
    .Select(d => (date: d, duration: (d - DateTime.Now).Duration()))
    .Aggregate((date: new DateTime(), duration: TimeSpan.MaxValue), (currentClosest, d) => d.duration < currentClosest.duration ? d : currentClosest)
    .date;
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43