AddBusinessDays ve GetBusinessDays


94

2 zarif eksiksiz uygulaması bulmam gerekiyor

public static DateTime AddBusinessDays(this DateTime date, int days)
{
 // code here
}

and 

public static int GetBusinessDays(this DateTime start, DateTime end)
{
 // code here
}

O (1) tercih edilir (döngü yok).

DÜZENLEME: İş günleri ile iş günlerini kastediyorum (Pazartesi, Salı, Çarşamba, Perşembe, Cuma). Tatil yok, sadece hafta sonları hariç.

Zaten işe yarayan bazı çirkin çözümlerim var ama bunu yapmanın zarif yolları olup olmadığını merak ediyorum. Teşekkürler


Şimdiye kadar yazdıklarım bu. Her durumda çalışır ve olumsuzluklar da yapar. Yine de GetBusinessDays uygulamasına ihtiyacınız var

public static DateTime AddBusinessDays(this DateTime startDate,
                                         int businessDays)
{
    int direction = Math.Sign(businessDays);
    if(direction == 1)
    {
        if(startDate.DayOfWeek == DayOfWeek.Saturday)
        {
            startDate = startDate.AddDays(2);
            businessDays = businessDays - 1;
        }
        else if(startDate.DayOfWeek == DayOfWeek.Sunday)
        {
            startDate = startDate.AddDays(1);
            businessDays = businessDays - 1;
        }
    }
    else
    {
        if(startDate.DayOfWeek == DayOfWeek.Saturday)
        {
            startDate = startDate.AddDays(-1);
            businessDays = businessDays + 1;
        }
        else if(startDate.DayOfWeek == DayOfWeek.Sunday)
        {
            startDate = startDate.AddDays(-2);
            businessDays = businessDays + 1;
        }
    }

    int initialDayOfWeek = (int)startDate.DayOfWeek;

    int weeksBase = Math.Abs(businessDays / 5);
    int addDays = Math.Abs(businessDays % 5);

    if((direction == 1 && addDays + initialDayOfWeek > 5) ||
         (direction == -1 && addDays >= initialDayOfWeek))
    {
        addDays += 2;
    }

    int totalDays = (weeksBase * 7) + addDays;
    return startDate.AddDays(totalDays * direction);
}

14
Tarihler kadar mantıksız bir şey söz konusu olduğunda zarif çözümler var mı?
Wyatt Barnett

Tatillerle ilgileniyor musunuz? - James Conigliaro. Hayır
Adrian Zanescu

9
Yardım etmeye çalışan insanları oylamak, kazanan bir strateji değildir.
Jamie Ide

1
AddBusinessDaysYukarıdaki sorudaki uygulama hakkında kısa not (aslında silinmiş bir cevaptı; bunun yerine, bu cevabı soruya kopyalayan bir mod): Bence bu çözüm şu ana kadar tüm cevaplardan daha iyi çünkü tek Kaynak olarak Cumartesi ve Pazar günleri negatif değerlerle doğru bir şekilde ilgilenen ve Üçüncü Taraf kitaplığına ihtiyaç duymayan. (Burada farklı çözümleri test etmek için küçük bir program yaptım.) if (businessDays == 0) return startDate;Bu uç durum için de doğru sonucu elde etmek için sadece yöntemin başına eklerim .
Slauma

