Datetime - Ottieni martedì prossimo


154

Come posso ottenere la data del prossimo martedì?

In PHP, è semplice come strtotime('next tuesday');.

Come posso ottenere qualcosa di simile in .NET


15
ASP.NET è un insieme di tecnologie web. C # è una lingua. Devi davvero pensarci in termini di semplice .NET. Ora, per "martedì prossimo" - è "il primo martedì dopo oggi"? Se fosse lunedì e qualcuno dicesse "ci vediamo martedì prossimo", mi aspetto che significhi 8 giorni anziché 1. Che dire se oggi è un martedì? Che ora del giorno ti serve?
Jon Skeet,

Se oggi è martedì, vuoi trovare la data del prossimo martedì? O oggi è lunedì, vuoi trovare il 2 martedì da lunedì?
Fuoco Panda

Il martedì più vicino in avanti verso il giorno in cui è sempre particolare.
brenjt,

2
@brenjtL: E se è già martedì?
Jon Skeet,

Se già martedì, quello stesso giorno
brenjt,

Risposte:


371

Come ho detto nei commenti, ci sono varie cose che potresti intendere per "martedì prossimo", ma questo codice ti dà "il prossimo martedì, o oggi se è già martedì":

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

Se vuoi dare "una settimana" se è già martedì, puoi usare:

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

... oppure potresti usare la formula originale, ma da domani:

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: Solo per rendere questo bello e versatile:

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

Quindi, per ottenere il valore di "oggi o nei prossimi 6 giorni":

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

Per ottenere il valore per "il prossimo martedì escluso oggi":

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

Caspita, mi stavo solo chiedendo come avrei potuto ottenere l'ennesimo giorno fino al martedì successivo e hai quindi aggiornato la tua risposta con un esempio di Nizza. Grazie
brenjt

È stato difficile scegliere la risposta corretta. Ma il tuo sembra essere il più versatile e tu lo hai reso facile da capire. Grazie per il tuo aiuto.
brenjt,

1
@brenjt: In realtà direi che Sven's è più versatile, dato che puoi specificare il giorno della settimana, ma è la tua chiamata :) (ora ho modificato il mio per dare una versione più generalizzata.)
Jon Skeet

1
La +7)%7soluzione è piuttosto carina però. Anche se il motivo per cui non l'ho usato è perché è un po 'una micro-ottimizzazione e troppo facile sbagliare (oltre a sacrificare un po' di leggibilità), ovviamente.
Sven,

Un test unitario: [TestMethod] void pubblico ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (now.Day <test.Day, "Il giorno del mese previsto non è qui."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Il giorno della settimana previsto non è qui."); Assert.IsTrue ((test.Day - now.Day) <7, "L'intervallo del giorno previsto non è qui."); }
rasx,

67

Questo dovrebbe fare il trucco:

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

Ottima risposta, se oggi è martedì (che è ah) questo tornerà oggi o il prossimo martedì?
Brenjt,

3
Questo tornerà il prossimo martedì. Se vuoi che ritorni oggi, rimuovi semplicemente .AddDays(1)dalla prima riga, in questo modo controllerà anche DateTime.Nowse stesso.
Sven,

7

Esistono soluzioni meno dettagliate e più intelligenti / eleganti a questo problema, ma la seguente funzione C # funziona davvero bene in diverse situazioni.

/// <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
L'unica risposta che implementa come estensione di DateTime. Mentre le altre soluzioni funzionano tutte, averlo come metodo di estensione produce il codice più semplice da usare.
Ryan McArthur,

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

Se oggi è lunedì, la risposta fornita fornirà una settimana da martedì, anziché domani.
Tony,

5

@Jon Skeet buona risposta.

Per il giorno precedente:

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

Grazie!!


Si noti che questa soluzione comporta numeri negativi consegnati all'operatore modulo. L' articolo di Wikipedia sull'operatore modulo afferma che "Quando a o n è negativo, la definizione ingenua si interrompe e i linguaggi di programmazione differiscono nel modo in cui questi valori sono definiti". Mentre questo probabilmente funziona in C #, una soluzione matematicamente più "solida" per ottenere lo stesso risultato sarebbe scambiare i DayOfWeekvalori in questo modo: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

Esempio molto semplice da includere o escludere la data corrente, si specifica la data e il giorno della settimana a cui si è interessati.

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

alcuni casi di test

[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
    }

Ho apportato ulteriori modifiche alla risposta originale dopo alcuni test approfonditi. Questo ora calcolerà in modo sicuro il giorno successivo in base alla data utilizzata, passata, presente e futura. Tutti gli esempi precedenti erano fantastici, ma fallivano in determinate condizioni. Non ho fatto una dichiarazione a una riga, in modo che ulteriori commenti possano essere fatti su ciò che i calcoli stanno facendo. Il caso positivo di Jon Skeet è stato grandioso, anche se il caso che ho avuto è stato di tornare indietro di 1 giorno da una data, ma ancora più grande di oggi, e se si sposta a oggi o a ieri ... questo ha risolto il problema.
AJB

1

Esso potrebbe essere un'estensione anche, tutto dipende

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

uso

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

0

Ora nel sapore di oneliner - nel caso in cui sia necessario passarlo come parametro in qualche meccanismo.

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

In questo caso specifico:

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

-5

Versione obiettivo C:

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

4
Bella risposta, ma la domanda originale era su .NET.
Adam Davis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.