计算日期所在的财务季度的开始日期
本文关键字:日期 季度 开始 计算 | 更新日期: 2023-09-27 18:22:31
假设财务季度总是从一个月的第一天开始,并且总是有3个日历月长。
不同的组织在不同的月份开始他们的财政年度(FY)——有些可能是4月1日,有些可能是7月1日或可能只是1月1日(这将与正常的日历季度相匹配)。
给定财政年度开始的日期和月份,如何确定该日期所在季度的开始。
例如
DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)
财政年度开始时的1月15日=1月1日
getStartOfFinancialQtr(new DateTime(2013,1,15), 1) == new DateTime(2013,1,1)
财政年度4月开始的8月15日将是的7月1日
getStartOfFinancialQtr(new DateTime(2013,8,15), 4) == new DateTime(2013,7,1)
但2013年1月15日财政年度2月开始时将是2012年11月1日
getStartOfFinancialQtr(new DateTime(2013,1,15), 2) == new DateTime(2012,11,1)
下面的解决方案是我能想到的最简单的实现,并且没有任何不必要的循环:
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);
}
这不是这么简单吗?我是不是错过了什么?一个季度被定义为三个月的时间段,所以你只需要找到给定的日期在哪里,然后根据该日期的给定月份计算该季度的开始位置。
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
您可以使用.NET:的时间段库的Year类
// ----------------------------------------------------------------------
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
如上所述,您可以轻松地从最近完成季度获得答案。以下是如何进行修改:
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
这通过了您的所有三个测试用例。