Tarih - Bir sonraki salı alın


154

Önümüzdeki Salı gününü nasıl edinebilirim?

PHP'de bu kadar basit strtotime('next tuesday');.

.NET'te benzer bir şeyi nasıl başarabilirim?


15
ASP.NET bir dizi web teknolojisidir. C # bir dildir. Bunu gerçekten sade .NET açısından düşünmeniz gerekiyor. Şimdi, "gelecek Salı" için - bu "bugünden sonraki ilk Salı" mı? Pazartesi olsaydı ve birisi "önümüzdeki Salı görüşürüz" derse, bunun 1 yerine 8 gün anlamına gelmesini beklerdim. Ya bugün bir Salı ise? Günün hangi saatine ihtiyacınız var?
Jon Skeet

Bugün salı ise, bir sonraki salı günü ne zaman bulmak istiyorsunuz? Yoksa bugün pazartesi, pazartesiden 2. salı mı bulmak istiyorsunuz?
FIre Panda

En yakın salı, hangi gün olduğu belli olacak.
brenjt

2
@brenjtL: Peki zaten Salı günüyse?
Jon Skeet

Zaten Salı ise aynı gün
brenjt

Yanıtlar:


371

Yorumlarda bahsettiğim gibi, "önümüzdeki Salı" ile ifade edebileceğiniz çeşitli şeyler vardır, ancak bu kod size "önümüzdeki Salı günü veya bugün zaten Salı ise" verir:

DateTime today = DateTime.Today;
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilTuesday = ((int) DayOfWeek.Tuesday - (int) today.DayOfWeek + 7) % 7;
DateTime nextTuesday = today.AddDays(daysUntilTuesday);

Zaten Salı ise "bir haftalık zaman" vermek istiyorsanız şunu kullanabilirsiniz:

// This finds the next Monday (or today if it's Monday) and then adds a day... so the
// result is in the range [1-7]
int daysUntilTuesday = (((int) DayOfWeek.Monday - (int) today.DayOfWeek + 7) % 7) + 1;

... ya da orijinal formülü kullanabilirsiniz, ancak yarından itibaren:

DateTime tomorrow = DateTime.Today.AddDays(1);
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilTuesday = ((int) DayOfWeek.Tuesday - (int) tomorrow.DayOfWeek + 7) % 7;
DateTime nextTuesday = tomorrow.AddDays(daysUntilTuesday);

EDIT: Sadece bu güzel ve çok yönlü yapmak için:

public static DateTime GetNextWeekday(DateTime start, DayOfWeek day)
{
    // The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
    int daysToAdd = ((int) day - (int) start.DayOfWeek + 7) % 7;
    return start.AddDays(daysToAdd);
}

"Bugün veya önümüzdeki 6 gün içinde" değerini elde etmek için:

DateTime nextTuesday = GetNextWeekday(DateTime.Today, DayOfWeek.Tuesday);

"Bugün hariç gelecek Salı" değerini almak için:

DateTime nextTuesday = GetNextWeekday(DateTime.Today.AddDays(1), DayOfWeek.Tuesday);

Vay canına, bir sonraki salı gününe kadar nci günleri nasıl alabileceğimi merak ediyordum ve cevabınızı Nice örneğiyle güncellediniz. Teşekkürler
brenjt

Doğru cevabı seçmek zordu. Ama seninki en çok yönlü gibi görünüyor ve anlaşılmasını kolaylaştırdın. Yardımın için teşekkürler.
brenjt

1
@brenjt: Aslında Sven'in daha çok yönlü olduğunu söyleyebilirim, haftanın gününü belirtebilirsiniz, ancak bu sizin çağrınız :) (Şimdi daha genel bir sürüm vermek için benimkini düzenledim.)
Jon Skeet

1
Ancak +7)%7çözüm oldukça güzel. Kullanmamamın nedeni, bir mikro optimizasyonun biraz olması ve yanlış anlaşılması çok kolay (bazı okunabilirliği feda etmenin yanı sıra).
Sven

