13

Is there a C# function which will give me the last day of the most recently finished Quarter given a date?

For example,

var lastDayOfLastQuarter = SomeFunction(jan 3, 2010);

would set lastDayOfLastQuarter = Dec 31, 2009

skaffman
  • 381,978
  • 94
  • 789
  • 754
Ian Vink
  • 60,720
  • 99
  • 311
  • 535
  • You'd need to be able to define when your quarter starts and ends. – Paddy Dec 22 '09 at 15:46
  • 2
    Oh, that one is probably just a special case of the `DoMagic()` method which miraculously works out what you want in any context :-). Seriously, there is no such method in the base class library but you can surely write your own. – Joey Dec 22 '09 at 15:48

7 Answers7

29
public static DateTime NearestQuarterEnd(this DateTime date) {
    IEnumerable<DateTime> candidates = 
        QuartersInYear(date.Year).Union(QuartersInYear(date.Year - 1));
    return candidates.Where(d => d < date.Date).OrderBy(d => d).Last();
}

static IEnumerable<DateTime> QuartersInYear(int year) {
    return new List<DateTime>() {
        new DateTime(year, 3, 31),
        new DateTime(year, 6, 30),
        new DateTime(year, 9, 30),
        new DateTime(year, 12, 31),
    };
}

Usage:

DateTime date = new DateTime(2010, 1, 3);
DateTime quarterEnd = date.NearestQuarterEnd();

This method has the advantage in that if you have an odd definition of quarters (for example, fiscal year is different than calendar year) the method QuartersInYear is easily modified to handle this.

Rad
  • 8,221
  • 4
  • 43
  • 44
jason
  • 220,745
  • 31
  • 400
  • 507
  • 3
    +1 - Simple, extensible, easy to verify and understand. Love it. – LBushkin Dec 22 '09 at 16:08
  • 1
    Beware that this method will assume the quarter has ended when you pass in the last day, that is, new DateTime(2012, 9, 30) will return "2012-09-30", although one could argue that on the last date, the quarter has not yet ended. Also, the method name is slightly misleading, as it will return the latest quarter, not the nearest if that is in the future. – R. Schreurs Sep 14 '12 at 16:09
  • Like the clever use of LINQ so +1 for that but doesn't it seem a little inefficient to anyone considering that this can be done without setting up datasets and using LINQ to search through them? See answer by @Greg. – Ryan Jul 16 '13 at 17:42
  • static IEnumerable QuartersStarts(int year) { return new List() { new DateTime(year, 1, 1), new DateTime(year, 3, 1), new DateTime(year, 6, 1), new DateTime(year, 10, 1), }; } public static DateTime NearestQuarterStart(this DateTime date) { IEnumerable candidates = QuartersStarts(date.Year).Union(QuartersStarts(date.Year - 1)); return candidates.Where(d => d <= NearestQuarterEnd(date)).OrderBy(d => d).Last(); } – Boris Gappov Feb 10 '14 at 14:01
  • public static DateTime QuarterStart(this DateTime date) { IEnumerable candidates = QuartersStarts(date.Year); return candidates.Where(d => d <= date).OrderBy(d => d).Last(); } public static DateTime QuarterEnd(this DateTime date) { IEnumerable candidates = QuartersEnds(date.Year); return candidates.Where(d => d >= date).OrderBy(d => d).First(); } – Boris Gappov Feb 10 '14 at 14:01
  • Given that the method should return the end of the last quarter, returning 30 sep 2015 given a date of 30 sep 2015 is not correct. Change the bit return candidates.Where(d => d <= date).OrderBy(d => d).Last(); to return candidates.Where(d => d < date).OrderBy(d => d).Last(); – Rad Mar 31 '15 at 08:34
3

Try this:
The AddMonths(-(d.Month-1) % 3)) moves the datevalue to the equivilent day of the first month in the quarter, and then the AddDays (-day) moves back to the last day of the preceding month.

  DateTime d = Datetime.Now;
  DateTime lastDayOfLastQuarter = d.AddMonths(-((d.Month-1)%3)).AddDays(-d.Day);