1
@AZ .: İlk silme işlemi oldukça eskiydi. Cevabınızı silme talebimden sonra, bir mod, sorunuzun altındaki içeriği kopyalamak için cevabı silmeyi (30 saniye için) geri aldı ve ardından tekrar sildi. Bu yüzden cevabınızda bu son silme zaman damgası var. Yukarıdaki yorumu yazdım çünkü amacım için AddBusinessDaysihtiyacım olan her durumda işe yarayan en genel çözümün buradaydı. Bunu mevcut projelerimden birine kopyaladım (küçük bir değişiklikten ve C ++ 'ya çevirdikten sonra), kod için teşekkürler :) Tüm uç durumları düzeltmek şaşırtıcı derecede zor olduğu için çok yardımcı oldu.
Slauma

Yanıtlar:


136

İlk göreviniz için son deneme:

public static DateTime AddBusinessDays(DateTime date, int days)
{
    if (days < 0)
    {
        throw new ArgumentException("days cannot be negative", "days");
    }

    if (days == 0) return date;

    if (date.DayOfWeek == DayOfWeek.Saturday)
    {
        date = date.AddDays(2);
        days -= 1;
    }
    else if (date.DayOfWeek == DayOfWeek.Sunday)
    {
        date = date.AddDays(1);
        days -= 1;
    }

    date = date.AddDays(days / 5 * 7);
    int extraDays = days % 5;

    if ((int)date.DayOfWeek + extraDays > 5)
    {
        extraDays += 2;
    }

    return date.AddDays(extraDays);

}

İkinci işlev olan GetBusinessDays şu şekilde uygulanabilir:

public static int GetBusinessDays(DateTime start, DateTime end)
{
    if (start.DayOfWeek == DayOfWeek.Saturday)
    {
        start = start.AddDays(2);
    }
    else if (start.DayOfWeek == DayOfWeek.Sunday)
    {
        start = start.AddDays(1);
    }

    if (end.DayOfWeek == DayOfWeek.Saturday)
    {
        end = end.AddDays(-1);
    }
    else if (end.DayOfWeek == DayOfWeek.Sunday)
    {
        end = end.AddDays(-2);
    }

    int diff = (int)end.Subtract(start).TotalDays;

    int result = diff / 7 * 5 + diff % 7;

    if (end.DayOfWeek < start.DayOfWeek)
    {
        return result - 2;
    }
    else{
        return result;
    }
}

İkincisi için bir çözüm, tarih ve tarih + gün arasındaki farkı almaktır. Bu, iki işlevin düzgün şekilde senkronize edileceğini garanti etmesi ve fazlalığı ortadan kaldırması açısından güzel.
Brian

Geçerli tarihi besleyin, 0 ila 10 iş günü çalıştırın, her zaman Çarşamba günü başarısız olur.
Adrian Godong

1
Evet, sonunda oraya vardık. (Minik katkım için 'biz' diyorum!) Çaba için oy verdi.
Noldorin

Girişiniz için teşekkürler Noldorin, maalesef yalnızca yorumlarınıza olumlu oy verebilirim!
Patrick McDonald

3
DateTime.AddDays negatif sayılarla çalışır. Bu, negatif sayıların AddBusinessDays ile kullanılmasıyla aynı modeli doğru şekilde izlemez, iş dışı günlerin seçilmesine izin verir.
Ristogod

63

Fluent DateTime kullanarak :

var now = DateTime.Now;
var dateTime1 = now.AddBusinessDays(3);
var dateTime2 = now.SubtractBusinessDays(5);

dahili kod aşağıdaki gibidir

    /// <summary>
    /// Adds the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be added.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime AddBusinessDays(this DateTime current, int days)
    {
        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);
        }
        return current;
    }

    /// <summary>
    /// Subtracts the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be subtracted.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime SubtractBusinessDays(this DateTime current, int days)
    {
        return AddBusinessDays(current, -days);
    }

VB.Net'e dönüştürüldüğümde benim için gerçekten işe yarayan tek çözüm budur
Nicholas

1
OP, açıkça döngüler varken, hiçbir döngü istemedi. Bir şeyi en az verimli şekilde yapmanın zarif hiçbir yanı yoktur.
Neolisk

13

İş günü eklemenize veya çıkarmanıza olanak tanıyan bir uzantı oluşturdum. Çıkarmak için negatif sayıda iş günü kullanın. Bence oldukça zarif bir çözüm. Her durumda işe yarıyor gibi görünüyor.

namespace Extensions.DateTime
{
    public static class BusinessDays
    {
        public static System.DateTime AddBusinessDays(this System.DateTime source, int businessDays)
        {
            var dayOfWeek = businessDays < 0
                                ? ((int)source.DayOfWeek - 12) % 7
                                : ((int)source.DayOfWeek + 6) % 7;

            switch (dayOfWeek)
            {
                case 6:
                    businessDays--;
                    break;
                case -6:
                    businessDays++;
                    break;
            }

            return source.AddDays(businessDays + ((businessDays + dayOfWeek) / 5) * 2);
        }
    }
}

Misal:

using System;
using System.Windows.Forms;
using Extensions.DateTime;

namespace AddBusinessDaysTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            label1.Text = DateTime.Now.AddBusinessDays(5).ToString();
            label2.Text = DateTime.Now.AddBusinessDays(-36).ToString();
        }
    }
}

Kaynak tarihin Cumartesi veya Pazar olması durumunda sonuç şüphelidir. Örneğin: Cumartesi + 1 iş günü, Pazartesi'yi beklemeyi tercih ettiğim Salı günüdür.
Slauma

