☰
Humanizer InDate.Three 完全指南:用 Fluent API 轻松计算“三天后/三个月后”的 DateOnly 日期
2026/9/28 6:17:30 网站建设 项目流程
  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

Humanizer 的InDate系列是专门面向DateOnly的流畅日期构造 API,而InDate.Three则集中提供了以3 个时间单位为步长的日期计算能力:3 天、3 周、3 个月、3 年后(或从任意给定日期起算)的日期。读完本文,你将掌握InDate.Three全部 4 个属性与 8 个方法的签名、返回值与语义差异,理解其基于UtcNow与AddDays/AddMonths/AddYears的实现原理,并能在 .NET 6+ 项目中写出可读、可复现的日期偏移代码。

一、定位:InDate是面向DateOnly的流畅日期构造器

InDate是 Humanizer FluentDate 模块中的一个public partial class,与面向DateTime的In类形成对应关系。从源码结构看,InDate.cs 提供了TheYear(int year)与各月份属性(January、April等,返回当年该月 1 日的DateOnly),而 InDate.SomeTimeFrom.cs 中则定义了从One到Ten共 10 个嵌套静态类,InDate.Three就是其中的第 3 个。

public partial class InDate { public static class Three { // 3 天 / 3 周 / 3 个月 / 3 年后(相对当前时刻) public static DateOnly Days { get; } public static DateOnly Weeks { get; } public static DateOnly Months { get; } public static DateOnly Years { get; } // 从指定日期起算 public static DateOnly DaysFrom(DateOnly date); public static DateOnly DaysFrom(DateTime date); public static DateOnly WeeksFrom(DateOnly date); public static DateOnly WeeksFrom(DateTime date); public static DateOnly MonthsFrom(DateOnly date); public static DateOnly MonthsFrom(DateTime date); public static DateOnly YearsFrom(DateOnly date); public static DateOnly YearsFrom(DateTime date); } }

对应 API 文档位于 website/versioned_docs/version-3.0.1/api/Humanizer.InDate.Three.md,整个InDate.Three类的返回类型一律是System.DateOnly,这意味着该 API 仅在 .NET 6 及以上框架可用(源码中整体包裹在#if NET6_0_OR_GREATER预处理器指令内)。

二、属性速览:四个“从现在起算”的只读属性

InDate.Three提供 4 个静态只读属性,语义均为“从现在起 N 个时间单位之后”,内部统一基于DateTime.UtcNow计算:

属性文档说明返回类型内部实现(源码)
Days3 days from now(3 天后)System.DateOnlyDateOnly.FromDateTime(DateTime.UtcNow.AddDays(3))
Weeks3 weeks from now(3 周后)System.DateOnlyDateOnly.FromDateTime(DateTime.UtcNow.AddDays(21))
Months3 months from now(3 个月后)System.DateOnlyDateOnly.FromDateTime(DateTime.UtcNow.AddMonths(3))
Years3 years from now(3 年后)System.DateOnlyDateOnly.FromDateTime(DateTime.UtcNow.AddYears(3))

实现细节对应 InDate.SomeTimeFrom.cs 中Three类的第 169–236 行,例如:

public static DateOnly Days => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(3)); public static DateOnly Weeks => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(21));

需要特别注意的三点:

  1. 周是“7 天制”:Weeks在源码中等价于AddDays(21)(3 × 7 天),而不是调用AddWeeks,因为DateOnly本身只提供AddDays/AddMonths/AddYears。
  2. 基准时刻是 UTC:这四个属性读的是DateTime.UtcNow而非本地DateTime.Now,因此取值随“当前 UTC 时刻”漂移,属于非确定性表达式(详见后文“可复现性”一节)。
  3. 只取日期部分:无论当前 UTC 时刻几点几分,结果都通过DateOnly.FromDateTime截断为纯日期,不含时间分量。

三、方法速览:八个“从指定日期起算”的重载

与属性相对,InDate.Three的方法族允许传入一个基准日期,从而得到确定性的偏移结果。每个时间单位都有两个重载:

方法参数类型返回类型源码实现
DaysFromSystem.DateOnlySystem.DateOnlydate.AddDays(3)
DaysFromSystem.DateTimeSystem.DateOnlyDateOnly.FromDateTime(date.AddDays(3))
WeeksFromSystem.DateOnlySystem.DateOnlydate.AddDays(21)
WeeksFromSystem.DateTimeSystem.DateOnlyDateOnly.FromDateTime(date.AddDays(21))
MonthsFromSystem.DateOnlySystem.DateOnlydate.AddMonths(3)
MonthsFromSystem.DateTimeSystem.DateOnlyDateOnly.FromDateTime(date.AddMonths(3))
YearsFromSystem.DateOnlySystem.DateOnlydate.AddYears(3)
YearsFromSystem.DateTimeSystem.DateOnlyDateOnly.FromDateTime(date.AddYears(3))

两组重载的差异在于输入:传DateOnly时直接调用DateOnly.AddXxx;传DateTime时先对DateTime做加法、再用DateOnly.FromDateTime转换。两种重载的返回值都是DateOnly,因此无论业务层拿到的是DateTime还是DateOnly,都能统一得到纯日期结果,便于与DateOnly字段、参数、ToString("yyyy-MM-dd")格式化等场景对接。

四、源码级原理:T4 模板批量生成与命名约定

InDate.Three并非手写代码,而是由 T4 文本模板 InDate.SomeTimeFrom.tt 批量生成。模板核心循环如下(节选):

<#for (var i = 1; i <= 10; i++){ var plural = i > 1 ? "s" : ""; var day = "Day" + plural; var week = "Week" + plural; var month = "Month" + plural; var year = "Year" + plural; #> public static class <#= i.ToWords().Dehumanize() #> { public static DateOnly <#= day #> => DateOnly.FromDateTime(DateTime.UtcNow.AddDays(<#= i #>)); ... } <#}#>

从中可以读出的三条生成规则:

