Datetime - Holen Sie sich den nächsten Dienstag

154

Wie kann ich das Datum für den nächsten Dienstag erhalten?

In PHP ist es so einfach wie strtotime('next tuesday');.

Wie kann ich in .NET etwas Ähnliches erreichen?

brenjt
quelle
15
ASP.NET ist eine Reihe von Webtechnologien. C # ist eine Sprache. Sie müssen wirklich in Bezug auf einfaches .NET darüber nachdenken. Nun, für "nächsten Dienstag" - ist das "der erste Dienstag nach heute"? Wenn es Montag wäre und jemand sagte "Bis nächsten Dienstag", würde ich erwarten, dass dies 8 Tage Zeit bedeutet anstatt 1. Was ist, wenn heute ein Dienstag ist? Welche Tageszeit brauchst du?
Jon Skeet
Wenn heute Dienstag ist, möchten Sie das Datum finden, an dem der nächste Dienstag ist? Oder ist heute Montag, möchten Sie den 2. Dienstag ab Montag finden?
Feuer Panda
Der nächste Dienstag für jeden Tag.
Brenjt
2
@brenjtL: Und wenn es schon Dienstag ist?
Jon Skeet
Wenn schon Dienstag dann am selben Tag
brenjt

Antworten:

371

Wie ich in den Kommentaren erwähnt habe, gibt es verschiedene Dinge, die Sie mit "nächster Dienstag" meinen könnten, aber dieser Code gibt Ihnen "den nächsten Dienstag oder heute, wenn es bereits Dienstag ist":

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

Wenn Sie "eine Woche Zeit" angeben möchten, wenn es bereits Dienstag ist, können Sie Folgendes verwenden:

// 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;

... oder Sie könnten die Originalformel verwenden, aber ab morgen:

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: Nur um dies schön und vielseitig zu machen:

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

So erhalten Sie den Wert für "heute oder in den nächsten 6 Tagen":

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

Um den Wert für "den nächsten Dienstag außer heute" zu erhalten:

DateTime nextTuesday = GetNextWeekday(DateTime.Today.AddDays(1), DayOfWeek.Tuesday);
Jon Skeet
quelle
Wow, ich habe mich nur gefragt, wie ich bis zum nächsten Dienstag n-te Tage bekommen könnte, und Sie haben dann Ihre Antwort mit einem Beispiel Nizza aktualisiert. Danke
brenjt
Es war schwer, die richtige Antwort zu wählen. Aber deine scheint die vielseitigste zu sein und du hast es leicht verständlich gemacht. Danke für deine Hilfe.
Brenjt
1
@brenjt: Eigentlich würde ich sagen, dass Sven's vielseitiger ist, da Sie den Wochentag angeben können, aber es ist Ihr Anruf :) (Ich habe meinen jetzt bearbeitet, um eine allgemeinere Version zu erhalten.)
Jon Skeet
1
Die +7)%7Lösung ist allerdings ziemlich gut. Obwohl der Grund, warum ich das nicht benutzt habe, darin besteht, dass es ein bisschen wie eine Mikrooptimierung ist und zu leicht, um etwas falsch zu machen (und die Lesbarkeit zu beeinträchtigen), imho natürlich.
Sven
Ein Komponententest: [TestMethod] public void ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (now.Day <test.Day, "Der erwartete Monatstag ist nicht hier."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Der erwartete Wochentag ist nicht hier."); Assert.IsTrue ((test.Day - now.Day) <7, "Das erwartete Tagesintervall ist nicht hier."); }
Rasx
67

Dies sollte den Trick tun:

static DateTime GetNextWeekday(DayOfWeek day)
{
    DateTime result = DateTime.Now.AddDays(1);
    while( result.DayOfWeek != day )
        result = result.AddDays(1);
    return result;
}
Sven
quelle
Tolle Resonanz, wenn heute Dienstag ist (was es ist ha), wird dies heute oder am nächsten Dienstag zurückkehren?
Brenjt
3
Dies wird am nächsten Dienstag zurückkehren. Wenn Sie möchten, dass es heute zurückgegeben wird, entfernen Sie es einfach .AddDays(1)aus der ersten Zeile. Auf diese Weise wird es auch DateTime.Nowselbst überprüft .
Sven
7

Es gibt weniger ausführliche und cleverere / elegantere Lösungen für dieses Problem, aber die folgende C # -Funktion funktioniert in einer Reihe von Situationen sehr gut.

/// <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);
}
Brent
quelle
1
Die einzige Antwort, die als Erweiterung von DateTime implementiert wird. Während die anderen Lösungen alle funktionieren, erzeugt es als Erweiterungsmethode den am einfachsten zu verwendenden Code.
Ryan McArthur
5
DateTime nextTuesday = DateTime.Today.AddDays(((int)DateTime.Today.DayOfWeek - (int)DayOfWeek.Tuesday) + 7);
Köter
quelle
Wenn heute Montag ist, ergibt die von Ihnen angegebene Antwort eine Woche ab Dienstag und nicht ab morgen.
Tony
5

