Soru AddBusinessDays ve GetBusinessDays


2 adet zarif ve eksiksiz uygulamayı bulmam gerek

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ÜZENLE:  İş günlerine göre iş günlerini kastediyorum (Pazartesi, Salı, Çarşamba, Perşembe, Cuma). Tatil yok, sadece hafta sonları hariç.

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


Şimdiye kadar yazmış olduğum şey bu. Her durumda çalışır ve negatif yapar. Hala bir GetBusinessDays uygulamasına ihtiyaç 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);
}

76
2018-06-25 15:48


Menşei


Tarihler kadar mantıksız bir şey olduğunda zarif çözümler var mı? - Wyatt Barnett
Donno. Bu yüzden sordum. - Adrian Zanescu
Tatiller ile ilgili misiniz? - James Conigliaro
Tatiller ile ilgili misiniz? James Conigliaro. Yok hayır - Adrian Zanescu
Yardım etmeye çalışan insanlar oy verme, kazanan bir strateji değildir. - Jamie Ide


Cevaplar:


İlk işleviniz için en son girişimi:

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, GetBusinessDays, aşağıdaki gibi 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;
    }
}

118
2018-06-25 16:14



İkincisi için, bir çözüm tarih ve tarih + gün arasındaki farkı almaktır. Bu, iki fonksiyonun düzgün bir şekilde senkronize edilmesini ve yedeklemeyi kaldırmasını garantilemek açısından güzeldir. - Brian
@Patrick: Şimdi düzeltilmelidir - umarım düzenlemeye aldırmazsınız. (Sadece aptalca bir şey yapsam geri al.) - Noldorin
Evet, sonunda oraya vardık. (Ben küçük katkı için 'biz' diyorum!) Çaba için yukarı oy. - Noldorin
Oy-up. Sadece içinden geçmeme yardımcı olacak bazı kod yorumlarını çok isterim. - PeterX
DateTime.AddDays negatif sayılarla çalışır. Bu, AddBusinessDays ile negatif sayıları kullanarak aynı kalıbı doğru şekilde takip etmez, iş dışı günlerin seçilmesine izin verir. - Ristogod


kullanma Akıcı DateTime:

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

iç 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);
    }

56
2017-09-04 13:12



VB.Net'e dönüştürüldüğünde aslında benim için çalışan tek çözüm budur. - Nicholas Head
OP, döngüler istemedi; En az verimli şekilde bir şey yapmanın şık bir tarafı yoktur. - Neolisk


İş günlerini eklemenize veya çıkarmanıza izin veren bir uzantı oluşturdum. Çıkarmak için negatif sayıda businessDays kullanın. Bence oldukça zarif bir çözüm. Her durumda çalışı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);
        }
    }
}

Örnek:

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();
        }
    }
}

11
2017-08-06 12:55



Kaynak tarihin Cumartesi veya Pazar olması durumunda sonuç sorgulanabilir. Örneğin: Cumartesi + 1 iş günü, Pazartesi günü beklemeyi tercih ettiğim Salı günü sonuçlandı. - Slauma
@Slauma: Kanada'daki çoğu işletme böyle çalışır. +1 iş günü = Cumartesi günü Salı günü olan "bir sonraki iş günü". Pazartesi, "aynı iş günü" olacaktı. - Neolisk
@Slauma Programı amaçlandığı gibi çalışır. Mantıklı düşünün. İşle ilgili bir şey cumartesi günü başlıyorsa ve iş gününün süresi boyunca insanların tepki vermesi için 1 iş gününe izin vermeniz gerekiyorsa, Pazartesi gününe kadar yapılması gerektiğini söylemek mantıklı olur mu ?! - Heliac


Benim için hafta sonlarını atlayan ve negatif ya da pozitif olan bir çözüm bulmam gerekiyordu. Kriterlerim, ileri gidip bir haftasonuna indiği takdirde pazartesi ilerlemesinin gerekmesiydi. Eğer bir hafta sonu geri gidip iniyorsa, cumaya 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 sen fikir almak;)

Bu uzantı sınıfını yazmayı bitirdim

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 yerlerde kullanmak için 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;
        }
    }
}

Eğer bununla uğraşmak istemiyorsan, sadece değiştirebilirsin if (MyClass.IsBusinessDay(date)) eğer varsa if ((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ı testlerden sonuçlar:

Beklenen Sonuç Testi
Ç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

6
2017-09-17 15:27



İyi iş! Bunu yazdığın için teşekkürler. - Jean-Paul


Uluslararasılaşma ile bu zor. Burada diğer konularda da belirtildiği üzere, bayramlar ülkeden ülkeye ve hatta ilden bölgeye farklılık göstermektedir. Çoğu hükümet, tatillerini beş yıldan fazla bir süre için planlamamaktadır.


2
2018-06-25 16:04



Birisinin neden Ash'ı reddettiğini anlayamıyorum: sorulanın cevabı değil, Ash'ın TAMAMEN DOĞRU OLDUĞU, aynı sorunla karşılaştığım doğru: yazılımım Avrupa’da (Mon-Sun) ve Afrika’da Asya (Sat-Cum). Bunu reddetmek için, kişinin burnunun ötesini göremeyen bir eşek (hayvan, her halükarda) olması gerekir: Bilgiden korkan, sadece bilmek ve tercih etmek istemeyen SO üzerinde insanlar var gibi görünüyor. güvencesiz cehaletlerinde kalmaya devam ediyorlar: ama ilk etapta AZ'ye bir hizmet yapmıyorlar (ve kendilerine de, ama kendi işlerini yapıyorlar) - M.Turrini
i (OP) inkar ettim çünkü sorunların ne olduğunu açıklığa kavuşturduğumu sandım ve Ash dind'in dikkat etmediğini düşündüm. Birilerinin canını yakarsa özür dilerim ama sadece bir oyundur - Adrian Zanescu
@AZ: Orijinal soruda uluslararasılaştırma kısıtlamalarından söz ettiniz mi? - Ash Machine
@AshMachine, tam olarak. O yapmadı. - jwg
Tatiller ülkeden ülkeye farklılık gösterir, ancak bu sorunun tatil ile ilgisi yoktur. Sorun açıklamasında açıkça belirtildiği gibi hafta sonları ile ilgilidir. Bu bir yorum olmalıydı. - Neolisk


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
2018-06-25 16:42





Cevap için geç geliyorum, ama iş günlerinde basit operasyonlar yapmak için gereken tüm kişiselleştirmelerle küçük bir kütüphane yaptım ... Onu burada bırakıyorum: Çalışma Günleri Yönetimi


1
2018-04-08 13:56



Ne yazık ki, bu GNU lisanslı yani herhangi bir ticari uygulama için "yasal zehir" dir. Bunu "MIT" veya "Apache" ye saklamanın bir ihtimali var mı? - Tony O'Hagan
Bazı statik listeler muhtemelen diziler olmalıdır (bağlantılı listeler yerine). - Tony O'Hagan
Sadece lisansı MIT olarak değiştirdim (basit bir şey üzerinde herhangi bir şeyi engellemek istemiyorum). Diğer teklifinize bakacağım. - Boneless
Güzel, bazı ülkelerin çalışma günlerini pazartesiden cumaya kadar olduğundan, iş günü yönetimini ülke bazında görmek ilginç olurdu. - serializer