  1. 类名由数字的英文单词生成:i.ToWords()将3转为"three",再经Dehumanize()得到帕斯卡命名Three,因此One~Ten十个类的类名完全一致对称。
  2. 成员名的单复数约定:i > 1时成员名为复数(Days/Weeks/Months/Years),i == 1时为单数(Day/Week/Month/Year)。也就是说,InDate.One.Day与InDate.Three.Days的命名不对称,这是刻意设计,使用时不要写错。
  3. 周统一用天数展开:模板中week成员的实现是AddDays(i * 7),与属性部分的UtcNow.AddDays(i * 7)一致。

同样的模式也存在于面向DateTime的In类(见 In.SomeTimeFrom.tt),二者共同构成了 Humanizer FluentDate 的“数字 + 时间单位”命名空间。

五、实战用法:可复现的日期偏移

InDate.Three最典型的用法是传入确定基准、获得确定结果,适合定时任务排期、订阅周期计算、报表截止日期等场景。

using Humanizer; // 从固定基准日偏移(确定性,可单测) var baseDate = new DateOnly(2026, 9, 27); var in3Days = InDate.Three.DaysFrom(baseDate); // 2026-09-30 var in3Weeks = InDate.Three.WeeksFrom(baseDate); // 2026-10-18 var in3Months = InDate.Three.MonthsFrom(baseDate); // 2026-12-27 var in3Years = InDate.Three.YearsFrom(baseDate); // 2029-09-27 // DateTime 重载同样返回 DateOnly var fromDateTime = InDate.Three.MonthsFrom(new DateTime(2026, 9, 27, 14, 30, 0)); // 结果仍是 DateOnly: 2026-12-27

如果只是想表达“相对现在的 3 个月后”,也可以直接用属性:

var reminderDate = InDate.Three.Months; // ≈ UtcNow 加 3 个月后的日期

Humanizer 官方场景示例 fluent-dates-and-time-spans.mdx 与可运行示例 Program.cs 也演示了这类日历型日期运算与时长型运算(如1.5.Days()返回TimeSpan)的区分思路。

测试验证

仓库测试 InDateTests.cs 对同族 API 的验证方式可以直接套用到InDate.Three:

[Fact] public void InFiveDays() { var baseDate = OnDate.January.The21st; var date = InDate.Five.DaysFrom(baseDate); Assert.Equal(baseDate.AddDays(5), date); }

即:给定基准日期调用From方法,应与基准日期直接调用AddDays/AddMonths/AddYears的结果完全相等。这也反向印证了InDate.Three.DaysFrom(date)就是date.AddDays(3)的薄封装。

六、实践要点与注意事项

  1. 框架前提:DateOnly自 .NET 6 引入,InDate全家(包括InDate.Three)仅在NET6_0_OR_GREATER条件下编译。面向 .NET Framework / .NET 5 及以下时,应改用面向DateTime的In类。
  2. 确定性优先:Days/Months/Weeks/Years四个属性依赖UtcNow,每次调用结果随时间变化;需要可重复执行的代码(定时任务、测试、幂等计算)应改为InDate.Three.MonthsFrom(fixedDate)形式。
  3. 日历算术而非时长算术:MonthsFrom/YearsFrom委托给AddMonths/AddYears,遵循日历归一化规则——例如从 2 月 29 日加 3 个月到非闰年,结果为 2 月 28 日(5 月 29 日→实际取 5 月末归一),这与TimeSpan的固定 24 小时天数语义有本质区别。
  4. 命名坑位提醒:InDate.One使用单数Day/Week/Month/Year,InDate.Three至InDate.Ten使用复数,复制粘贴代码时留意区分。

七、延伸阅读

  • InDate全部成员(月份属性与Of(int year)方法):Humanizer.InDate API
  • 面向DateTime的对应实现:In类(In.SomeTimeFrom.tt)与InAPI 文档
  • FluentDate 场景指南:fluent-dates-and-time-spans.mdx
  • 生成InDate.One~Ten的 T4 模板:InDate.SomeTimeFrom.tt,生成结果见 InDate.SomeTimeFrom.cs
  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载
上一篇:如何快速上手IDR:从2D图像重建高质量3D模型的完整指南
下一篇:【亲测免费】 Juicebox:解锁基因组的三维密码

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询