计算日期所在的财务季度的开始日期

时间:2013-07-16 17:14:05

标签: c# datetime

假设财务季度始终在一个月的第一天开始,并且总是3个日历月。

不同的组织在不同月份开始其财政年度(FY) - 有些可能是4月1日,有些可能是7月1日,或者可能只是1月1日(这将与正常的日历季度相匹配)。

考虑到FY开始的日期和月份,您如何确定该日期所在季度的开始。

E.g。

DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)
1月15日,当FY开始Jan将= 1月1日

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

8月15日,FY将于4月1日开始,

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

但2013年1月15日,2月开始2月将是11月1日 2012

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

4 个答案:

答案 0 :(得分:6)

以下解决方案是我能想到的最简单的实现,并且没有任何 - 不必要的循环:

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

答案 1 :(得分:3)

这不简单吗?我错过了什么吗?四分之一被定义为三个月的期间,因此您只需要找到给定日期的位置,然后根据该日期的给定月份计算季度开始的位置。

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

以下是我跑的测试:

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

控制台输出:

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

答案 2 :(得分:3)

您可以使用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

答案 3 :(得分:1)

如上所述,您可以轻松Nearest Completed quarter获取答案。以下是您进行修改的方式:

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

用法:

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

输出:

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

这会传递所有三个测试用例。