3
@Slauma: Kanada'daki çoğu işletme böyle çalışıyor. +1 iş günü = "sonraki iş günü", Cumartesi olması durumunda Salıdır. Pazartesi, "aynı iş günü" olurdu.
Neolisk

3
@Slauma Programı amaçlandığı gibi çalışıyor. Mantıklı bir şekilde düşünün. İşle ilgili bir şey Cumartesi günü başlarsa ve söz konusu iş günü süresince insanların tepki vermesi için 1 iş gününe izin vermeniz gerekiyorsa, onlara bunun Pazartesi'ye kadar yapılması gerektiğini söylemek mantıklı olur mu ?!
Riegardt Steyn

8

Benim için hafta sonlarını atlayıp, olumsuz ya da pozitif giden bir çözüme sahip olmalıydım. Kriterlerim, eğer bir hafta sonu ileri gidip inerse, pazartesiye ilerlemesi gerekecekti. Geri gidip bir hafta sonu inmiş olsaydı, Cuma gününe atlamak zorunda kalacaktı.

Örneğin:

  • Çarşamba - 3 iş günü = Geçen Cuma
  • Çarşamba + 3 iş günü = Pazartesi
  • Cuma - 7 iş günü = Geçen Çarşamba
  • Salı - 5 iş günü = Geçen Salı

Peki, fikri anladınız;)

Bu uzatma sınıfını yazdım

public static partial class MyExtensions
{
    public static DateTime AddBusinessDays(this DateTime date, int addDays)
    {
        while (addDays != 0)
        {
            date = date.AddDays(Math.Sign(addDays));
            if (MyClass.IsBusinessDay(date))
            {
                addDays = addDays - Math.Sign(addDays);
            }
        }
        return date;
    }
}

Başka bir yerde kullanmanın yararlı olacağını düşündüğüm bu yöntemi kullanıyor ...

public class MyClass
{
    public static bool IsBusinessDay(DateTime date)
    {
        switch (date.DayOfWeek)
        {
            case DayOfWeek.Monday:
            case DayOfWeek.Tuesday:
            case DayOfWeek.Wednesday:
            case DayOfWeek.Thursday:
            case DayOfWeek.Friday:
                return true;
            default:
                return false;
        }
    }
}

Bununla uğraşmak istemiyorsan sadece if (MyClass.IsBusinessDay(date))if ile değiştirebilirsinif ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

Yani şimdi yapabilirsin

var myDate = DateTime.Now.AddBusinessDays(-3);

veya

var myDate = DateTime.Now.AddBusinessDays(5);

İşte bazı testlerin sonuçları:

Test Beklenen Sonuç
Çarşamba -4 iş günü Perşembe Perşembe
Çarşamba -3 iş günü Cuma Cuma
Çarşamba +3 iş günü Pazartesi Pazartesi
Cuma -7 iş günü Çarşamba Çarşamba
Salı -5 iş günü Salı Salı
Cuma +1 iş günü Pazartesi Pazartesi
Cumartesi +1 iş günü Pazartesi Pazartesi
Pazar -1 iş günü Cuma Cuma
Pazartesi -1 iş günü Cuma Cuma
Pazartesi +1 iş günü Salı Salı
Pazartesi +0 iş günü Pazartesi Pazartesi

2. yöntemi bir uzatma yöntemi de yaptım: public static bool IsBusinessDay (bu DateTime tarihi)
Andy B

2
public static DateTime AddBusinessDays(this DateTime date, int days)
{
    date = date.AddDays((days / 5) * 7);

    int remainder = days % 5;

    switch (date.DayOfWeek)
    {
        case DayOfWeek.Tuesday:
            if (remainder > 3) date = date.AddDays(2);
            break;
        case DayOfWeek.Wednesday:
            if (remainder > 2) date = date.AddDays(2);
            break;
        case DayOfWeek.Thursday:
            if (remainder > 1) date = date.AddDays(2);
            break;
        case DayOfWeek.Friday:
            if (remainder > 0) date = date.AddDays(2);
            break;
        case DayOfWeek.Saturday:
            if (days > 0) date = date.AddDays((remainder == 0) ? 2 : 1);
            break;
        case DayOfWeek.Sunday:
            if (days > 0) date = date.AddDays((remainder == 0) ? 1 : 0);
            break;
        default:  // monday
            break;
    }

    return date.AddDays(remainder);
}

1

Cevap için geç geliyorum, ancak iş günlerinde basit işlemler yapmak için gereken tüm özelleştirmeleri içeren küçük bir kitaplık yaptım ... Burada bırakıyorum: Çalışma Günleri Yönetimi


