Ryan
Ryan

Reputation: 24482

Calculate the start date of a Financial Quarter a date is in

Assume Financial Quarters always start on the 1st of a month and they are always 3 calendar months long.

Different organisations start their Financial Year (FY) in different months - some may be 1st April , some may be 1st July or could be just 1st Jan (which will match normal Calendar Quarters).

Given a date and a month that the FY starts on how can you determine the start of the quarter that the date falls in.

E.g.

DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)

15th Jan when FY starts Jan would = 1st Jan

getStartOfFinancialQtr(new DateTime(2013,1,15), 1) == new DateTime(2013,1,1)

15th August when FY starts April would be 1st July

getStartOfFinancialQtr(new DateTime(2013,8,15), 4) == new DateTime(2013,7,1)

BUT 15th Jan 2013 when FY starts February would be 1st November 2012

getStartOfFinancialQtr(new DateTime(2013,1,15), 2) == new DateTime(2012,11,1)

Upvotes: 0

Views: 7124

Answers (4)

user687474
user687474

Reputation:

You can use the Year class of the Time Period Library for .NET:

// ----------------------------------------------------------------------
public void FiscalYearRange()
{
  // calendar
  TimeCalendar fiscalYearCalendar = new TimeCalendar(
    new TimeCalendarConfig
      {
        YearBaseMonth = YearMonth.April,
        YearType = YearType.FiscalYear
      } );

  // time range
  TimeRange timeRange = new TimeRange( new DateTime( 2007, 10, 1 ), new DateTime( 2012, 2, 25 ) );
  Console.WriteLine( "Time range: " + timeRange );
  Console.WriteLine();

  // fiscal quarter
  Console.WriteLine( "Start Quarter: " + new Quarter( timeRange.Start, fiscalYearCalendar ) );
  Console.WriteLine( "End Quarter: " + new Quarter( timeRange.End, fiscalYearCalendar ) );
  Console.WriteLine();

  // fiscal year
  Year year = new Year( timeRange.Start, fiscalYearCalendar );
  while ( year.Start < timeRange.End )
  {
    Console.WriteLine( "Fiscal Year: " + year );
    year = year.GetNextYear();
  }
} // FiscalYearRange

Upvotes: 3

jason
jason

Reputation: 241789

As mentioned, you can easily obtain the answer from Nearest Completed quarter. Here's how you make the modification:

public static class DateTimeExtensions {
    public static DateTime NearestQuarterEnd(
        this DateTime date,
        int firstMonthOfFiscalYear
    ) {
        IEnumerable<DateTime> candidates =
            QuartersInYear(date.Year, firstMonthOfFiscalYear)
                .Concat(QuartersInYear(date.Year - 1, firstMonthOfFiscalYear));
        return candidates.SkipWhile(d => d > date).First();
    }

    static Dictionary<Tuple<int, int>, List<DateTime>> dict =
        new Dictionary<Tuple<int, int>, List<DateTime>>();
    static IEnumerable<DateTime> QuartersInYear(
        int year,
        int firstMonthOfFiscalYear
    ) {
        Contract.Requires(firstMonthOfFiscalYear >= 1 
            && firstMonthOfFiscalYear <= 12);
        var key = Tuple.Create(year, firstMonthOfFiscalYear);
        if(dict.ContainsKey(key)) {
            return dict[key];
        }
        else {
            var value =
                Enumerable
                  .Range(0, 4)
                  .Select(k => firstMonthOfFiscalYear + 3 * k)
                  .Select(m => m <= 12 ? m : m % 12)
                  .Select(m => new DateTime(year, m, 1))
                  .OrderByDescending(d => d)
                  .ToList();
            dict.Add(key, value);
            return value;
        }
    }
}

Usage:

 Console.WriteLine(new DateTime(2013, 1, 15).NearestQuarterEnd(1));
 Console.WriteLine(new DateTime(2013, 8, 15).NearestQuarterEnd(4));
 Console.WriteLine(new DateTime(2013, 1, 15).NearestQuarterEnd(2));

Output:

1/1/2013 12:00:00 AM
7/1/2013 12:00:00 AM
11/1/2012 12:00:00 AM

This passes all three of your test cases.

Upvotes: 1

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174467

The following solution is the most simple implementation I could think of and works without any - unnecessary - loops:

DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)
{
    var actualMonth = date.Month;
    var financialYear = date.Year;
    var difference = actualMonth - monthFinancialYearStartsOn;
    if(difference < 0)
    {
        --financialYear;
        difference += 12;
    }
    var quarter = difference / 3;

    return new DateTime(financialYear, monthFinancialYearStartsOn, 1).AddMonths(quarter * 3);
}

Upvotes: 6

Bob.
Bob.

Reputation: 4002

Isn't it as simple as this? Am I missing something to this? A quarter is defined as a period of three months, so you just have to find where the given date is, and then compute where the quarter begins based off that given month of the date.

public DateTime GetStartOfFinancialQtr(DateTime dtGiven, int startMonth) {
    DateTime dtQuarter = new DateTime(dtGiven.Year, startMonth, 1);

    // Start Q is less than the given date
    if(startMonth > dtGiven.Month) {
        while(dtQuarter > dtGiven) {
            dtQuarter = dtQuarter.AddMonths(-3);
        }
    }
    // Start Q is larger than the given date
    else {
        while(dtQuarter.Month + 3 <= dtGiven.Month) {
            dtQuarter = dtQuarter.AddMonths(3);
        }
    }

    return dtQuarter;
}

Below is the testing I ran:

Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 1, 15), 1).ToString());
Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 8, 15), 4).ToString());
Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 1, 15), 2).ToString());

Console output:

01/01/2013 000000
07/01/2013 000000
11/01/2012 000000

Upvotes: 3

Related Questions