Bu yazıyı yeniden canlandırıyorum çünkü bugün sadece Cumartesi ve Pazar günleri değil, tatilleri de dışlamanın bir yolunu bulmalıydım . Daha spesifik olarak, aşağıdakiler dahil çeşitli olası tatil setlerini halletmem gerekiyordu:
- ülkeyle değişmeyen tatiller (en azından Batı ülkeleri için - 01 Ocak gibi).
- hesaplanan tatiller (Paskalya ve Paskalya pazartesi gibi).
- ülkeye özgü tatiller (İtalyan kurtuluş günü veya Amerika Birleşik Devletleri ID4 gibi).
- şehre özgü tatiller (Roma Aziz Patron Günü gibi).
- diğer herhangi bir ısmarlama tatil ("yarın ofisimiz kapalı" gibi).
Sonunda, aşağıdaki yardımcı / uzantı sınıfları ile ortaya çıktım: bariz bir şekilde zarif olmasalar da, verimsiz döngüleri büyük ölçüde kullandıklarından, sorunlarımı iyi bir şekilde çözecek kadar iyi. Başkası için de yararlı olacağını umarak bu gönderiye tüm kaynak kodunu bırakıyorum.
Kaynak kodu
public static class DateTimeExtensions
{
public static int Years(DateTime dt1,DateTime dt2)
{
return Months(dt1,dt2)/12;
}
public static int Years2(DateTime start, DateTime end)
{
return (end.Year - start.Year - 1) +
(((end.Month > start.Month) ||
((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0);
}
public static int Months(DateTime dt1,DateTime dt2)
{
if (dt2<dt1)
{
DateTime dt0=dt1;
dt1=dt2;
dt2=dt0;
}
dt2=dt2.AddDays(-(dt1.Day-1));
return (dt2.Year-dt1.Year)*12+(dt2.Month-dt1.Month);
}
public static DateTime Max(DateTime dt1,DateTime dt2)
{
return (dt2>dt1?dt2:dt1);
}
public static DateTime Min(DateTime dt1,DateTime dt2)
{
return (dt2<dt1?dt2:dt1);
}
public static DateTime AddBusinessDays(
this DateTime current,
int days,
IEnumerable<DateTime> holidays = null)
{
var sign = Math.Sign(days);
var unsignedDays = Math.Abs(days);
for (var i = 0; i < unsignedDays; i++)
{
do
{
current = current.AddDays(sign);
}
while (current.DayOfWeek == DayOfWeek.Saturday
|| current.DayOfWeek == DayOfWeek.Sunday
|| (holidays != null && holidays.Contains(current.Date))
);
}
return current;
}
public static DateTime SubtractBusinessDays(
this DateTime current,
int days,
IEnumerable<DateTime> holidays)
{
return AddBusinessDays(current, -days, holidays);
}
public static int GetBusinessDays(
this DateTime startDate,
DateTime endDate,
IEnumerable<DateTime> holidays)
{
if (startDate > endDate)
throw new NotSupportedException("ERROR: [startDate] cannot be greater than [endDate].");
int cnt = 0;
for (var current = startDate; current < endDate; current = current.AddDays(1))
{
if (current.DayOfWeek == DayOfWeek.Saturday
|| current.DayOfWeek == DayOfWeek.Sunday
|| (holidays != null && holidays.Contains(current.Date))
)
{
}
else cnt++;
}
return cnt;
}
public static DateTime GetEasterSunday(int year)
{
int day = 0;
int month = 0;
int g = year % 19;
int c = year / 100;
int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30;
int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11));
day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28;
month = 3;
if (day > 31)
{
month++;
day -= 31;
}
return new DateTime(year, month, day);
}
public static IEnumerable<DateTime> GetHolidays(IEnumerable<int> years, string countryCode = null, string cityName = null)
{
var lst = new List<DateTime>();
foreach (var year in years.Distinct())
{
lst.AddRange(new[] {
new DateTime(year, 1, 1),
new DateTime(year, 1, 6),
new DateTime(year, 5, 1),
new DateTime(year, 8, 15),
new DateTime(year, 11, 1),
new DateTime(year, 12, 8),
new DateTime(year, 12, 25),
new DateTime(year, 12, 26)
});
var easterDate = GetEasterSunday(year);
lst.Add(easterDate);
lst.Add(easterDate.AddDays(1));
if (!String.IsNullOrEmpty(countryCode))
{
switch (countryCode.ToUpper())
{
case "IT":
lst.Add(new DateTime(year, 4, 25));
break;
case "US":
lst.Add(new DateTime(year, 7, 4));
break;
case default:
break;
}
}
if (!String.IsNullOrEmpty(cityName))
{
switch (cityName)
{
case "Rome":
case "Roma":
lst.Add(new DateTime(year, 6, 29));
break;
case "Milano":
case "Milan":
lst.Add(new DateTime(year, 12, 7));
break;
default:
break;
}
}
}
return lst;
}
}
Kullanım bilgisi
Kod oldukça açıklayıcıdır, ancak burada onu nasıl kullanabileceğinizi açıklamak için birkaç örnek var.
10 iş günü ekleyin (yalnızca cumartesi ve pazar günleri atlanır)
var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10);
10 iş günü ekleyin (2019 için cumartesi, pazar ve ülkeden bağımsız tüm tatil günleri atlanır)
var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019));
10 iş günü ekleyin (2019 için cumartesi, pazar ve tüm İtalya tatillerini atlayın)
var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT"));
10 iş günü ekleyin (2019 için cumartesi, pazar, tüm İtalyan tatillerini ve Roma'ya özgü tatilleri atlayın)
var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT", "Rome"));
Yukarıdaki işlevler ve kod örnekleri, blogumun bu gönderisinde daha ayrıntılı açıklanmıştır .