Я сделал это очень похожим образом на Святослава Петрова, но вместо того, чтобы предполагать, что все данные даты попадают в один и тот же год, я работаю с набором строк дат в обратном порядке и на каждой итерации цикла. определить самый последний год (а), который равен или более ранний, чем год самой последней преобразованной даты, и (б) в котором действителен данный день недели. Этот подход должен быть действительным до тех пор, пока не существует многолетнего разрыва между любыми двумя последовательными датами в серии или между последней датой в серии и текущей датой.
void Test()
{
var dateStrings = new string[] {
"Mer 15/06","Jeu 16/06","Ven 17/06","Sam 18/06","Dim 19/06","Lun 20/06","Mar 21/06",
"Jeu 23/06","Ven 24/06","Sam 25/06","Dim 26/06","Lun 27/06","Mar 28/06","Mer 29/06",
"Jeu 30/06","Ven 01/07","Sam 02/07","Dim 03/07","Lun 04/07","Mar 05/07","Mer 06/07"
};
var parsedDates = ParseDateStrings(dateStrings);
foreach (var date in parsedDates)
Console.WriteLine(date);
}
// Takes a set of date strings in the format described by the question and returns
// the analogous set of DateTime objects. This method assumes that the supplied
// dates are in chronological order.
List<DateTime> ParseDateStrings(IEnumerable<string> dateStrings)
{
var year = DateTime.Today.Year;
var parsedDates = new List<DateTime>();
// Since we can't know at first how many years are represented in the given
// data set, we can't really make any assumptions about the year in which the
// data begins. Instead we assume that the most recent date occurs in either
// the current year or the latest previous year in which that date was valid,
// and work through the set backwards.
foreach (var dateString in dateStrings.Reverse())
{
var dayOfWeek = GetDayOfWeek(dateString.Substring(0, 3));
var day = int.Parse(dateString.Substring(4, 2));
var month = int.Parse(dateString.Substring(7, 2));
year = GetMostRecentValidYear(year, month, day, dayOfWeek);
parsedDates.Add(new DateTime(year, month, day));
}
// Reversing our output again at this point puts the results back into the
// same order as the inputs.
parsedDates.Reverse();
return parsedDates;
}
// Gets the appropriate DayOfWeek value for the given three-character abbreviation.
DayOfWeek GetDayOfWeek(string abbreviation)
{
switch (abbreviation.ToLower())
{
case "dim": return DayOfWeek.Sunday;
case "lun": return DayOfWeek.Monday;
case "mar": return DayOfWeek.Tuesday;
case "mer": return DayOfWeek.Wednesday;
case "jeu": return DayOfWeek.Thursday;
case "ven": return DayOfWeek.Friday;
case "sam": return DayOfWeek.Saturday;
default: throw new ArgumentException();
}
}
// Gets the latest year that is equal to or earlier than the given year, and in
// which the given day of the given month fell on the given day of the week.
int GetMostRecentValidYear(int year, int month, int day, DayOfWeek dayOfWeek)
{
while (!YearIsValid(year, month, day, dayOfWeek))
--year;
return year;
}
// Returns a flag indicating whether the given day of the given month fell on the
// given day of the week in the given year.
bool YearIsValid(int year, int month, int day, DayOfWeek dayOfWeek) =>
(month != 2 || day != 29 || IsLeapYear(year)) &&
new DateTime(year, month, day).DayOfWeek == dayOfWeek;
// Returns a flag indicating whether the given year was a leap year.
bool IsLeapYear(int year) =>
(year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
Выход:
2016-06-15 00:00:00
2016-06-16 00:00:00
2016-06-17 00:00:00
2016-06-18 00:00:00
2016-06-19 00:00:00
2016-06-20 00:00:00
2016-06-21 00:00:00
2016-06-23 00:00:00
2016-06-24 00:00:00
2016-06-25 00:00:00
2016-06-26 00:00:00
2016-06-27 00:00:00
2016-06-28 00:00:00
2016-06-29 00:00:00
2016-06-30 00:00:00
2016-07-01 00:00:00
2016-07-02 00:00:00
2016-07-03 00:00:00
2016-07-04 00:00:00
2016-07-05 00:00:00
2016-07-06 00:00:00
Редактировать : Я снова посмотрел на это и обнаружил ошибку в моей первоначальной реализации YearIsValid
: попытка построить DateTime
для 29 февраля в не високосный год приведет к конструктор, чтобы бросить. Я добавил тест на високосные годы, чтобы обойти эту проблему. YearIsValid
будет по-прежнему выдавать, если вы дадите ему ввод, который недопустим в любой год, например, 30 февраля, но в этом случае исключением является предполагаемое поведение.