2
Maalesef bu GNU lisanslıdır ve herhangi bir ticari uygulama için "yasal zehir" dir. Bunu "MIT" veya "Apache" olarak gevşetme şansın var mı?
Tony O'Hagan

Bazı statik listeler muhtemelen diziler olmalıdır (bağlantılı listeler yerine).
Tony O'Hagan

1
Lisansı MIT olarak değiştirdim (bu kadar basit bir şeyde hiçbir şeyi engellemek istemiyorum). Diğer teklifinize bakacağım.
Kemiksiz

Güzel, bazı ülkelerin Pazartesiden Cumaya kadar farklı çalışma günleri olabileceği için ülkeye göre iş günü yönetimini görmek ilginç olurdu.
serileştirici

1

Tek gerçek çözüm, bu çağrıların işletmeniz için takvimi tanımlayan bir veritabanı tablosuna erişmesini sağlamaktır. Pazartesiden Cumaya kadar olan bir çalışma haftası için çok fazla zorlanmadan kodlayabilirsiniz, ancak tatillerle başa çıkmak zor olacaktır.

Şık olmayan ve test edilmemiş kısmi çözüm eklemek için düzenlendi:

public static DateTime AddBusinessDays(this DateTime date, int days)
{
    for (int index = 0; index < days; index++)
    {
        switch (date.DayOfWeek)
        {
            case DayOfWeek.Friday:
                date = date.AddDays(3);
                break;
            case DayOfWeek.Saturday:
                date = date.AddDays(2);
                break;
            default:
                date = date.AddDays(1);
                break;
         }
    }
    return date;
}

Ayrıca döngü yok gereksinimini de ihlal ettim.


Cumartesi davasının asla vurulacağını sanmıyorum.
CoderDennis

@Dennis - geçen tarih Cumartesi ise olur.
Jamie Ide

Çalışması için kodunuzu düzenleme özgürlüğünü aldım. Lütfen bir dahaki sefere göndermeden önce kodu test edin, teşekkürler.
bytecode77

Ve sıfır olumlu oyların kendi adına konuştuğunu sanıyordum. Teşekkürler!
Jamie Ide

1

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

/// <summary>
/// Helper/extension class for manipulating date and time values.
/// </summary>
public static class DateTimeExtensions
{
    /// <summary>
    /// Calculates the absolute year difference between two dates.
    /// </summary>
    /// <param name="dt1"></param>
    /// <param name="dt2"></param>
    /// <returns>A whole number representing the number of full years between the specified dates.</returns>
    public static int Years(DateTime dt1,DateTime dt2)
    {
        return Months(dt1,dt2)/12;
        //if (dt2<dt1)
        //{
        //    DateTime dt0=dt1;
        //    dt1=dt2;
        //    dt2=dt0;
        //}

        //int diff=dt2.Year-dt1.Year;
        //int m1=dt1.Month;
        //int m2=dt2.Month;
        //if (m2>m1) return diff;
        //if (m2==m1 && dt2.Day>=dt1.Day) return diff;
        //return (diff-1);
    }

