Pobierz daty pierwszego i ostatniego dnia poprzedniego miesiąca w języku C #

140

Nie mogę wymyślić łatwego jednego lub dwóch wkładek, które dostałyby poprzednie miesiące pierwszego i ostatniego dnia.

Jestem LINQ-ifying ankietową aplikację internetową i wycisnęli nowe wymaganie w.

Ankieta musi obejmować wszystkie zgłoszenia serwisowe z poprzedniego miesiąca. Więc jeśli jest 15 kwietnia, potrzebuję wszystkich identyfikatorów żądań Marchii.

var RequestIds = (from r in rdc.request 
                  where r.dteCreated >= LastMonthsFirstDate && 
                  r.dteCreated <= LastMonthsLastDate 
                  select r.intRequestId);

Po prostu nie mogę łatwo wymyślić dat bez przełącznika. Chyba że jestem ślepy i nie dostrzegam wewnętrznej metody robienia tego.

Jeremy Boyd
źródło

Odpowiedzi:

304
var today = DateTime.Today;
var month = new DateTime(today.Year, today.Month, 1);       
var first = month.AddMonths(-1);
var last = month.AddDays(-1);

Ustaw je szeregowo, jeśli naprawdę potrzebujesz jednej lub dwóch linii.

andleer
źródło
2
IIRC DateTime.Dzisiejsze wywołanie jest dość drogie, więc lepiej najpierw zapisz wartość w zmiennej. I tak dobra odpowiedź :)
Leandro López
2
@andleer, oto ładna biblioteka, która działa tak, jak wspomniałeś fluentdatetime.codeplex.com
Matthew Lock,
@MatthewLock, link wydaje się być uszkodzony.
Guillermo Gutiérrez
1
@ guillegr123 teraz na github github.com/FluentDateTime/FluentDateTime i Nuget nuget.org/packages/FluentDateTime
Matthew Lock
2
Chciałbym tylko zwrócić uwagę, że jeśli wpisy są przechowywane przy użyciu pełnej daty i godziny, to zapytanie może nie odzyskać żadnych, które rozpoczynają się po godzinie 00:00 ostatniego dnia miesiąca. Możesz rozwiązać ten problem, zmieniając ostatnią linię tak, aby czytała var last = month.AddTicks (-1);
SixOThree
23

Sposób, w jaki robiłem to w przeszłości, to pierwszy dzień tego miesiąca

dFirstDayOfThisMonth = DateTime.Today.AddDays( - ( DateTime.Today.Day - 1 ) );

Następnie odejmij dzień, aby otrzymać koniec ostatniego miesiąca

dLastDayOfLastMonth = dFirstDayOfThisMonth.AddDays (-1);

Następnie odejmij miesiąc, aby otrzymać pierwszy dzień poprzedniego miesiąca

dFirstDayOfLastMonth = dFirstDayOfThisMonth.AddMonths(-1);
MikeW
źródło
4
+1, ale żeby być pedantycznym, lepiej oceniaj DateTime, dziś raz i przechowuj w zmiennej lokalnej. Jeśli Twój kod zacznie się wykonywać nanosekundę przed północą, dwa kolejne wywołania funkcji DateTime.Today mogą zwrócić różne wartości.
Joe
Tak, dzięki, wszyscy się zgadzacie, nawet ten pedantyczny Naprawiono błąd.
MikeW
cóż, niech kompilator będzie dla Ciebie mniej pedantyczny :)
Maksym Gontar
1
przegłosowano, podobnie jak porównanie, return date.AddDays(-(date.Day-1))a return new DateTime(date.Year, date.Month, 1);wydajność pierwszych ponad 2000 iteracji jest lepsza (nowe 923 ms w porównaniu z 809 ms zwracaniem tego samego obiektu)
Terry_Brown
9
DateTime LastMonthLastDate = DateTime.Today.AddDays(0 - DateTime.Today.Day);
DateTime LastMonthFirstDate = LastMonthLastDate.AddDays(1 - LastMonthLastDate.Day);
Franci Penov
źródło
DateTime.Today.Days -> „System.DateTime” nie zawiera definicji „Days” ...
andleer
5