@ Jon Skeet gute Antwort.

Für den vorherigen Tag:

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

Vielen Dank!!

Anik Islam Abhi
quelle
Beachten Sie, dass diese Lösung negative Zahlen enthält, die dem Modulo-Operator übergeben werden. In dem Wikipedia-Artikel über den Modulo-Operator heißt es: "Wenn entweder a oder n negativ ist, bricht die naive Definition zusammen und die Programmiersprachen unterscheiden sich in der Definition dieser Werte." Während dies wahrscheinlich in C # funktioniert, wäre eine mathematisch „solidere“ Lösung, um das gleiche Ergebnis zu erzielen, das Vertauschen der folgenden DayOfWeekWerte: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);
Blind
quelle
3

Sehr einfaches Beispiel zum Einschließen oder Ausschließen des aktuellen Datums. Sie geben das Datum und den Tag der Woche an, an der Sie interessiert sind.

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

einige Testfälle

[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
    }
AJB
quelle
Ich habe nach einigen umfangreichen Tests zusätzliche Änderungen gegenüber der ursprünglichen Antwort vorgenommen. Dies berechnet nun sicher den nächsten Tag basierend auf dem verwendeten Datum, der Vergangenheit, der Gegenwart und der Zukunft. Alle vorherigen Beispiele waren großartig, scheiterten aber unter bestimmten Bedingungen. Ich habe es nicht zu einer einzeiligen Aussage gemacht, damit zusätzliche Kommentare zu den Berechnungen abgegeben werden können. Der positive Fall von Jon Skeet war großartig, obwohl der Fall, den ich hatte, darin bestand, einen Tag von einem Datum zurück zu ziehen, aber immer noch größer als heute, und was ist, wenn er auf heute oder gestern verschoben wird ... das hat es gelöst.
AJB
1

Es könnte auch eine Erweiterung sein, alles hängt davon ab

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

Verwendung

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

Jetzt im Oneliner-Geschmack - für den Fall, dass Sie ihn als Parameter an einen Mechanismus übergeben müssen.

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

In diesem speziellen Fall:

DateTime.Now.AddDays(((int)DayOfWeek.Tuesday - (int)DateTime.Now.DayOfWeek + 7) % 7).Day
Matas Vaitkevicius
quelle
-5

Ziel C Version:

+(NSInteger) daysUntilNextWeekday: (NSDate*)startDate withTargetWeekday: (NSInteger) targetWeekday
{
    NSInteger startWeekday = [[NSCalendar currentCalendar] component:NSCalendarUnitWeekday fromDate:startDate];
    return (targetWeekday - startWeekday + 7) % 7;
}
Max Hiroyuki Ueda
quelle
4
Coole Antwort, aber die ursprüngliche Frage zu .NET.
Adam Davis