You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#基于NodaTime计算日期间隔的月份进位问题求助

嘿,我来帮你搞定这个NodaTime的日期间隔问题!

首先得说清楚为什么你会得到2 months, 30 days的结果——NodaTime的Period.Between计算的是两个日期之间的排他性日历间隔,也就是从起始日到结束日的前一天的间隔。而且它的计算逻辑是优先凑整年,再整月,最后算剩余天数,不会自动把天数进位成月份(毕竟不同月份天数不一样,没法统一进位)。

你的测试用例里,2017-10-16到2018-01-15,差一天就满3个月(到2018-01-16才是整3个月),所以Period.Between会拆成2个月(到2017-12-16)加上剩下的30天(2017-12-16到2018-01-15),这完全符合NodaTime的设计逻辑。


解决方案:包含结束日期并得到预期的间隔

针对你要包含结束日期正确计算月份间隔的需求,最简洁准确的方法是给结束日期加1天,再计算间隔——这样Period.Between就会把原结束日当天纳入计算范围:

LocalDate start = new LocalDate(2017, 10, 16);
LocalDate end = new LocalDate(2018, 1, 15);
// 给结束日期加1天,让计算覆盖原结束日
Period period = Period.Between(start, end.PlusDays(1));
Console.WriteLine("{0} years, {1} months, {2} days", period.Years, period.Months, period.Days);
// 输出:0 years, 3 months, 0 days

这个结果正好符合你的预期!因为加1天后,结束日期变成2018-01-16,和起始日2017-10-16刚好差整3个月。


额外说明:自定义间隔逻辑(如果需要)

如果你有更个性化的需求(比如不管天数是否满一个月,只要跨了n个自然月就算n个月),可以手动计算总月份差,再单独处理天数:

LocalDate start = new LocalDate(2017, 10, 16);
LocalDate end = new LocalDate(2018, 1, 15);

int totalYears = end.Year - start.Year;
int totalMonths = end.Month - start.Month;
int days = end.Day - start.Day;

// 处理天数不足的借位
if (days < 0)
{
    totalMonths--;
    // 计算借位后的天数:取结束月前一个月的最后一天,减去起始日天数,再加结束日天数
    days = (end.PlusMonths(-1).Day - start.Day) + end.Day;
}

// 处理月份不足的跨年份借位
if (totalMonths < 0)
{
    totalYears--;
    totalMonths += 12;
}

// 包含结束日期,给天数加1
days += 1;

Console.WriteLine("{0} years, {1} months, {2} days", totalYears, totalMonths, days);

不过这个方案更适合特殊场景,大多数情况下用第一个方案就足够简洁准确了。


最后再提一句:NodaTime的Period日历期间,不是时长——它代表的是日历上的年、月、日差,不是固定的毫秒数,所以不会自动把30天转换成1个月(毕竟有的月是31天,有的是28天)。如果需要纯时长计算,可以用Duration,但Duration只能给出总天数、小时数等,没法直接转成年月日。

内容的提问来源于stack exchange,提问作者Nex

火山引擎 最新活动