Używam tego prostego, jednowierszowego:

public static DateTime GetLastDayOfPreviousMonth(this DateTime date)
{
    return date.AddDays(-date.Day);
}

Miej świadomość, że zachowuje czas.


źródło
1
Właśnie tego chciałem, zwięzłego wyrażenia, którego mógłbym użyć wewnątrz trójskładnika. Dzięki!
Joe Ballard
4

Podejście wykorzystujące metody rozszerzające:

class Program
{
    static void Main(string[] args)
    {
        DateTime t = DateTime.Now;

        DateTime p = t.PreviousMonthFirstDay();
        Console.WriteLine( p.ToShortDateString() );

        p = t.PreviousMonthLastDay();
        Console.WriteLine( p.ToShortDateString() );


        Console.ReadKey();
    }
}


public static class Helpers
{
    public static DateTime PreviousMonthFirstDay( this DateTime currentDate )
    {
        DateTime d = currentDate.PreviousMonthLastDay();

        return new DateTime( d.Year, d.Month, 1 );
    }

    public static DateTime PreviousMonthLastDay( this DateTime currentDate )
    {
        return new DateTime( currentDate.Year, currentDate.Month, 1 ).AddDays( -1 );
    }
}

Zobacz ten link http://www.codeplex.com/fluentdatetime, aby uzyskać kilka inspirowanych rozszerzeń DateTime.

rp.
źródło
3

Kanoniczny przypadek użycia w handlu elektronicznym to daty ważności kart kredytowych, MM / rr. Odejmij jedną sekundę zamiast jednego dnia. W przeciwnym razie karta będzie wydawać się wygasła na cały ostatni dzień miesiąca wygaśnięcia.

DateTime expiration = DateTime.Parse("07/2013");
DateTime endOfTheMonthExpiration = new DateTime(
  expiration.Year, expiration.Month, 1).AddMonths(1).AddSeconds(-1);
MartinLeo
źródło
1

Jeśli jest jakakolwiek szansa, że ​​Twoje daty nie są ścisłymi datami kalendarzowymi, powinieneś rozważyć skorzystanie z porównań wykluczeń z dat końcowych ... Dzięki temu nie przegapisz żadnych żądań utworzonych w dniu 31 stycznia.

DateTime now = DateTime.Now;
DateTime thisMonth = new DateTime(now.Year, now.Month, 1);
DateTime lastMonth = thisMonth.AddMonths(-1);

var RequestIds = rdc.request
  .Where(r => lastMonth <= r.dteCreated)
  .Where(r => r.dteCreated < thisMonth)
  .Select(r => r.intRequestId);
Amy B.
źródło
1
DateTime now = DateTime.Now;
int prevMonth = now.AddMonths(-1).Month;
int year = now.AddMonths(-1).Year;
int daysInPrevMonth = DateTime.DaysInMonth(year, prevMonth);
DateTime firstDayPrevMonth = new DateTime(year, prevMonth, 1);
DateTime lastDayPrevMonth = new DateTime(year, prevMonth, daysInPrevMonth);
Console.WriteLine("{0} {1}", firstDayPrevMonth.ToShortDateString(),
  lastDayPrevMonth.ToShortDateString());
Maksym Gontar
źródło
1
Co się stanie, jeśli DateTime.Now zwróci 2009-01-31 w pierwszym wywołaniu i 2009-02-01 w drugim?
Amy B
1

Oto odpowiedź na odpowiedź Mike'a W.

internal static DateTime GetPreviousMonth(bool returnLastDayOfMonth)
{
    DateTime firstDayOfThisMonth = DateTime.Today.AddDays( - ( DateTime.Today.Day - 1 ) );
    DateTime lastDayOfLastMonth = firstDayOfThisMonth.AddDays (-1);
    if (returnLastDayOfMonth) return lastDayOfLastMonth;
    return firstDayOfThisMonth.AddMonths(-1);
}

Możesz to tak nazwać:

dateTimePickerFrom.Value = GetPreviousMonth(false);
dateTimePickerTo.Value = GetPreviousMonth(true);
B. Clay Shannon
źródło