Bir birim testi: [TestMethod] genel void ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (şimdi.Day <test.Day, "Beklenen ay günü burada değil."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Beklenen hafta günü burada değil."); Assert.IsTrue ((test.Day - now.Day) <7, "Beklenen gün aralığı burada değil."); }
rasx

67

Bu hile yapmalı:

static DateTime GetNextWeekday(DayOfWeek day)
{
    DateTime result = DateTime.Now.AddDays(1);
    while( result.DayOfWeek != day )
        result = result.AddDays(1);
    return result;
}

Büyük tepki, bugün Salı ise (ki bu ha) bu bugün veya bir sonraki salı günü geri dönecek mi?
brenjt

3
Bu, önümüzdeki Salı günü geri dönecek. Bugün geri dönmesini istiyorsanız .AddDays(1), ilk satırdan kaldırın , böylece DateTime.Nowkendisini de kontrol edecektir .
Sven

7

Bu soruna daha az ayrıntılı ve daha akıllı / zarif çözümler var, ancak aşağıdaki C # işlevi birçok durum için gerçekten iyi çalışıyor.

/// <summary>
/// Find the closest weekday to the given date
/// </summary>
/// <param name="includeStartDate">if the supplied date is on the specified day of the week, return that date or continue to the next date</param>
/// <param name="searchForward">search forward or backward from the supplied date. if a null parameter is given, the closest weekday (ie in either direction) is returned</param>
public static DateTime ClosestWeekDay(this DateTime date, DayOfWeek weekday, bool includeStartDate = true, bool? searchForward=true)
{
    if (!searchForward.HasValue && !includeStartDate) 
    {
        throw new ArgumentException("if searching in both directions, start date must be a valid result");
    }
    var day = date.DayOfWeek;
    int add = ((int)weekday - (int)day);
    if (searchForward.HasValue)
    {
        if (add < 0 && searchForward.Value)
        {
            add += 7;
        }
        else if (add > 0 && !searchForward.Value)
        {
            add -= 7;
        }
        else if (add == 0 && !includeStartDate)
        {
            add = searchForward.Value ? 7 : -7;
        }
    }
    else if (add < -3) 
    {
        add += 7; 
    }
    else if (add > 3)
    {
        add -= 7;
    }
    return date.AddDays(add);
}

1
DateTime'a ek olarak uygulanan tek cevap. Diğer çözümlerin hepsi çalışırken, bir genişletme yöntemi olarak kullanmak, kullanımı en kolay kodu üretir.
Ryan McArthur

5
DateTime nextTuesday = DateTime.Today.AddDays(((int)DateTime.Today.DayOfWeek - (int)DayOfWeek.Tuesday) + 7);

Bugün Pazartesi ise, verdiğiniz yanıt yarın yerine Salı'dan bir hafta gelir.
Tony

5

@Jon Skeet iyi cevap.

Önceki Gün için:

private DateTime GetPrevWeekday(DateTime start, DayOfWeek day) {
    // The (... - 7) % 7 ensures we end up with a value in the range [0, 6]
    int daysToRemove = ((int) day - (int) start.DayOfWeek - 7) % 7;
    return start.AddDays(daysToRemove);
}

Teşekkürler!!


Bu çözümün modulo operatörüne teslim edilen negatif sayıları içerdiğini unutmayın. Modülo operatörü hakkında Wikipedia makalesi söylüyor "Ne zaman ya bir veya n negatif, naif tanım kırıldığı ve diller bu değerlerin nasıl tanımlandığı farklı programlama olduğunu." Bu muhtemelen C # 'da çalışırken, aynı sonucu elde etmek için matematiksel olarak daha' katı 'bir çözüm aşağıdaki DayOfWeekgibi değerleri değiştirmek olacaktır :int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
Andre

4
DateTime nexttuesday=DateTime.Today.AddDays(1);

while(nexttuesday.DayOfWeek!=DayOfWeek.Tuesday)
   nexttuesday = nexttuesday.AddDays(1);

3

Güncel tarihi dahil etmek veya hariç tutmak için çok basit bir örnek, ilgilendiğiniz tarihi ve günü belirtirsiniz.

public static class DateTimeExtensions
{
    /// <summary>
    /// Gets the next date.
    /// </summary>
    /// <param name="date">The date to inspected.</param>
    /// <param name="dayOfWeek">The day of week you want to get.</param>
    /// <param name="exclDate">if set to <c>true</c> the current date will be excluded and include next occurrence.</param>
    /// <returns></returns>
    public static DateTime GetNextDate(this DateTime date, DayOfWeek dayOfWeek, bool exclDate = true)
    {
        //note: first we need to check if the date wants to move back by date - Today, + diff might move it forward or backwards to Today
        //eg: date - Today = 0 - 1 = -1, so have to move it forward
        var diff = dayOfWeek - date.DayOfWeek;
        var ddiff = date.Date.Subtract(DateTime.Today).Days + diff;

        //note: ddiff < 0 : date calculates to past, so move forward, even if the date is really old, it will just move 7 days from date passed in
        //note: ddiff >= (exclDate ? 6 : 7) && diff < 0 : date is into the future, so calculated future weekday, based on date
        if (ddiff < 0 || ddiff >= (exclDate ? 6 : 7) && diff < 0)
            diff += 7; 

        //note: now we can get safe values between 0 - 6, especially if past dates is being used
        diff = diff % 7;

        //note: if diff is 0 and we are excluding the date passed, we will add 7 days, eg: 1 week
        diff += diff == 0 & exclDate ? 7 : 0;

        return date.AddDays(diff);
    }
}

bazı test senaryoları

[TestMethod]
    public void TestNextDate()
    {
        var date = new DateTime(2013, 7, 15);
        var start = date;
        //testing same month - forwardOnly
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //16
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //17
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //18
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Friday)); //19
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Saturday)); //20
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Sunday)); //21
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Monday)); //22

        //testing same month - include date
        Assert.AreEqual(start = date, date.GetNextDate(DayOfWeek.Monday, false)); //15
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday, false)); //16
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday, false)); //17

        //testing month change - forwardOnly
        date = new DateTime(2013, 7, 29);
        start = date;
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //30
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //31
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //2013/09/01-month increased
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Friday)); //02

        //testing year change
        date = new DateTime(2013, 12, 30);
        start = date;
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //31
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //2014/01/01 - year increased
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //02
    }

