Eine feste Liste der Daten ist eine etwas begrenzte Weise Feiertage zum Ausdruck bringen.
Beachten Sie, dass Ihre Liste nur Daten für das aktuelle Jahr enthält. Wenn also heute der 30. Dezember 2015 ist, wäre der nächste Feiertag der 1. Januar 2016 - den Sie nicht in Ihrer Liste finden würden.
Denken Sie auch daran, dass viele Feiertage nicht jedes Jahr auf dasselbe Datum fallen. Oft sind sie an den Wochentag gebunden und manchmal werden sie von religiösen Kalendern oder willkürlich bestimmt.
Ein robusteres System sollte eine Vielzahl von verschiedenen Arten von Ferien behandeln.Hier ist eine mögliche Implementierung:
public abstract class Holiday
{
public abstract DateTime? GetDate(int year);
}
public class MonthDayBasedHoliday : Holiday
{
private readonly int _month;
private readonly int _day;
public MonthDayBasedHoliday(int month, int day)
{
_month = month;
_day = day;
}
public override DateTime? GetDate(int year)
{
return new DateTime(year, _month, _day);
}
}
public class DayOfWeekBasedHoliday : Holiday
{
private readonly int _occurrence;
private readonly DayOfWeek _dayOfWeek;
private readonly int _month;
public DayOfWeekBasedHoliday(int occurrence, DayOfWeek dayOfWeek, int month)
{
_occurrence = occurrence;
_dayOfWeek = dayOfWeek;
_month = month;
}
public override DateTime? GetDate(int year)
{
if (_occurrence <= 4)
{
DateTime dt = new DateTime(year, _month, 1);
int delta = (_dayOfWeek - dt.DayOfWeek + 7) % 7;
delta += 7 * (_occurrence - 1);
return dt.AddDays(delta);
}
else // last occurrence in month
{
int daysInMonth = DateTime.DaysInMonth(year, _month);
DateTime dt = new DateTime(year, _month, daysInMonth);
int delta = (dt.DayOfWeek - _dayOfWeek + 7) % 7;
return dt.AddDays(-delta);
}
}
}
public class FixedDateBasedHoliday : Holiday
{
private readonly IDictionary<int, DateTime> _dates;
public FixedDateBasedHoliday(params DateTime[] dates)
{
_dates = dates.ToDictionary(x => x.Year, x => x);
}
public override DateTime? GetDate(int year)
{
if (_dates.ContainsKey(year))
return _dates[year];
// fixed date not established for year
return null;
}
}
Mit diesen definiert ist, können wir jetzt Feiertage definieren viel robuster, wie zum Beispiel:
var holidays = new List<Holiday>();
// New Year's Day
holidays.Add(new MonthDayBasedHoliday(1, 1));
// President's Day (US)
holidays.Add(new DayOfWeekBasedHoliday(3, DayOfWeek.Monday, 2));
// Easter (Western Observance)
holidays.Add(new FixedDateBasedHoliday(new DateTime(2015, 4, 5), new DateTime(2016, 3, 27)));
// Memorial Day (US)
holidays.Add(new DayOfWeekBasedHoliday(5, DayOfWeek.Monday, 5));
// Christmas Day
holidays.Add(new MonthDayBasedHoliday(12, 25));
Und jetzt können wir eine Methode erstellen, die für den nächsten Werktag überprüft , wie Sie verlangen:
public static DateTime GetNextNonHolidayWeekDay(DateTime date, IList<Holiday> holidays, IList<DayOfWeek> weekendDays)
{
// always start with tomorrow, and truncate time to be safe
date = date.Date.AddDays(1);
// calculate holidays for both this year and next year
var holidayDates = holidays.Select(x => x.GetDate(date.Year))
.Union(holidays.Select(x => x.GetDate(date.Year + 1)))
.Where(x=> x != null)
.Select(x=> x.Value)
.OrderBy(x => x).ToArray();
// increment until we get a non-weekend and non-holiday date
while (true)
{
if (weekendDays.Contains(date.DayOfWeek) || holidayDates.Contains(date))
date = date.AddDays(1);
else
return date;
}
}
Diese Methode auf der abstrakten Holiday
Klasse gehen könnte, oder es könnte überall wirklich gehen.
Beispiel der Verwendung (mit obiger Definition für holidays
):
var weekendDays = new[] { DayOfWeek.Saturday, DayOfWeek.Sunday };
DateTime workDay = GetNextNonHolidayWeekDay(new DateTime(2015, 12, 31), holidays, weekendDays);
// returns 2016-01-04
Dies ist immer noch nicht ganz vollständige Lösung though. Viele Feiertage haben komplexere Berechnungsregeln. Als eine Übung, die dem Leser überlassen wird, versuchen Sie, eine Klasse zu implementieren, die von Holiday
für den zweiten Tag in den USA Erntedankfest stammt. Der erste Tag fällt immer am 4. Donnerstag im November, aber der zweite Tag ist immer "der Freitag nach dem 4. Donnerstag im November" und nicht nur "der vierte Freitag im November" (siehe November 2019 für ein Beispiel wo dies liegt) Angelegenheiten).
+1 und indem 'eine Funktion IsHoliday' Sie vermeiden können, eine statische Liste von Feiertagen zu bauen und stattdessen on the fly berechnen das Datum/Jahr ist vergangen - das ist wichtig für Daten wie Ostern, die sich bewegen. –
Was ist 'IsHolliday (Datum)'? Gibt es diese Methode? – Fabjan
@Fabjan Sie müssen diese Methode selbst implementieren. Zum Beispiel können Sie den Code eingeben, den das OP geschrieben hat, um zu prüfen, ob ein Datum in den Ferien ist. – fjardon