    /// <summary>
    /// Calculates the absolute year difference between two dates.
    /// Alternative, stand-alone version (without other DateTimeUtil dependency nesting required)
    /// </summary>
    /// <param name="start"></param>
    /// <param name="end"></param>
    /// <returns></returns>
    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);
    }

    /// <summary>
    /// Calculates the absolute month difference between two dates.
    /// </summary>
    /// <param name="dt1"></param>
    /// <param name="dt2"></param>
    /// <returns>A whole number representing the number of full months between the specified dates.</returns>
    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);
    }

    /// <summary>
    /// Returns the higher of the two date time values.
    /// </summary>
    /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param>
    /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param>
    /// <returns><c>dt1</c> or <c>dt2</c>, whichever is higher.</returns>
    public static DateTime Max(DateTime dt1,DateTime dt2)
    {
        return (dt2>dt1?dt2:dt1);
    }

    /// <summary>
    /// Returns the lower of the two date time values.
    /// </summary>
    /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param>
    /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param>
    /// <returns><c>dt1</c> or <c>dt2</c>, whichever is lower.</returns>
    public static DateTime Min(DateTime dt1,DateTime dt2)
    {
        return (dt2<dt1?dt2:dt1);
    }

    /// <summary>
    /// Adds the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be added.</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    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;
    }

    /// <summary>
    /// Subtracts the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be subtracted.</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime SubtractBusinessDays(
        this DateTime current, 
        int days,
        IEnumerable<DateTime> holidays)
    {
        return AddBusinessDays(current, -days, holidays);
    }

    /// <summary>
    /// Retrieves the number of business days from two dates
    /// </summary>
    /// <param name="startDate">The inclusive start date</param>
    /// <param name="endDate">The inclusive end date</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns></returns>
    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))
                )
            {
                // skip holiday
            }
            else cnt++;
        }
        return cnt;
    }

    /// <summary>
    /// Calculate Easter Sunday for any given year.
    /// src.: https://stackoverflow.com/a/2510411/1233379
    /// </summary>
    /// <param name="year">The year to calcolate Easter against.</param>
    /// <returns>a DateTime object containing the Easter month and day for the given year</returns>
    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);
    }

    /// <summary>
    /// Retrieve holidays for given years
    /// </summary>
    /// <param name="years">an array of years to retrieve the holidays</param>
    /// <param name="countryCode">a country two letter ISO (ex.: "IT") to add the holidays specific for that country</param>
    /// <param name="cityName">a city name to add the holidays specific for that city</param>
    /// <returns></returns>
    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),       // 1 gennaio (capodanno)
                new DateTime(year, 1, 6),       // 6 gennaio (epifania)
                new DateTime(year, 5, 1),       // 1 maggio (lavoro)
                new DateTime(year, 8, 15),      // 15 agosto (ferragosto)
                new DateTime(year, 11, 1),      // 1 novembre (ognissanti)
                new DateTime(year, 12, 8),      // 8 dicembre (immacolata concezione)
                new DateTime(year, 12, 25),     // 25 dicembre (natale)
                new DateTime(year, 12, 26)      // 26 dicembre (s. stefano)
            });

            // add easter sunday (pasqua) and monday (pasquetta)
            var easterDate = GetEasterSunday(year);
            lst.Add(easterDate);
            lst.Add(easterDate.AddDays(1));

            // country-specific holidays
            if (!String.IsNullOrEmpty(countryCode))
            {
                switch (countryCode.ToUpper())
                {
                    case "IT":
                        lst.Add(new DateTime(year, 4, 25));     // 25 aprile (liberazione)
                        break;
                    case "US":
                        lst.Add(new DateTime(year, 7, 4));     // 4 luglio (Independence Day)
                        break;

                    // todo: add other countries

                    case default:
                        // unsupported country: do nothing
                        break;
                }
            }

            // city-specific holidays
            if (!String.IsNullOrEmpty(cityName))
            {
                switch (cityName)
                {
                    case "Rome":
                    case "Roma":
                        lst.Add(new DateTime(year, 6, 29));  // 29 giugno (s. pietro e paolo)
                        break;
                    case "Milano":
                    case "Milan":
                        lst.Add(new DateTime(year, 12, 7));  // 7 dicembre (s. ambrogio)
                        break;

                    // todo: add other cities

                    default:
                        // unsupported city: do nothing
                        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 .


0
    public static DateTime AddBusinessDays(DateTime date, int days)
    {
        if (days == 0) return date;
        int i = 0;
        while (i < days)
        {
            if (!(date.DayOfWeek == DayOfWeek.Saturday ||  date.DayOfWeek == DayOfWeek.Sunday)) i++;  
            date = date.AddDays(1);
        }
        return date;
    }

Gelecekte cevap için biraz daha fazla bağlam ekleyin ve belki de elinizdekini neden koydunuz :)
dax

0

Eklenecek negatif sayıda günü destekleyen bir "AddBusinessDays" istedim ve şunu elde ettim:

// 0 == Monday, 6 == Sunday
private static int epochDayToDayOfWeek0Based(long epochDay) {
    return (int)Math.floorMod(epochDay + 3, 7);
}

public static int daysBetween(long fromEpochDay, long toEpochDay) {
    // http://stackoverflow.com/questions/1617049/calculate-the-number-of-business-days-between-two-dates
    final int fromDOW = epochDayToDayOfWeek0Based(fromEpochDay);
    final int toDOW = epochDayToDayOfWeek0Based(toEpochDay);
    long calcBusinessDays = ((toEpochDay - fromEpochDay) * 5 + (toDOW - fromDOW) * 2) / 7;

    if (toDOW   == 6) calcBusinessDays -= 1;
    if (fromDOW == 6) calcBusinessDays += 1;
    return (int)calcBusinessDays;
}

public static long addDays(long epochDay, int n) {
    // https://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/
    // NB: in .NET, Sunday == 0, but in our code Monday == 0
    final int dow = (epochDayToDayOfWeek0Based(epochDay) + 1) % 7;
    final int wds = n + (dow == 0 ? 1 : dow); // Adjusted number of working days to add, given that we now start from the immediately preceding Sunday
    final int wends = n < 0 ? ((wds - 5) / 5) * 2
                            : (wds / 5) * 2 - (wds % 5 == 0 ? 2 : 0);
    return epochDay - dow + // Find the immediately preceding Sunday
           wds +            // Add computed working days
           wends;           // Add weekends that occur within each complete working week
}

Döngü gerekmez, bu yüzden "büyük" eklemeler için bile makul derecede hızlı olmalıdır.

Yeni JDK8 LocalDate sınıfı tarafından açığa çıkarıldığından ve Java'da çalıştığım için, çağdan bu yana birkaç takvim günü olarak ifade edilen günlerle çalışır. Yine de diğer ayarlara uyum sağlamak basit olmalıdır.

Temel özellikleri olduğunu vardır addDayshep herkes için hafta içi döndürür ve o dve n,daysBetween(d, addDays(d, n)) == n

Teorik olarak 0 gün ekleme ve 0 gün çıkarma işlemlerinin farklı işlemler olması gerektiğini unutmayın (tarihiniz Pazar ise, 0 gün eklemek sizi Pazartesi'ye ve 0 gün çıkarmak sizi Cuma'ya götürmelidir). Negatif 0 diye bir şey olmadığından (kayan noktanın dışında!), N = 0 bağımsız değişkenini sıfır gün eklemek anlamında yorumlamayı seçtim .


0

Bunun GetBusinessDays için daha basit bir yol olabileceğine inanıyorum:

    public int GetBusinessDays(DateTime start, DateTime end, params DateTime[] bankHolidays)
    {
        int tld = (int)((end - start).TotalDays) + 1; //including end day
        int not_buss_day = 2 * (tld / 7); //Saturday and Sunday
        int rest = tld % 7; //rest.

        if (rest > 0)
        {
            int tmp = (int)start.DayOfWeek - 1 + rest;
            if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2;
        }

        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start <= bh && bh <= end))
            {
                not_buss_day++;
            }
        }
        return tld - not_buss_day;
    }