Bazı kapsamlı testlerden sonra orijinal yanıttan ek değişiklikler yaptım. Bu, ertesi günü kullanılan tarihe, geçmişe, bugüne ve geleceğe göre güvenli bir şekilde hesaplayacaktır. Önceki tüm örnekler harika, ancak belirli koşullar altında başarısız oldu. Tek satırlık bir açıklama yapmadım, böylece hesaplamaların ne yaptığı hakkında ek yorumlar yapılabilir. Jon Skeet'in olumlu davası harikaydı, ancak sahip olduğum dava bir günden bir gün önce, ama Bugün'den daha büyüktü ve bugüne veya düne geçerse ... bu sorunu çözdü.
AJB

1

Ayrıca bir uzantı olabilir , hepsi bağlıdır

public static class DateTimeExtensions
{
    public static IEnumerable<DateTime> Next(this DateTime date, DayOfWeek day)
    {
        // This loop feels expensive and useless, but the point is IEnumerable
        while(true)
        {
            if (date.DayOfWeek == day)
            {
                yield return date;
            }
            date = date.AddDays(1);
        }
    }
}

kullanım

    var today = DateTime.Today;
    foreach(var monday in today.Next(DayOfWeek.Monday))
    {
        Console.WriteLine(monday);
        Console.ReadKey();
    }

0

Şimdi oneliner lezzetinde - bir parametre olarak parametre olarak geçirmeniz gerektiğinde.

DateTime.Now.AddDays(((int)yourDate.DayOfWeek - (int)DateTime.Now.DayOfWeek + 7) % 7).Day

Bu özel durumda:

DateTime.Now.AddDays(((int)DayOfWeek.Tuesday - (int)DateTime.Now.DayOfWeek + 7) % 7).Day

-5

Amaç C Versiyonu:

+(NSInteger) daysUntilNextWeekday: (NSDate*)startDate withTargetWeekday: (NSInteger) targetWeekday
{
    NSInteger startWeekday = [[NSCalendar currentCalendar] component:NSCalendarUnitWeekday fromDate:startDate];
    return (targetWeekday - startWeekday + 7) % 7;
}

4
Güzel cevap, ancak orijinal soru .NET hakkında sordu.
Adam Davis
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.