Ottieni le date del primo e dell'ultimo giorno del mese precedente in c #


140

Non riesco a pensare a uno o due liner facili che otterrebbero i mesi precedenti il ​​primo e l'ultimo giorno.

Sono LINQ-ifying un'app Web di sondaggio e hanno soddisfatto un nuovo requisito.

Il sondaggio deve includere tutte le richieste di servizio per il mese precedente. Quindi, se è il 15 aprile, ho bisogno di tutti gli ID di richiesta per le Marche.

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

Non riesco a pensare facilmente alle date senza un cambio. A meno che non sia cieco e trascuri un metodo interno per farlo.

Risposte:


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

In linea, se hai davvero bisogno di una o due linee.


2
IIRC DateTime.Today è una chiamata piuttosto costosa, quindi è meglio memorizzare prima il valore in una variabile. Buona risposta comunque :)
Leandro López,

2
@andleer ecco una bella libreria che funziona come hai detto fluentdatetime.codeplex.com
Matthew Lock,

@MatthewLock, il collegamento sembra essere rotto.
Guillermo Gutiérrez,


2
Vorrei solo sottolineare che se le voci vengono archiviate utilizzando un datetime completo, questa query potrebbe non riuscire a recuperare quelle che iniziano dopo le 12:00 dell'ultimo giorno del mese. È possibile risolvere questo problema modificando l'ultima riga per leggere var last = month.AddTicks (-1);
SixOThree

23

Il modo in cui l'ho fatto in passato è il primo giorno di questo mese

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

Quindi sottrarre un giorno per ottenere la fine del mese scorso

dLastDayOfLastMonth = dFirstDayOfThisMonth.AddDays (-1);

Quindi sottrarre un mese per ottenere il primo giorno del mese precedente

dFirstDayOfLastMonth = dFirstDayOfThisMonth.AddMonths(-1);

4
+1, ma per essere pedanti, è meglio valutare DateTime. Oggi una volta e archiviare in una variabile locale. Se il codice inizia a eseguire un nanosecondo prima di mezzanotte, due chiamate consecutive a DateTime. Oggi potrebbero restituire valori diversi.
Joe,

Sì, grazie, tutti voi avete corretto, anche quello pedante Risolto l'errore.
MikeW,

bene lascia che il compilatore sia meno pedante per te :)
Maksym Gontar,

1
valutato come lo era il confronto return date.AddDays(-(date.Day-1))rispetto a return new DateTime(date.Year, date.Month, 1);e le prestazioni delle prime oltre 2000 iterazioni sono migliori (923 ms di aggiornamento rispetto a 809 ms che restituiscono lo stesso oggetto)
Terry_Brown


9
DateTime LastMonthLastDate = DateTime.Today.AddDays(0 - DateTime.Today.Day);
DateTime LastMonthFirstDate = LastMonthLastDate.AddDays(1 - LastMonthLastDate.Day);

DateTime.Today.Days -> 'System.DateTime' non contiene una definizione per 'Days' ...
andleer

5

Uso questo semplice one-liner:

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

Essere consapevoli del fatto che mantiene il tempo.


1
Proprio quello che volevo, espressione concisa che avrei potuto usare all'interno di un ternario. Grazie!
Joe Ballard,

4

Un approccio che utilizza metodi di estensione:

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

Vedi questo link http://www.codeplex.com/fluentdatetime per alcune estensioni DateTime ispirate.


3

Il caso d'uso canonico nell'e-commerce sono le date di scadenza della carta di credito, MM / AA. Sottrai un secondo invece di un giorno. Altrimenti la carta apparirà scaduta per l'intero ultimo giorno del mese di scadenza.

DateTime expiration = DateTime.Parse("07/2013");
DateTime endOfTheMonthExpiration = new DateTime(
  expiration.Year, expiration.Month, 1).AddMonths(1).AddSeconds(-1);

1

Se c'è qualche possibilità che i tuoi periodi di tempo non siano date di calendario rigorose, dovresti prendere in considerazione l'utilizzo di confronti di esclusione di fine periodo ... Questo ti impedirà di perdere qualsiasi richiesta creata durante la data del 31 gennaio.

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
Che cosa succede se DateTime.Now produce il 2009-01-31 alla prima chiamata e il 2009-02-01 alla seconda chiamata?
Amy B,

1

Questa è una versione della risposta di Mike 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);
}

Puoi chiamarlo così:

dateTimePickerFrom.Value = GetPreviousMonth(false);
dateTimePickerTo.Value = GetPreviousMonth(true);
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.