2009-03-08 3 views

Antwort

12

Kann nicht ein handliches Einzeiler finden, aber diese funktioniert:

static DateTime LastDayOfWeekInMonth(DateTime day, DayOfWeek dow) 
{ 
    DateTime lastDay = new DateTime(day.Year, day.Month, 1).AddMonths(1).AddDays(-1); 
    DayOfWeek lastDow = lastDay.DayOfWeek; 

    int diff = dow - lastDow; 

    if (diff > 0) diff -= 7; 

    System.Diagnostics.Debug.Assert(diff <= 0); 

    return lastDay.AddDays(diff); 
} 
+0

Gefällt mir, danke Henk. Kleiner Punkt - Sie könnten die letzte .AddDays (-1) entfernen und "if (diff> 0)" in "if (diff> = 0)" ändern - also 1 datetime.addDays-Operation entfernen. – Ryan

+1

Ryan, ja, es spart 1 op, aber es grenzt an, was der Compiler optimieren kann. Und konzeptionell "letzter Tag des Monats" ist für den Verstand einfacher als "erster Tag des nächsten Monats". Normalerweise würde ich das nicht optimieren. –

6

Erhalten Sie den ersten Tag im nächsten Monat, dann finden Sie den ersten mathing Wochentag in diesem Monat. Gehen Sie 7 Tage zurück, und Sie sind an diesem Tag in der letzten Woche des corrent Monat:

DateTime date = new DateTime(2009, 3, 12); 
DayOfWeek day = DayOfWeek.Sunday; 

DateTime nextMonth = new DateTime(date.Year, date.Month, 1).AddMonths(1); 
while (nextMonth.DayOfWeek != day) { 
    nextMonth = nextMonth.AddDays(1); 
} 
DateTime lastInMonth = nextMonth.AddDays(-7); 

(Sie könnten die Schleife mit einigen arithmetischen ersetzen, die die Anzahl der Tage berechnet basierend auf den numerischen Werten der hinzufügen DayOfWeek Werte, aber das ist einfacher.

Edit:
Sie könnten natürlich auch den letzten Tag im aktuellen Monat bekommen, dann Schleife rückwärts, bis Sie den richtigen Wochentag finden.

+0

@Guffa, danke für den Fang. Ich wollte nur als erster antworten, also war meine Logik gut. –

11

http://datetimeextensions.codeplex.com/ hat eine Last (dayOfWeek) Extension-Methode, die dies tun wird für Sie

-Test enthalten :-)

+0

Clever Implementierung und eine Erweiterung wäre süß. Ich würde es jedoch in etwas Sittenspezifisches umbenennen. Es könnte Date.LastDayOfWeekForMonth Date.LastDayOfWeekForYear oder Date.LastDayOfWeekCentury Date.LastDayOfWeekForMillenium –

+0

Große Bibliothek, danke TFD! Leider kann ich es nicht so verwenden wie es ist, weil ich .NET 2.0 angeredet habe, also habe ich Henks Antwort markiert, aber Sie haben trotzdem eine Menge Upvotes dafür. – Ryan

+0

Test fehlgeschlagen, DateTime dt = DateTime.Today.AddMonths (1) .Last (DayOfWeek.Thursday); Assert.AreEqual (neue DateTime (2012, 4, 26), dt); – Vincent

1

Try this: am letzten Tag starten und zurück rechnen, bis Sie den Tag treffen Sie suchen

static DateTime LastOccurenceOfDay(DateTime dt, DayOfWeek dow) 
    { 
     DateTime looperDate = new DateTime(dt.Year, dt.Month, 1) 
            .AddMonths(1).AddDays(-1); 
     while (looperDate.DayOfWeek!=dow)        
      looperDate =looperDate.AddDays(-1);    
     return looperDate; 

Bearbeiten: Wiederhergestellt die alte Version Dangph bezieht sich auf in den Kommentaren.

static DateTime LastOccurenceOfDay(DateTime dt, DayOfWeek dow) 
    { 
     //set start of loop 
     DateTime looperDate = new DateTime(dt.Year, dt.Month, 1); 
     //initialze return value 
     DateTime returnDate = dt; 
     //loop until the month is over 
     while (looperDate.Month == dt.Month) 
     { 
      //if the current DayOfWeek is the date you're looking for 
      if (looperDate.DayOfWeek == dow) 
       //remember it. 
       returnDate = looperDate; 
      //increase day 
      looperDate=looperDate.AddDays(1); 
     } 
     return returnDate; 
    } 
+0

Das ist deine Definition von einfach? –

+0

Ja, wenn Sie eine bessere Idee haben, wo ist Ihre Antwort? – Sorskoot

+0

Ich mochte deine erste Version mehr. Über dieses ist schwerer nachzudenken.Und ich bezweifle stark, dass es einen nachweisbaren Leistungsgewinn haben könnte, wenn Sie nicht eine Unmenge dieser Berechnungen machen würden. Ich wollte in der alten Version vorschlagen, dass du einfach 7 Tage auf einmal hinzufügen kannst, um es einfacher zu machen. –

4
static DateTime LastDateOfWeekForMonth(DayOfWeek weekday, int month, int year) 
{ 
    DateTime d = new DateTime(year, month, 1).AddMonths(1); 
    while (!(d.DayOfWeek == weekday && d.Month == month)) 
    { 
     d = d.AddDays(-1); 
    } 
    return d; 
} 
+0

Warum der Downvote auf diesem? Ich habe das "!" im! –

+0

Ich rate den Downvote ist, weil die Verwendung einer Schleife für so etwas ist wahrscheinlich nicht optimal - aber zumindest beginnen Sie am Ende des Monats und arbeiten rückwärts so maximal 6 Iterationen. – Ryan

+0

Um zu optimieren, wenn dayweekek> Mittwoch, mach es @ Guffa Weg, sonst meins :) –

