Datetime - Obtenez mardi prochain


154

Comment puis-je obtenir la date de mardi prochain?

En PHP, c'est aussi simple que strtotime('next tuesday');.

Comment puis-je réaliser quelque chose de similaire dans .NET


15
ASP.NET est un ensemble de technologies Web. C # est un langage. Vous devez vraiment penser à cela en termes de simple .NET. Maintenant, pour "mardi prochain" - est-ce "le premier mardi après aujourd'hui"? Si c'était lundi et que quelqu'un disait «à mardi prochain», je m'attendrais à ce que cela signifie 8 jours au lieu de 1. Et si aujourd'hui était un mardi? De quelle heure de la journée avez-vous besoin?
Jon Skeet le

Si aujourd'hui est mardi, vous voulez trouver la date du mardi prochain? Ou aujourd'hui c'est lundi, vous voulez trouver le 2ème mardi du lundi?
FIre Panda le

Le mardi le plus proche du jour où il se trouve.
brenjt le

2
@brenjtL: Et si c'est déjà mardi?
Jon Skeet le

Si déjà mardi, le même jour
brenjt

Réponses:


371

Comme je l'ai mentionné dans les commentaires, il y a différentes choses que vous pourriez vouloir dire par "mardi prochain", mais ce code vous donne "le mardi prochain à se produire, ou aujourd'hui si c'est déjà mardi":

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

Si vous voulez donner "le temps d'une semaine" si c'est déjà mardi, vous pouvez utiliser:

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

... ou vous pouvez utiliser la formule originale, mais à partir de demain:

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: Juste pour rendre ce joli et polyvalent:

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

Donc, pour obtenir la valeur "aujourd'hui ou dans les 6 prochains jours":

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

Pour obtenir la valeur de "le mardi prochain sauf aujourd'hui":

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

Wow, je me demandais simplement comment je pourrais avoir les nièmes jours jusqu'au mardi suivant et vous avez ensuite mis à jour votre réponse avec un exemple Nice. Merci
brenjt le

Il était difficile de choisir la bonne réponse. Mais le vôtre semble être le plus polyvalent et vous l'avez rendu facile à comprendre. Merci pour ton aide.
brenjt le

1
@brenjt: En fait, je dirais que Sven est plus polyvalent, car vous pouvez spécifier le jour de la semaine, mais c'est votre appel :) (j'ai maintenant édité le mien pour donner une version plus générale.)
Jon Skeet

1
La +7)%7solution est cependant assez sympa. Bien que la raison pour laquelle je ne l'ai pas utilisé soit parce que c'est un peu une micro-optimisation et qu'il est trop facile de se tromper (en plus de sacrifier une certaine lisibilité), à mon avis bien sûr.
Sven le

Un test unitaire: [TestMethod] public void ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (now.Day <test.Day, "Le jour du mois prévu n'est pas ici."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Le jour de la semaine prévu n'est pas ici."); Assert.IsTrue ((test.Day - now.Day) <7, "L'intervalle de jour prévu n'est pas ici."); }
rasx

67

Cela devrait faire l'affaire:

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

Bonne réponse, si aujourd'hui c'est mardi (ce qui est ha) est-ce que cela reviendra aujourd'hui ou le mardi prochain?
brenjt le

3
Cela reviendra le mardi prochain. Si vous voulez qu'il revienne aujourd'hui, supprimez simplement le .AddDays(1)de la première ligne, de cette façon, il se vérifiera également DateTime.Now.
Sven le

7

Il existe des solutions moins verbeuses et plus intelligentes / élégantes à ce problème, mais la fonction C # suivante fonctionne très bien dans un certain nombre de situations.

/// <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
La seule réponse qui implémente comme extension de DateTime. Alors que les autres solutions fonctionnent toutes, l'avoir comme méthode d'extension produit le code le plus simple à utiliser.
Ryan McArthur

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

Si aujourd'hui est lundi, la réponse que vous avez fournie rapporterait une semaine à partir de mardi, plutôt que demain.
Tony

5

@Jon Skeet bonne réponse.

Pour la journée précédente:

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

Merci!!


Notez que cette solution implique des nombres négatifs transmis à l'opérateur modulo. L' article de Wikipédia sur l'opérateur modulo dit que "Quand a ou n est négatif, la définition naïve s'effondre et les langages de programmation diffèrent dans la façon dont ces valeurs sont définies." Bien que cela fonctionne probablement en C #, une solution mathématiquement plus `` solide '' pour obtenir le même résultat serait d'échanger les DayOfWeekvaleurs comme ceci:int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
André

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

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

3

Échantillon très simple pour inclure ou exclure la date actuelle, vous spécifiez la date et le jour de la semaine qui vous intéresse.

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

quelques cas de 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
    }

J'ai apporté des modifications supplémentaires à la réponse d'origine après quelques tests approfondis. Cela calculera désormais en toute sécurité le jour suivant en fonction de la date utilisée, passée, présente et future. Tous les exemples précédents étaient excellents, mais ont échoué dans certaines conditions. Je n'en ai pas fait une déclaration unique, de sorte que des commentaires supplémentaires puissent être faits sur ce que font les calculs. Le cas positif de Jon Skeet était excellent, même si le cas que j'avais était de reculer d'un jour d'une date, mais toujours plus grand qu'aujourd'hui, et que se passe-t-il s'il passe à aujourd'hui ou à hier ... cela l'a résolu.
AJB

1

Ça pourrait être une extension aussi, tout dépend

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

Usage

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

0

Maintenant dans la saveur oneliner - au cas où vous auriez besoin de le passer comme paramètre dans un mécanisme.

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

Dans ce cas précis:

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

-5

Version Objectif C:

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

4
Réponse cool, mais la question originale posée sur .NET.
Adam Davis
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.