Charles Bretana
  • 131,932
  • 22
  • 140
  • 207
  • This fails for, say, `Day = 1`, `Month = 12`, `Year = 2009`. – jason Dec 22 '09 at 15:59
  • because month property is 1-12, (not 0-11 as I thought), corrected now – Charles Bretana Dec 22 '09 at 16:01
  • Okay, I think that works. Downvote removed. However, the disadvantage of this method is that is heavily dependent on quarters being defined as the last days of the third, sixth, ninth and twelfth months of the year. If a different definition is used this method is not easily adaptable to that (companies move their financial statement reporting dates more often than you might think). – jason Dec 22 '09 at 16:06
  • 1
    This is first I've EVER heard of "redefining quarters differently than standard calendar quarter 1-3, 4-6, 7-9, 10-12. But I just did some research and saw that for estimated taxes some C-Corps ar allowed to use 1-3, 4-5, 6-8, and 9-12... very interesting... – Charles Bretana Dec 22 '09 at 16:12
  • 1
    But if this odd pattern is in use, then any function to dop what OP asked would have to be passed info on how quarters were redefined... A different problem entirely from what OP asked. (He specofies standard quarters) – Charles Bretana Dec 22 '09 at 16:15
  • I think Cisco is an example of a company with their quarters ending in the first, fourth, seventh and tenth months of the years. – jason Dec 22 '09 at 16:21
  • they're probably aligned with FY, at least they're still all three months long.. The examples I found are 2 and 4 months long "quarters" to adjust for varying expected revenue streams during the year, to adjust I assume to keep the "monetary revenue" size of the quarters balaanced... – Charles Bretana Dec 22 '09 at 16:46
  • Yes, that will happen for companies with seasonal cash flows. – jason Dec 22 '09 at 20:00
2

Assuming quarters always end at 3 month intervals you could do:

Maybe not the best solution, but very easy to read and modify compared to other solutions offered.

public DateTime LastDayOfLastQuarter(DateTime date)
{
    int result = (int)(date.Month/3)

    switch (result)
    {
        // January - March
        case 0:
            return new DateTime(date.Year - 1, 12, 31);
        // April - June
        case 1:
            return new DateTime(date.Year, 3, 31);
        // July - September
        case 2:
            return new DateTime(date.Year, 6, 30);
        // October - December
        case 3:
            return new DateTime(date.Year, 9, 30);
    }
}
Brett Allen
  • 4,877
  • 5
  • 27
  • 60
  • 1
    Many errors in this code: 1. missing semi-colons on each statement; 2. return type should be DateTime i.s.o. void; 3. missing a default case, with default compiler settings, you'll get "not all code paths return a value". – R. Schreurs Sep 14 '12 at 15:38
  • @R.Schreurs, fixed all but the compiler warning for ya. What exactly would you suggest for a return that should logically never be executed? – Brett Allen Sep 14 '12 at 15:50
  • 1
    I would throw an exception in such a case: default: throw new ApplicationException(string.Format("{0} is not a valid number for a quarter.", result)); The compiler will be happy, and your code is clear about what it accepts as valid. Still missing 1 semicolon... just out of curiosity, why don't you write your code in VS.Net and just compile it before posting it here? Anyone looking for this function would be glad if it could just be copied and pasted and not need debugging. – R. Schreurs Sep 17 '12 at 20:38
  • Two final comments on this: 1. I modified the expression to get the quarter number to become (int)((date.Month - 1) / 3). Otherwise, any day in march will already give year-03-31. The last day of a quarter will also yield the last day of a quarter before, if that is undesired, a day must be added like this: (int)((date.AddDays(1).Month - 1) / 3). 2. I took the trouble of debugging this, because I like it for the reasons you stated: "very easy to read and modify". – R. Schreurs Sep 18 '12 at 13:17
2

A simple function can calculate the last days of the most recently completed month:

public static DateTime LastQuarter(DateTime date)
{
    return new DateTime(date.Year, date.Month - ((date.Month - 1) % 3), 1).AddDays(-1);
}
Greg
  • 21,917
  • 11
  • 55
  • 77
1

Here's a simple function to give you the last day of the current quarter (assuming you're using a standard calendar).

DateTime LastDayOfQuarter(DateTime today)
{
    int quarter = (today.Month-1) / 3;
    int lastMonthInQuarter = (quarter +1) * 3;
    int lastDayInMonth =  DateTime.DaysInMonth(today.Year, lastMonthInQuarter);
    return new DateTime(today.Year, lastMonthInQuarter, lastDayInMonth); 
}

Hope that helps.

Tom Hazel
  • 2,932
  • 2
  • 17
  • 20
1
Func<int, int> q = (i) => { return ((i - 1) / 3) + 1; };

Test:

Enumerable.Range(1, 12).Select(i => q(i));
abatishchev
  • 92,232
  • 78
  • 284
  • 421
0

You can use a simple switch statement to check which quarter the given date falls and return the last day of that quarter.

GraphicsMuncher
  • 4,269
  • 3
  • 30
  • 48