# Get first DateTime by given weekdays and a starttime

Posted on

Problem

At work there is an input-system where customers are able to specify weekdays and a starting time for an event. The weekdays are integers in the range from 1 (Monday) to 7 (Sunday).
After the customer has given the needed input, I need to calculate the next possible `DateTime` for the event. If the event is on the same day as today and the current time is not yet over the submitted starting-time, the next possible `DateTime` would be today.

This is what I have came up with, but it looks awful and complicated. You can obviously shorten the linq-queries a little, but i let the intermediate objects in there for sake of debugging.

``````public static class Test
{
public static void Main( string[] args )
{
var now = DateTime.Now;
var startTimes = new List<TimeSpan> {
now.TimeOfDay ,                                     // get the next possible starting point
now.TimeOfDay.Add( new TimeSpan( 0 , 1 , 0 ) ) ,    // starting point is today
};
var weekdaysList = new List<int[]> {
new [] { 1 , 4 , 5 } ,
new [] { 1 , 2 } ,
};

foreach( var weekdays in weekdaysList )
{
foreach( var startTime in startTimes )
{
var dt = GetNext( weekdays , startTime );
}
}
}

public static DateTime GetNext( int[] weekdays , TimeSpan startTime )
{
// convert to german format (Monday:1 - Sunday:7)
var currentWeekDay = (int)DateTime.Now.DayOfWeek;

if( currentWeekDay == 0 )
currentWeekDay = 7;

if( weekdays.Contains( currentWeekDay ) )
{
var today = DateTime.Now.Date.Add( startTime );

if( DateTime.Now < today )
}

// calculate the day index and keep the added days around (better debugging)
var days = Enumerable.Range( 0 , 7 )
.Select( addedDays => new { addedDays , dayIndex = ( currentWeekDay + addedDays ) % 7 } )
.ToArray();
// only days that are specified
var validDays = days
.Where( x => weekdays.Contains( x.dayIndex ) )
.ToArray();
// the first day is the one that has the least days added
// but we already sorted out today, so the next possible day is the second (if exists) or 1 week/ 7 days later
{
if( validDays.Count() > 1 )
else
}

return DateTime.Now.Date
}
}
``````

I feel like I am missing some obvious shortcuts or linq-fu to shorten this code down and make it easier understandable.

I let this code as it is, but it was bugging me the whole day, how could I improve this?

Only the basic algorithm in the `GetNext()`-Method is relevant, no error-checking etc.

Solution

After some fresh air I think I got around my mental blockade. I simply convert to the natural C# `DayOfWeek` representation beforehand instead of fiddling around with the other one.

``````public static IEnumerable<DayOfWeek> ConvertDaysOfWeek( int[] daysOfWeekIds )
=> daysOfWeekIds.Select( x => x == 7 ? DayOfWeek.Sunday : (DayOfWeek)x );

public static DateTime GetNext( IEnumerable<DayOfWeek> daysOfWeek , TimeSpan startTime )
{
var nextDate = DateTime.Now.Date;
var isToday = daysOfWeek.Contains( nextDate.DayOfWeek ) && DateTime.Now.TimeOfDay < startTime;

if( !isToday )
nextDate = Enumerable.Range( 1 , 7 )
.Select( x => nextDate.AddDays( x ) )
.First( x => daysOfWeek.Contains( x.DayOfWeek ) );

}
``````

``````static void Main(string[] args)
{
//input samples
var startTimes = new List<TimeSpan> { DateTime.Now.TimeOfDay, DateTime.Now.AddHours(4).TimeOfDay };
var weekdaysList = new List<int>() { 1, 4, 5, 2 }; //why did you choose make it a list of integer arrays?, if thats how its populated, you could later flatten it

//you'll want to sort the lists for convenience
startTimes.Sort();
weekdaysList.Sort();

var next_event = GetNext(weekdaysList, startTimes);
}
public static DateTime GetNext(List<int> daysOfWeekIds, List<TimeSpan> startTimes)
{
var today = DateTime.Now;
var today_Day = (int)today.DayOfWeek;
var today_Time = today.TimeOfDay;

TimeSpan later_that_day = startTimes.Where(st => st > today_Time).FirstOrDefault() - today_Time;

//check if day is the same at a later time
if (daysOfWeekIds.Any(d => (d == today_Day)) && later_that_day.TotalMinutes > 0) //you may want to put a minimum time threshold here for same-day events
{
}

//check if it can be done later in the same week
int later_that_week = daysOfWeekIds.Where(d => d > today_Day).FirstOrDefault() - today_Day;

if (later_that_week > 0)
{