169

I can't think of an easy one or two liner that would get the previous months first day and last day.

I am LINQ-ifying a survey web app, and they squeezed a new requirement in.

The survey must include all of the service requests for the previous month. So if it is April 15th, I need all of Marches request ids.

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

I just can't think of the dates easily without a switch. Unless I'm blind and overlooking an internal method of doing it.

Jeremy Boyd
  • 5,245
  • 7
  • 33
  • 57

11 Answers11

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

In-line them if you really need one or two lines.

andleer
  • 22,388
  • 8
  • 62
  • 82
  • 2
    IIRC DateTime.Today is a quite expensive call, so you better store the value in a variable first. Good answer anyway :) – Leandro López Feb 26 '09 at 19:26
  • 2
    @andleer here's a nice library which works like you mentioned http://fluentdatetime.codeplex.com/ – Matthew Lock Jun 01 '12 at 01:31
  • @MatthewLock, the link seems to be broken. – Guillermo Gutiérrez Feb 13 '13 at 20:46
  • 1
    @guillegr123 now at github https://github.com/FluentDateTime/FluentDateTime and Nuget http://nuget.org/packages/FluentDateTime – Matthew Lock Feb 13 '13 at 23:32
  • 2
    I would just like to point out that if entries are stored using a a full datetime this query may fail to retrieve any that start after 12:00 AM on the last day of the month. You could solve this by changing the last line to read var last = month.AddTicks(-1); – SixOThree Dec 22 '14 at 22:12
29

The way I've done this in the past is first get the first day of this month

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

Then subtract a day to get end of last month

dLastDayOfLastMonth = dFirstDayOfThisMonth.AddDays (-1);

Then subtract a month to get first day of previous month

dFirstDayOfLastMonth = dFirstDayOfThisMonth.AddMonths(-1);
MikeW
  • 5,702
  • 1
  • 35
  • 43
  • 4
    +1, but to be pedantic, you're better evaluating DateTime.Today once and storing in a local variable. If your code starts executing a nanosecond before midnight, two consecutive calls to DateTime.Today could return different values. – Joe Feb 26 '09 at 18:36
  • Yes, thanks, all of you correct, even the pedantic one Fixed the error. – MikeW Feb 26 '09 at 19:24
  • well let the compiler be less pedantic to you :) – Maksym Gontar Feb 26 '09 at 20:17
  • 1
    upvoted as was comparing `return date.AddDays(-(date.Day-1))` versus `return new DateTime(date.Year, date.Month, 1);` and the performance of the first over 2000 iterations is better (923ms newing up versus 809ms returning the same object) – Terry_Brown Apr 02 '12 at 10:28
13

using Fluent DateTime https://github.com/FluentDateTime/FluentDateTime

        var lastMonth = 1.Months().Ago().Date;
        var firstDayOfMonth = lastMonth.FirstDayOfMonth();
        var lastDayOfMonth = lastMonth.LastDayOfMonth();
shriek
  • 5,157
  • 2
  • 36
  • 42
Simon
  • 33,714
  • 21
  • 133
  • 202
11
DateTime LastMonthLastDate = DateTime.Today.AddDays(0 - DateTime.Today.Day);
DateTime LastMonthFirstDate = LastMonthLastDate.AddDays(1 - LastMonthLastDate.Day);
Franci Penov
  • 74,861
  • 18
  • 132
  • 169
6

I use this simple one-liner:

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

Be aware, that it retains the time.

4

The canonical use case in e-commerce is credit card expiration dates, MM/yy. Subtract one second instead of one day. Otherwise the card will appear expired for the entire last day of the expiration month.

DateTime expiration = DateTime.Parse("07/2013");
DateTime endOfTheMonthExpiration = new DateTime(
  expiration.Year, expiration.Month, 1).AddMonths(1).AddSeconds(-1);
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
MartinLeo
  • 41
  • 2
4

An approach using extension methods:

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

See this link http://www.codeplex.com/fluentdatetime for some inspired DateTime extensions.

Alex Essilfie
  • 12,339
  • 9
  • 70
  • 108
rp.
  • 17,483
  • 12
  • 63
  • 79
1

This is a take on Mike W's answer:

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

You can call it like so:

dateTimePickerFrom.Value = GetPreviousMonth(false);
dateTimePickerTo.Value = GetPreviousMonth(true);
B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
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
  • 22,765
  • 10
  • 78
  • 114
  • 1
    What if DateTime.Now yields 2009-01-31 on the first call and 2009-02-01 on the second call? – Amy B Feb 26 '09 at 18:42
1

If there's any chance that your datetimes aren't strict calendar dates, you should consider using enddate exclusion comparisons... This will prevent you from missing any requests created during the date of Jan 31.

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
  • 108,202
  • 21
  • 135
  • 185
1
var lastMonth = DateTime.Today.AddMonths(-1);
dRet1 = new DateTime(lastMonth.Year, lastMonth.Month, 1);
dRet2 = new DateTime(lastMonth.Year, lastMonth.Month, DateTime.DaysInMonth(lastMonth.Year, lastMonth.Month));
Ahmed Elzeiny
  • 67
  • 1
  • 3