Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTime shift to next predefined date

Tags:

c#

datetime

linq

Say that I have a list of valid scheduling days. Something like: 23, 27, 29

I want to modify a given date to it's next valid day-month based on the above list.

If your given date was "23/11/2013" the next valid date would be "27/11/2013" But If your given date was "30/11/2013" it has to return "23/12/2013" And if the given date is "30/12/2013" it has to return "23/01/2014"

I've done that in SQL, but now I'm translating it to C# and it's a bit tricky. I'm trying to do it using LINQ over the list for SQL similarity, but it gets confusing.

The SQL statement was (yes, i know it doesn't swift year):

SELECT TOP 1 @DATE = ISNULL(DateAdd(yy, YEAR(@DATE)-1900, DateAdd(m,  (MONTH(@DATE)+CASE WHEN DATEPART(day,@DATE)>[DAY] THEN 1 ELSE 0 END) - 1, [DAY] - 1)),@DATE)
FROM @DAYS WHERE DateAdd(yy, YEAR(@DATE)-1900, DateAdd(m,  (MONTH(@DATE)+CASE WHEN DATEPART(day,@DATE)>[DAY] THEN 1 ELSE 0 END) - 1, [DAY] - 1))>=@DATE
ORDER BY [DAY]

@DAYS was a working table.

like image 968
Sergio Avatar asked Feb 06 '14 10:02

Sergio


2 Answers

I think what you're looking for is something like this (using LINQ):

    public static DateTime NextDate(DateTime seed, int[] days)
    {
        if (Enumerable.Range(1, 31).Intersect(days).Any())  //Check to stop a very long running lookup!
        {
            return Enumerable.Range(0, int.MaxValue)
                .Select(i => seed.AddDays(i))
                .First(d => days.Contains(d.Day));
        }

        return seed;
    }

Usage:

var nextDate = NextDate(DateTime.Now, new[] { 23, 27, 29 });
like image 133
Oliver Avatar answered Sep 30 '22 15:09

Oliver


I think you need something like this:

    public static DateTime GetNextValidDate(DateTime date)
    {
        var validDays = new List<short> { 23, 27, 29 };

        var nextDay = validDays.FirstOrDefault(n => n >= date.Day);

        if (nextDay != default(int))
        {
            // The next valid day is in the current month
            return date.AddDays(nextDay - date.Day);
        }
        // The next valid day is next month
        nextDay = validDays.Min();
        return new DateTime(date.Year, date.Month, nextDay, date.Hour, date.Minute, date.Second).AddMonths(1);
    }

I've tested this code with a few values and it works fine :

        Console.WriteLine(GetNextValidDate(new DateTime(2014, 1, 20)));
        Console.WriteLine(GetNextValidDate(new DateTime(2014, 1, 24)));
        Console.WriteLine(GetNextValidDate(new DateTime(2014, 1, 30)));

There is one limitation: if the first valid day is up to 28, you can have some issues with February (and April with 31 etc...)

like image 29
AlexH Avatar answered Sep 30 '22 15:09

AlexH