1
public DateTime GetLastDayOfMonth(int year, int month, DayOfWeek dayOfWeek) 
    { 
     var daysInMonth = DateTime.DaysInMonth(year, month); 
     var lastDay = new DateTime(year, month, daysInMonth); 

     while (lastDay.DayOfWeek != dayOfWeek) 
     { 
      lastDay = lastDay.AddDays(-1); 
     } 

     return lastDay; 
    } 
0
static DateTime GetDayOfWeekInMonthFromWeekIndex(this DateTime date, DayOfWeek dow, int weekIndex) 
{ 
    if (weekIndex > 4) 
     return LastDayOfWeekInMonth(date, dow); 

    DateTime newDate = new DateTime(date.Year, date.Month, 1); 
    DayOfWeek newDow = newDate.DayOfWeek; 
    int diff = dow - newDow; 
    diff += ((weekIndex - 1) * 7); 
    return newDate.AddDays(diff); 
} 
1

Hier ist sowohl LastDayOfMonth() und LastDayOfMonth (DayOfWeek) und Unit-Tests, die von der "Last Freitag" Umsetzung in How to find the 3rd Friday in a month with C#? von @ Paul Fryer inspiriert wurden:

/** 
    /// <summary>An extension method that returns the last day of the month.</summary> 
    /// <param name="d">A date within the month to calculate.</param> 
    /// <returns>The last day of the current month.</returns> 
    **/ 
    public static DateTime LastDayOfMonth(this DateTime d) 
    { 
     DateTime nextMonth = new DateTime(d.Year, d.Month, 1).AddMonths(1); 
     return nextMonth.AddDays(-1); 
    } 

    /** 
    /// <summary>An extension method that returns the last <see cref="DayOfWeek"> of the month.</summary> 
    /// <param name="d">A date within the month to calculate.</param> 
    /// <returns>The last day of the current month.</returns> 
    **/ 
    public static DateTime LastDayOfMonth(this DateTime d, DayOfWeek dayOfWeek) 
    { 
     DateTime lastDayOfMonth = d.LastDayOfMonth(); 
     int vector = (((int)lastDayOfMonth.DayOfWeek - (int)dayOfWeek + DaysInWeek) % DaysInWeek); 
     return lastDayOfMonth.AddDays(-vector); 
    } 

#region LastDayOfMonth Tests 

    [TestCase("1/1/2011", "1/31/2011")] 
    [TestCase("2/1/2009", "2/28/2009")] //Leap Year 
    [TestCase("2/1/2008", "2/29/2008")] //Leap Year 
    [TestCase("3/10/2011", "3/31/2011")] 
    [TestCase("4/20/2011", "4/30/2011")] 
    [TestCase("5/15/2011", "5/31/2011")] 
    [TestCase("6/30/2011", "6/30/2011")] 
    [TestCase("12/1/2011", "12/31/2011")] 
    public void LastDayOfMonthReturnsCorrectDay(string startingDate, string expectedDate) 
    { 
     //Arrange 
     DateTime testDate = DateTime.Parse(startingDate); 
     DateTime expected = DateTime.Parse(expectedDate); 

     //Act 
     DateTime actual = testDate.LastDayOfMonth(); 

     //Assert 
     Assert.That(actual, Is.EqualTo(expected)); 
    } 

    [TestCase("1/1/2011", DayOfWeek.Monday, "1/31/2011")] 
    [TestCase("2/1/2009", DayOfWeek.Saturday, "2/28/2009")] 
    [TestCase("2/1/2009", DayOfWeek.Sunday, "2/22/2009")] 
    [TestCase("2/1/2008", DayOfWeek.Friday, "2/29/2008")] //Leap Year 
    [TestCase("2/1/2008", DayOfWeek.Thursday, "2/28/2008")] //Leap Year 
    [TestCase("3/10/2011", DayOfWeek.Wednesday, "3/30/2011")] 
    [TestCase("4/20/2011", DayOfWeek.Friday, "4/29/2011")] 
    [TestCase("4/20/2011", DayOfWeek.Saturday, "4/30/2011")] 
    [TestCase("5/15/2011", DayOfWeek.Tuesday, "5/31/2011")] 
    [TestCase("5/15/2011", DayOfWeek.Saturday, "5/28/2011")] 
    [TestCase("9/30/2011", DayOfWeek.Sunday, "9/25/2011")] 
    [TestCase("12/1/2011", DayOfWeek.Monday, "12/26/2011")] 
    public void LastDayOfMonthReturnsCorrectDayOfWeek(string startingDate, DayOfWeek dayOfWeek, string expectedDate) 
    { 
     //Arrange 
     DateTime testDate = DateTime.Parse(startingDate); 
     DateTime expected = DateTime.Parse(expectedDate); 

     //Act 
     DateTime actual = testDate.LastDayOfMonth(dayOfWeek); 

     //Assert 
     Assert.That(actual, Is.EqualTo(expected)); 
    }  

    #endregion