У меня есть список элементов перечисления DayOfWeek: var daysOfWeek = List<DayOfWeek>
Этот список содержит переменное количество элементов DaysOfWeek, например. Понедельник, Четверг, Суббота.
Я хотел бы найти следующее DateTime для любого заданного DateTime на основе List<DayOfWeek>
.
Если данная дата выпадет на среду, следующее значение DateTime, которое должно вернуться, будет четвергом.
Если данная дата выпадет на четверг, следующее значение DateTime, которое должно вернуться, будет субботой.
До сих пор я возился с некоторыми выражениями LINQ и пробовал некоторые параметры с методом расширения Min(), но у меня нет кода, которым я мог бы поделиться, который был бы работоспособным. Мне интересно, не хватает ли мне некоторых реальных базовых функций LINQ.
SO-темы, которые до сих пор дали мне некоторые идеи, включают Вот этот и Вон тот, однако я не смог найти решение своей проблемы с их ответами.
Спасибо за ваш ответ @RistoM! Я искал следующий DateTime, который соответствует ближайшему DayOfWeek в моем списке.
Хорошо, посмотрим, смогу ли я улучшить ответ.
Имеет ли значение порядок в списке (например, если это были понедельник, суббота, четверг, приведет ли четверг к понедельнику или субботе)?
Нет, порядок не должен иметь значения.
public static DateTime GetNextDateOrSomething(DateTime start, IEnumerable<DayOfWeek> weekdays)
{
if (!weekdays.Any()) throw new ArgumentException($"{nameof(weekdays)} cannot be empty.");
var increments = Enumerable.Range(1, 6);
var matchedIncrement = increments.FirstOrDefault(i => weekdays.Contains(start.AddDays(i).DayOfWeek));
return start.AddDays(matchedIncrement > 0 ? matchedIncrement : 7);
}
[DataTestMethod]
[DataRow("4/10/2019", "Wednesday,Thursday", "4/11/2019")]
[DataRow("4/10/2019", "Thursday", "4/11/2019")]
[DataRow("4/10/2019", "Monday,Tuesday", "4/15/2019")]
[DataRow("4/10/2019", "Tuesday", "4/16/2019")]
public void TestDateMethod(string start, string weekdays, string expected)
{
var startDate = DateTime.Parse(start);
var weekDaysList = weekdays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d));
var expectedDate = DateTime.Parse(expected);
var result = GetNextDateOrSomething(startDate, weekDaysList);
Assert.AreEqual(expectedDate, result);
}
Вы можете вычислить (неотрицательное) расстояние между завтрашним днем и следующим днем недели в списке, а затем использовать минимальное расстояние, чтобы получить новую дату:
var tomorrowDOW = startDate.AddDays(1).DayOfWeek;
var dist = daysOfWeek.Select(w => (w - tomorrowDOW + 14) % 7).Min();
var nextDate = startDate.AddDays(dist + 1);
class Program
{
static DateTime NextDay(List<DayOfWeek> workingDays, DateTime dateTime)
{
var result = dateTime;
var dayOfWeek = (int)dateTime.DayOfWeek;
dayOfWeek++;
result = result.AddDays(1);
while (!workingDays.Any(x=> x == (DayOfWeek)dayOfWeek))
{
if (dayOfWeek > (int)workingDays.Last())
{
var delta = ((int)workingDays.First() + 7) - dayOfWeek;
dayOfWeek = (int)workingDays.First();
result = result.AddDays(delta);
}
else
{
dayOfWeek++;
result = result.AddDays(1);
}
}
return result;
}
static void Main(string[] args)
{
var workingDays = new List<DayOfWeek>()
{
DayOfWeek.Monday,
DayOfWeek.Thursday,
DayOfWeek.Saturday
};
workingDays.Sort();
var dayOfWeek = NextDay(workingDays, DateTime.Now);
Console.WriteLine(dayOfWeek.ToString());
dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(1));
Console.WriteLine(dayOfWeek.ToString());
dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(2));
Console.WriteLine(dayOfWeek.ToString());
dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(3));
Console.WriteLine(dayOfWeek.ToString());
Console.ReadLine();
}
}
}
Предполагается, что ответ должен быть Дата следующего дня недели, а не дня недели.
Помимо отличных ответов, опубликованных на этот вопрос, вот еще одно решение, которое отлично сработало для меня. Я создал следующий частный метод для возврата следующего DateTime на основе заданного DateTime для списка допустимых элементов DayOfWeek:
private static DateTime NextDateTimeByDayOfWeek(DateTime target, List<DayOfWeek> validDaysOfWeek)
{
return Enumerable.Range(1, 7)
.Select(n => target.AddDays(n))
.First(date => validDaysOfWeek.Contains(date.DayOfWeek));
}
Я ответил, но должен уточнить, вы искали следующий DayOfWeek или следующий DateTime?