对于应用程序,我需要对日期进行一些计算。我发现如何在2个日期之间获得差异,但不知道如何将这些月份添加到另一个日期。
计算月份差异的函数:
public static decimal GetMonthsInRange(DateTime start, DateTime finish)
{
var monthsApart =
Math.Abs(12 * (start.Year - finish.Year) + start.Month - finish.Month) - 1;
decimal daysInStartMonth = DateTime.DaysInMonth(start.Year, start.Month);
decimal daysInFinishMonth = DateTime.DaysInMonth(finish.Year, finish.Month);
var daysApartInStartMonth = (daysInStartMonth - start.Day + 1) / daysInStartMonth;
var daysApartInFinishMonth = finish.Day / daysInFinishMonth;
return monthsApart + daysApartInStartMonth + daysApartInFinishMonth;
}
示例:
我得到的月份差异是4.5个月,我需要将其添加到另一个日期。但DateTime.AddMonths
函数只接受整数。
我该怎么做?
GRTS, Nanou
答案 0 :(得分:4)
显然,如果你想将这种差异添加到某些DateTime
,你不应该计算月份的差异,因为这种差异可能更令人困惑,比如说4.33个月或类似的东西。
相反 - 只需计算天数差异(在具体示例中为(finish - start).TotalDays
)并使用AddDays
。
答案 1 :(得分:0)
DateTime具有“AddMonths”和“AddDays”等功能。这些采用整数值。如果您有小数月,则应保留您计算出的天数的整数差异,并将该值添加为所需精度的天数。 ins/2
另外,你确实遇到了问题,因为你在两个月之间进行ABS计算(因此它可以两种方式工作),但你没有看到在月份的日期之前/之后进行相同的修改calcuations。
答案 2 :(得分:0)
您的GetMonthsInRange
的工作原理如下:每天的重量与该月的天数成反比。所以一天(即24小时)的相同时差 - 如果它落在不同的月份 - 对应于不同的小数结果,根据到GetMonthsInRange
的奇怪的规则。
我说这很奇怪,但也许可能有一些合同/会计理由重新定义数月的差异。例如,如果想要根据月度金额计算时间等效期间 ...
如果您希望使用反向工程AddMonths
,基于相同的规则,那么与该位置一致,您可以编写如下的扩展名
public static class Extensions
{
public static DateTime AddMonths(this DateTime date, decimal months)
{
var start = date;
decimal daysInStartMonth = DateTime.DaysInMonth(start.Year, start.Month);
var daysApartInStartMonth = (daysInStartMonth - start.Day + 1) / daysInStartMonth;
if (months <= daysApartInStartMonth)
{
return date.AddDays((double)(months * daysInStartMonth - 1));
}
var finish = date.AddMonths(1);
int monthsApart = 0;
if (months > daysApartInStartMonth + 1)
{
monthsApart = (int)(months - daysApartInStartMonth);
finish = finish.AddMonths(monthsApart);
}
decimal daysInFinishMonth = DateTime.DaysInMonth(finish.Year, finish.Month);
var startOfFinishMonth = new DateTime(finish.Year, finish.Month, 1).AddDays(-1);
decimal remaining = months - daysApartInStartMonth - monthsApart;
return startOfFinishMonth.AddDays((double)(remaining * daysInFinishMonth));
}
}
测试这是否符合您的需求。我假设您希望GetMonthsInRange
和AddMonths
保持一致。
可能的测试用例生成器
bool ok = true;
for (int i = 0; i < 1000; i++)
{
var day1 = new DateTime(2017, 2, 16);
var day2 = new DateTime(2017, 2, 16).AddDays(i);
var test = Extensions.GetMonthsInRange(day1, day2);
var res = day1.AddMonths(test);
var check = DateTime.Compare(day2, res);
if (check != 0)
{
ok = false;
break;
}
}
答案 3 :(得分:0)
从技术上讲,您可以尝试在两个 AddMonth
结果之间使用线性插值:
private static DateTime AddMonths(DateTime source, double months) {
int left = (int) Math.Floor(months);
int right = (int) Math.Ceiling(months);
double days =
(source.AddMonths(right) - source.AddMonths(left)).TotalDays *
(months - Math.Floor(months));
return source.AddMonths(left).AddDays(days);
}
试验:
DateTime source = DateTime.Today;
double add = 1.0;
Console.Write($"{source} + {add} = {AddMonths(source, add)}");
add = 1.1;
Console.Write($"{source} + {add} = {AddMonths(source, add)}");
add = 1.5;
Console.Write($"{source} + {add} = {AddMonths(source, add)}");
add = 1.95;
Console.Write($"{source} + {add} = {AddMonths(source, add)}");
add = 2.0;
Console.Write($"{source} + {add} = {AddMonths(source, add)}");
结果:
16.02.2017 0:00:00 + 1 = 16.03.2017 0:00:00
16.02.2017 0:00:00 + 1.1 = 19.03.2017 2:24:00
16.02.2017 0:00:00 + 1.5 = 31.03.2017 12:00:00
16.02.2017 0:00:00 + 1.95 = 14.04.2017 10:48:00
16.02.2017 0:00:00 + 2 = 16.04.2017 0:00:00
但是,请记住,几个月的长度不同[28..31]
天,插值只是估算。