☰
Humanizer OnDate.March 流畅日期 API 详解:用 DateOnly 构建三月的可读日期表达式
2026/9/27 8:35:06 网站建设 项目流程
  • 开发工具

【免费下载链接】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 FluentDate 体系中的OnDate.March类:它是面向System.DateOnly的流畅日期访问器,让你以OnDate.March.The14th或OnDate.March.The(14)这种接近自然语言的表达式,直接获取"当前年份 3 月 14 日"这一日期值。读完本文,你将掌握该类的全部 31 个静态属性与The(int)方法的签名、返回值语义、底层实现原理(T4 模板代码生成)、运行环境前提(.NET 6+),以及它与On系列(DateTime版本)的对应关系,并能在自己的 .NET 项目中直接落地使用。

OnDate.March 类是什么

OnDate.March是 Humanizer 中OnDate静态类的一个嵌套类,文档原文将其定义为"Provides fluent date accessors for March"(为三月提供流畅的日期访问器)。其完整声明为:

public class OnDate.March

继承关系为System.Object→OnDate.March,同时该类还带有一个无参构造函数March(),用于初始化类的实例(由于成员均为静态,实际使用时无需实例化)。

在 API 文档中,OnDate.March暴露的成员可以分成三类:

  • 31 个静态只读属性:The1st到The31st,分别对应 3 月的 1 日到 31 日;
  • 1 个静态方法:The(int dayNumber),按传入的日期数字返回对应的 3 月日期;
  • 1 个构造函数:March()。

OnDate.March属于 Humanizer FluentDate 命名空间 中的OnDate体系。与On类(返回System.DateTime)不同,OnDate系列专门为 .NET 6 引入的DateOnly类型设计,因此整个类被#if NET6_0_OR_GREATER条件编译指令保护——只有目标框架为 .NET 6 或更高版本时,这些成员才可用。

全部 31 个日期属性:The1st 到 The31st

OnDate.March为 3 月的每一天都生成了一个静态属性,属性名采用英文序数词风格命名(The1st、The2nd、The3rd……The31st),每个属性都返回一个System.DateOnly值,语义为"当前年份三月的第 N 天"。完整清单如下:

属性说明属性说明
The1st3 月 1 日The17th3 月 17 日
The2nd3 月 2 日The18th3 月 18 日
The3rd3 月 3 日The19th3 月 19 日
The4th3 月 4 日The20th3 月 20 日
The5th3 月 5 日The21st3 月 21 日
The6th3 月 6 日The22nd3 月 22 日
The7th3 月 7 日The23rd3 月 23 日
The8th3 月 8 日The24th3 月 24 日
The9th3 月 9 日The25th3 月 25 日
The10th3 月 10 日The26th3 月 26 日
The11th3 月 11 日The27th3 月 27 日
The12th3 月 12 日The28th3 月 28 日
The13th3 月 13 日The29th3 月 29 日
The14th3 月 14 日The30th3 月 30 日
The15th3 月 15 日The31st3 月 31 日
The16th3 月 16 日

每个属性的签名完全一致,例如:

public static System.DateOnly The14th { get; }

API 文档中标注的Property Value类型均为System.DateOnly。由于属性是静态且只读的,访问时直接使用OnDate.March.The14th即可,无需任何实例。

The(int) 方法:按数字取三月的任意一天

除了固定命名的属性,OnDate.March还提供一个通用的The(int dayNumber)方法,用于按日期数字动态获取 3 月的某一天:

public static System.DateOnly The(int dayNumber);
  • 参数dayNumber:System.Int32,表示要获取的 3 月日期数字(如 14 表示 3 月 14 日);
  • 返回值:System.DateOnly,即当前年份 3 月dayNumber日对应的日期。

实际使用示例:

using Humanizer; var piDay = OnDate.March.The14th; // 3 月 14 日(圆周率日) var sameDay = OnDate.March.The(14); // 与上面等价,动态传参 Console.WriteLine(piDay); // 输出形如:2026-03-14 Console.WriteLine(piDay == sameDay); // True

当日期数字需要在运行时计算、无法预先静态写出时(例如来自用户输入或循环遍历),The(int)是比 31 个命名属性更灵活的选择。

底层实现:T4 模板批量生成的源代码

OnDate.March并非手写代码,而是由 T4 文本模板自动生成。模板位于 src/Humanizer/FluentDate/OnDate.Days.tt,其生成逻辑如下:

  1. 以闰年2012为基准,遍历 1 到 12 月,通过new DateTime(leapYear, month, 1).ToString("MMMM")得到月份英文名,从而生成January、February、March等 12 个嵌套类;
  2. 对每个月,用DateTime.DaysInMonth(leapYear, month)确定该月天数(3 月为 31 天),因此March类恰好生成 31 个属性;
  3. 每个日期属性的名字由day.Ordinalize()生成——这正是 Humanizer 自己的序数词扩展方法(1→1st、2→2nd、3→3rd、21→21st等),从而得到The1st、The2nd、The3rd直到The31st的属性名;
  4. 每个属性与The(int)方法内部都统一使用new(DateTime.Now.Year, month, day)构造DateOnly。

生成的实体代码位于 src/Humanizer/FluentDate/OnDate.Days.cs。以March类(从第 391 行开始)为例,其成员实现如下:

public class March { /// <summary> /// The nth day of March of the current year /// </summary> public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 3, dayNumber); /// <summary> /// The 1st day of March of the current year /// </summary> public static DateOnly The1st => new(DateTime.Now.Year, 3, 1); // ... The2nd 到 The31st 依此类推 }

从源码结构可以看出两个关键事实:

