1

Given a DateTime object, i'd like to know which day of it's respective quarter it is.

E.g. 2 Feb is 33rd day of 1st quarter.

I can get the quarter from the month like so: (int)System.Math.Ceiling(month / (double)3)

I can also use DateTime.DaysInMonth() to find out how many days were in each of the quarters.

I wrote this particularly unsightly method, was hoping someone can point me to (something obvious) i am sure i am missing.

public static int DayOfQuarter(DateTime dt)
        {
            var quarter = GetQuarter(dt);

            int[] months = new int[0];
            switch (quarter)
            {
                case 1:
                    months = new[] { 1, 2, 3 };
                    break;
                case 2:
                    months = new[] { 4, 5, 6 };
                    break;
                case 3:
                    months = new[] { 7, 8, 9 };
                    break;
                case 4:
                    months = new[] { 10, 11, 12 };
                    break;
            }

            var idx = -1;
            for (var i = 0; i < months.Length; i++)
            {
                if (months[i] == dt.Month)
                {
                    idx = i;
                }
            }

            if (idx == 0)
            {
                return dt.Day;
            }

            if (idx == 1)
            {
                return DateTime.DaysInMonth(dt.Year, dt.Month - 1) + dt.Day;
            }

            return DateTime.DaysInMonth(dt.Year, dt.Month - 2) + DateTime.DaysInMonth(dt.Year, dt.Month - 1) + dt.Day;
        }
zaitsman
  • 8,984
  • 6
  • 47
  • 79
  • Combine [Calculate the start-date and name of a quarter from a given date](//stackoverflow.com/q/1492079) and [Calculate difference between two dates (number of days)?](//stackoverflow.com/q/1607336) – Heretic Monkey May 06 '18 at 13:48
  • 4
    dt.DayOfYear - new DateTime(dt.Year, 1 + 3 * ((dt.Month-1) / 3), 1).DayOfYear – Hans Passant May 06 '18 at 13:49
  • Possible duplicate of [How do i discover the quarter of a given date](https://stackoverflow.com/questions/8698303/how-do-i-discover-the-quarter-of-a-given-date) – codebender May 06 '18 at 14:35

1 Answers1

5

Yes, I think we can make this simpler, using the DayOfYear property. You just need to be able to work out the start of the quarter, then you can take that date's day-of-year from the specified date's day-of-year.

public static int DayOfQuarter(DateTime dt)
{
    int zeroBasedQuarter = (dt.Month - 1) / 3;
    DateTime startOfQuarter = new DateTime(dt.Year, zeroBasedQuarter * 3 + 1, 1);
    return dt.DayOfYear - startOfQuarter.DayOfYear + 1;
}

Here's a short but complete test app:

using System;

public class Program
{
    static void Main()
    {
        var dates = new[]
        {
            new DateTime(2000, 1, 1),
            new DateTime(2001, 1, 1),
            new DateTime(2000, 3, 1),
            new DateTime(2001, 3, 1),
            new DateTime(2000, 4, 1),
            new DateTime(2001, 4, 1),
            new DateTime(2000, 5, 1),
            new DateTime(2001, 5, 1),
            new DateTime(2000, 12, 31),
            new DateTime(2001, 12, 31),
        };
        foreach (var date in dates)
        {
            int dayOfQuarter = DayOfQuarter(date);
            Console.WriteLine($"{date:yyyy-MM-dd}: {dayOfQuarter}");
        }
    }

    public static int DayOfQuarter(DateTime dt)
    {
        int zeroBasedQuarter = (dt.Month - 1) / 3;
        DateTime startOfQuarter = new DateTime(dt.Year, zeroBasedQuarter * 3 + 1, 1);
        return dt.DayOfYear - startOfQuarter.DayOfYear + 1;
    }
}

Output:

2000-01-01: 1
2001-01-01: 1
2000-03-01: 61
2001-03-01: 60
2000-04-01: 1
2001-04-01: 1
2000-05-01: 31
2001-05-01: 31
2000-12-31: 92
2001-12-31: 92

Note the third and fourth lines, showing that it's doing the right thing with leap years (where the day-of-quarter of March 1st is one greater in leap years).

I'd also suggest avoiding floating point for your GetQuarter method - it's unnecessary:

public static int GetQuarter(DateTime dt) => (dt.Month - 1) / 3 + 1;
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194