Obter as datas do primeiro e último dia do mês anterior em c #

140

Não consigo pensar em uma linha fácil de uma ou duas que receba os meses anteriores no primeiro dia e no último dia.

Estou usando o LINQ para acessar um aplicativo da web de pesquisa e eles apertaram um novo requisito.

A pesquisa deve incluir todas as solicitações de serviço do mês anterior. Portanto, se for 15 de abril, preciso de todos os IDs de solicitação do Marches.

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

Eu simplesmente não consigo pensar nas datas facilmente sem mudar. A menos que eu seja cego e negligencie um método interno de fazê-lo.

Jeremy Boyd
fonte

Respostas:

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

Alinhe-os se você realmente precisar de uma ou duas linhas.

andleer
fonte
2
O IIRC DateTime.Today é uma chamada bastante cara, portanto é melhor armazenar primeiro o valor em uma variável. Boa resposta de qualquer maneira :)
Leandro López
2
@andleer aqui está uma biblioteca agradável que funciona como você mencionou fluentdatetime.codeplex.com
Matthew Bloqueio
@MatthewLock, o link parece estar quebrado.
Guillermo Gutiérrez
1
@ guillegr123 agora no github github.com/FluentDateTime/FluentDateTime e Nuget nuget.org/packages/FluentDateTime
Matthew Bloqueio
2
Gostaria apenas de salientar que, se as entradas forem armazenadas usando uma data / hora completa, essa consulta poderá não recuperar nenhuma que inicie após as 12:00 no último dia do mês. Você pode resolver isso alterando a última linha para ler var last = month.AddTicks (-1);
SixOThree
23

A maneira como eu fiz isso no passado é primeiro no primeiro dia deste mês

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

Subtraia um dia para terminar o mês passado

dLastDayOfLastMonth = dFirstDayOfThisMonth.AddDays (-1);

Subtraia um mês para obter o primeiro dia do mês anterior

dFirstDayOfLastMonth = dFirstDayOfThisMonth.AddMonths(-1);
MikeW
fonte
4
+1, mas, para ser pedante, é melhor avaliar o DateTime.Hoje e armazenar uma variável local. Se o seu código começar a executar um nanossegundo antes da meia-noite, duas chamadas consecutivas para DateTime.Today poderão retornar valores diferentes.
2626 Joe
Sim, obrigado, todos vocês corrigem, até o pedante Corrigiu o erro.
26909 MikeW
bem deixe o compilador ser menos pedante para você :)
Maksym Gontar
1
upvoted como foi comparar return date.AddDays(-(date.Day-1))contra return new DateTime(date.Year, date.Month, 1);e o desempenho dos primeiros mais de 2000 iterações é melhor (923ms 809ms newing-se contra o retorno do mesmo objecto)
Terry_Brown
9
DateTime LastMonthLastDate = DateTime.Today.AddDays(0 - DateTime.Today.Day);
DateTime LastMonthFirstDate = LastMonthLastDate.AddDays(1 - LastMonthLastDate.Day);
Franci Penov
fonte
DateTime.Today.Days -> 'System.DateTime' não contém uma definição para 'Days' ...
andleer
5

Eu uso este simples liner:

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

Esteja ciente de que isso retém o tempo.


fonte
1
Exatamente o que eu queria, expressão concisa que eu pudesse usar dentro de um ternário. Obrigado!
Joe Ballard
4

Uma abordagem usando métodos de extensão:

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

Consulte este link http://www.codeplex.com/fluentdatetime para obter algumas extensões inspiradas do DateTime.

rp.
fonte
3

O caso de uso canônico no comércio eletrônico são as datas de vencimento dos cartões de crédito, MM / aa. Subtraia um segundo em vez de um dia. Caso contrário, o cartão aparecerá expirado durante todo o último dia do mês de vencimento.

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

Se houver alguma chance de que suas datas não sejam datas de calendário estritas, considere usar comparações de exclusão de datas finais ... Isso impedirá que você perca as solicitações criadas durante a data de 31 de janeiro.

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
fonte
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
fonte
1
E se o DateTime.Now produzir 31/01/2009 na primeira chamada e 01/02/2009 na segunda chamada?
217 Amy B
1

Esta é uma resposta à resposta de 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);
}

Você pode chamar assim:

dateTimePickerFrom.Value = GetPreviousMonth(false);
dateTimePickerTo.Value = GetPreviousMonth(true);
B. Clay Shannon
fonte