  • 年份取自系统当前时间:所有成员都使用DateTime.Now.Year作为年份,因此返回的总是"当前年份"的 3 月日期。若在 2026 年运行,OnDate.March.The1st即为2026-03-01;
  • 跨年自动生效:由于年份是运行时动态取的,应用程序跨年后无需修改任何代码,访问器会自动指向新一年的 3 月。

测试验证:生成结果如何被保障

仓库通过两层测试保证 31 个属性与The(int)方法的正确性:

1. 直接断言测试(tests/Humanizer.Tests/FluentDate/OnDateTests.cs)

该测试文件使用与生成代码相同的DateTime.Now.Year构造期望值,验证访问器与手写构造的结果一致:

[Fact] public void OnJanuaryThe23rd() => Assert.Equal(new(DateTime.Now.Year, 1, 23), OnDate.January.The23rd); [Fact] public void OnFebruaryThe() => Assert.Equal(new(DateTime.Now.Year, 2, 11), OnDate.February.The(11));

2. 反射式全覆盖测试(tests/Humanizer.Tests/FluentDate/GeneratedFluentDateTests.cs)

该测试通过反射遍历OnDate下所有月份嵌套类:

  • OnDateDayPropertiesCoverAllGeneratedDayAccessors断言所有月份嵌套类的静态属性都能被解析为"月 + 日"并返回正确的DateOnly;
  • OnDateTheMethodsCoverAllGeneratedMonthFactories断言每个月份类都存在The(int)方法且调用The(1)返回该月 1 日;
  • 解析属性名时采用The前缀 + 序数后缀的规则(TryParseDayProperty),能识别1st/2nd/3rd/4th…全部 31 个属性名。

这两类测试共同确保了"模板生成的 31 个属性数量正确、命名符合序数词规则、返回日期与手写new DateOnly(year, 3, day)完全等价"。

环境前提与限制

使用OnDate.March需要注意以下约束:

  • 目标框架必须为 .NET 6 或更高:因为返回值类型是System.DateOnly,整个OnDate类(连同InDate)都被#if NET6_0_OR_GREATER条件编译包裹(见 src/Humanizer/FluentDate/OnDate.Days.cs 第 1 行)。在 .NET Framework 或 .NET 5 及以下项目中无法使用;
  • 属性是静态的:直接通过OnDate.March.The14th访问,不需要实例化March类;
  • The(int)的入参是普通整数:传入 1~31 之间的任意整数即可,若需要特定命名可优先使用属性版本。

与 On.March(DateTime 版)的对应关系

Humanizer 的 FluentDate 提供了两套平行的日期 API:On系列返回DateTime,OnDate系列返回DateOnly。场景文档 fluent-dates-and-time-spans.mdx 明确说明:"InDateandOnDateprovide correspondingDateOnlyvalues on compatible frameworks"——即在支持DateOnly的框架上,OnDate是On的对应版本。

两者的成员结构完全平行:On.March.The14th返回包含时间分量的DateTime(时间为零点),而OnDate.March.The14th返回不含时间的DateOnly。在选择时可以参考以下规则:

  • 只需要"日期"语义、不关心时间部分、且目标是 .NET 6+:优先使用OnDate.March;
  • 需要DateTime(例如要与旧 API 互操作、参与时区转换):使用On.March。

此外,InDate系列(如InDate.March的月份访问器与In(5).Days之类的相对偏移)提供了从"当前日期"偏移的DateOnly访问器,与OnDate的"绝对某月某日"语义互补,共同构成完整的 FluentDate 体验。相关 API 参考可见 Humanizer.OnDate.March、Humanizer.OnDate 与 Humanizer.InDate。

实战组合示例

将命名属性、动态方法与DateOnly的既有能力组合起来,可以写出高度可读的业务代码:

using Humanizer; // 1) 静态命名:圆周率日与白色情人节 DateOnly piDay = OnDate.March.The14th; DateOnly whiteDay = OnDate.March.The14th.AddDays(0); // 3 月 14 日 // 2) 动态传参:根据配置项决定日期 int configuredDay = 8; // 假设来自配置 DateOnly womenDay = OnDate.March.The(configuredDay); // 3 月 8 日 // 3) 结合 DateOnly 计算:本月剩余天数 DateOnly today = DateOnly.FromDateTime(DateTime.Now); DateOnly endOfMarch = OnDate.March.The31st; int daysLeftInMarch = endOfMarch.DayNumber - today.DayNumber; Console.WriteLine($"3 月还剩 {daysLeftInMarch} 天");

以上代码同时体现了OnDate.March的两大价值:代码自文档化(OnDate.March.The14th比new DateOnly(2026, 3, 14)表达意图更直接)与年份自适应(无需关心具体年份,始终指向当前年份的 3 月)。

小结

OnDate.March是 Humanizer FluentDate 体系中OnDate静态类的 3 月访问器,提供 31 个静态DateOnly属性(The1st–The31st)与一个The(int)动态方法,全部返回"当前年份三月"的对应日期。它由 OnDate.Days.tt 模板借助 Humanizer 自身的Ordinalize()自动生成,实体代码位于 src/Humanizer/FluentDate/OnDate.Days.cs,并通过 OnDateTests.cs 与 GeneratedFluentDateTests.cs 双重验证。使用时需注意 .NET 6+ 的环境前提,并可参照On.March(DateTime版)在两种返回类型之间按需选择。

  • 开发工具

【免费下载链接】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
点击查看免费下载
上一篇:SmartTube终极指南:如何在Android TV上完美开启HDR视频播放
下一篇:终极指南:深入理解Trino分布式事务的两阶段提交实现

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

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

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

立即咨询