0

İşte hem kalkış tarihi hem de müşteride teslim tarihi ile birlikte kodum.

            // Calculate departure date
            TimeSpan DeliveryTime = new TimeSpan(14, 30, 0); 
            TimeSpan now = DateTime.Now.TimeOfDay;
            DateTime dt = DateTime.Now;
            if (dt.TimeOfDay > DeliveryTime) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1);
            dt = dt.Date + DeliveryTime;
            string DepartureDay = "today at "+dt.ToString("HH:mm");
            if (dt.Day!=DateTime.Now.Day)
            {
                DepartureDay = dt.ToString("dddd at HH:mm", new CultureInfo(WebContextState.CurrentUICulture));
            }
            Return DepartureDay;

            // Caclulate delivery date
            dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1);
            string DeliveryDay = dt.ToString("dddd", new CultureInfo(WebContextState.CurrentUICulture));
            return DeliveryDay;

Mutlu kodlamalar.


0
public static DateTime AddWorkingDays(this DateTime date, int daysToAdd)
{
    while (daysToAdd > 0)
    {
        date = date.AddDays(1);

        if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday)
        {
            daysToAdd -= 1;
        }
    }

    return date;
}

0
public static int GetBusinessDays(this DateTime start, DateTime end)
            {
                return Enumerable.Range(0, (end- start).Days)
                                .Select(a => start.AddDays(a))
                                .Where(a => a.DayOfWeek != DayOfWeek.Sunday)
                                .Where(a => a.DayOfWeek != DayOfWeek.Saturday)
                                .Count();
    
            }

-1

Umarım bu birine yardımcı olur.

private DateTime AddWorkingDays(DateTime addToDate, int numberofDays)
    {
        addToDate= addToDate.AddDays(numberofDays);
        while (addToDate.DayOfWeek == DayOfWeek.Saturday || addToDate.DayOfWeek == DayOfWeek.Sunday)
        {
            addToDate= addToDate.AddDays(1);
        }
        return addToDate;
    }

2
Bu yanlış. Çoğu durumda işe yaramayacaktır. Kimseye yardım etme olasılığı düşük.
Neolisk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.