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.

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.


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


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

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

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.


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.


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

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

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

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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.