I'm trying to create a function that returns the number of Dates in a Date Range that are sequential, starting on a specific date.
Example:
StartDate: 9/1/2022
Date Range: 9/1/2022, 9/2/2022, 9/3/2022, 9/4/2022, 9/7/2022
In this scenario the function I'm looking for would return 4.
Assume dates could be unordered and they can roll over into the next month, so with StartDate 9/29/2022:
9/29/2022, 9/30/2022, 10/1/2022, 10/4/2022 would return 3.
I know I can loop through the dates starting at the specific date and check the number of consecutive days, but I'm wondering if there's a clean way to do it with Linq.
CodePudding user response:
Here's a LINQ solution that will do that job:
var sortedDates = originalDates.OrderBy(dt => dt).ToArray();
var firstDate = sortedDates.First();
var sequentialDateCount = Enumerable.Range(0, sortedDates.Length)
.Max(i => sortedDates[i] == firstDate.AddDays(i)) 1;
It sorts the dates into an array, then finds the maximum index where the value is equal to the first value plus the index as a number of days. As soon as there's a gap, those values will not be equal. Adding 1 to that index gives the length of that initial series of sequential dates.
Without using LINQ:
var sortedDates = originalDates.OrderBy(dt => dt).ToArray();
var firstDate = sortedDates[0];
var sequentialDateCount = 0;
for (var i = 0; i < sortedDates.Length; i )
{
if (sortedDates[i] == firstDate.AddDays(i))
{
sequentialDateCount ;
}
else
{
break;
}
}
CodePudding user response:
To count the number of consecutive dates in a date range:
class Program
{
private static void Main(string[] args)
{
string dateRange = "10/4/2022, 9/29/2022, 10/1/2022, 9/30/2022";
List<DateTime> dates = new List<DateTime>();
foreach (var dateStr in dateRange.Split(", "))
{
// split date string to individual parts
var dateData = dateStr.Split("/");
// parse to DateTime
int month = int.Parse(dateData[0]);
int day = int.Parse(dateData[1]);
int year = int.Parse(dateData[2]);
var date = new DateTime(year, month, day);
// add date to list
dates.Add(date);
}
// order the dates
dates = dates.OrderBy(x => x).ToList();
// count for consecutive days in the date range
var consecutiveDatesCounter = 1; // 1 to count for start date
dates.Aggregate((last, next) =>
{
if (last.AddDays(1) == next)
consecutiveDatesCounter ;
else
return last; // to prevent counting later consecutive dates
return next;
});
// Display result
Console.WriteLine(consecutiveDatesCounter);
}
}
Output:
3
CodePudding user response:
Using a loop would probably be the cleanest way to go. I would use something like the following:
List<DateTime> GetConsecutiveDates(IEnumerable<DateTime> range, DateTime startDate)
{
var orderedRange = range.OrderBy(d => d).ToList();
int startDateIndex = orderedRange.IndexOf(startDate);
if (startDateIndex == -1) return null;
var consecutiveDates = new List<DateTime> { orderedRange[startDateIndex] };
for (int i = startDateIndex 1; i < orderedRange.Count; i )
{
if (orderedRange[i] != orderedRange[i - 1].AddDays(1)) break;
consecutiveDates.Add(orderedRange[i]);
}
return consecutiveDates;
}
CodePudding user response:
This is the cleanest solution I can come up with...
var startDate = new DateTime(2022, 9, 1);
var days = new List<DateTime>()
{
new(2022, 8, 28),
new(2022, 9, 1),
new(2022, 9, 2),
new(2022, 9, 3),
new(2022, 9, 4),
new(2022, 9, 7)
};
var consecutiveDays = GetConsecutiveDays(startDate, days);
foreach (var day in consecutiveDays)
{
Console.WriteLine(day);
}
Console.ReadKey();
static IEnumerable<DateTime> GetConsecutiveDays(DateTime startDate, IEnumerable<DateTime> days)
{
var wantedDate = startDate;
foreach (var day in days.Where(d => d >= startDate).OrderBy(d => d))
{
if (day == wantedDate)
{
yield return day;
wantedDate = wantedDate.AddDays(1);
}
else
{
yield break;
}
}
}
Output is: 01.09.2022 0:00:00 02.09.2022 0:00:00 03.09.2022 0:00:00 04.09.2022 0:00:00
If you wanted the count, you can call .Count() on the result or just modify the method... Should be easy.
CodePudding user response:
Case: start; { 9/1/2022 }
Case: finish; { 9/7/2022 }