☰
Humanizer `On.March` 流式日期访问器完全指南:三月 31 个日期属性与源码实现解析
2026/9/28 11:11:26 网站建设 项目流程
  • 开发工具

【免费下载链接】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 的On.March类展开,它是流式日期(Fluent Date)API 家族中专门表达"当前年份三月的某一天"的静态访问器集合。读完本文,你将掌握On.March.The1st~The31st全部 31 个日期属性的准确语义与返回类型、The(int dayNumber)方法的动态取值用法,并理解这些 API 由 T4 模板批量生成的底层原理、与At/AtNoon/AtMidnight等介词扩展的组合套路,以及"读取当前年份"这一行为在可重复测试与确定型代码中的注意事项。

On.March类概览

On.March是嵌套在静态类On内部的公共类,位于Humanizer命名空间下,用于为三月提供流式日期访问器(fluent date accessors):

public class On.March

从继承关系看,它是一个直接继承自System.Object的普通类,类内所有成员都是public static,因此使用时不需实例化,直接以On.March.xxx形式调用。该类的完整源码位于 src/Humanizer/FluentDate/On.Days.cs,整个On类在同一文件中按月份嵌套定义了January~December共 12 个类似的月类。

在 Humanizer 的日期 API 体系中,On系列承担"构造日历日期"的职责:On.April.The3rd、On.March.The15th这类调用读起来就是一句自然语言。配套的还有提供DateOnly变体的OnDate类,以及表示"将来时间"的In系列(如In.Two.MonthsFrom(startingPoint)),三者共同构成 website/docs/scenarios/fluent-dates-and-time-spans.mdx 中描述的"可读性日期构造器"。

完整 API 清单:31 个静态日期属性

On.March为三月的每一天(1 日至 31 日)提供对应的静态属性,命名采用序数词后缀(The1st、The2nd、The3rd……),每个属性的返回值都是System.DateTime,语义统一为"当前年份三月的第 N 天"。

属性总表

属性名说明返回类型
On.March.The1st当前年份三月的第 1 天System.DateTime
On.March.The2nd当前年份三月的第 2 天System.DateTime
On.March.The3rd当前年份三月的第 3 天System.DateTime
On.March.The4th当前年份三月的第 4 天System.DateTime
On.March.The5th当前年份三月的第 5 天System.DateTime
On.March.The6th当前年份三月的第 6 天System.DateTime
On.March.The7th当前年份三月的第 7 天System.DateTime
On.March.The8th当前年份三月的第 8 天System.DateTime
On.March.The9th当前年份三月的第 9 天System.DateTime
On.March.The10th当前年份三月的第 10 天System.DateTime
On.March.The11th当前年份三月的第 11 天System.DateTime
On.March.The12th当前年份三月的第 12 天System.DateTime
On.March.The13th当前年份三月的第 13 天System.DateTime
On.March.The14th当前年份三月的第 14 天System.DateTime
On.March.The15th当前年份三月的第 15 天System.DateTime
On.March.The16th当前年份三月的第 16 天System.DateTime
On.March.The17th当前年份三月的第 17 天System.DateTime
On.March.The18th当前年份三月的第 18 天System.DateTime
On.March.The19th当前年份三月的第 19 天System.DateTime
On.March.The20th当前年份三月的第 20 天System.DateTime
On.March.The21st当前年份三月的第 21 天System.DateTime
On.March.The22nd当前年份三月的第 22 天System.DateTime
On.March.The23rd当前年份三月的第 23 天System.DateTime
On.March.The24th当前年份三月的第 24 天System.DateTime
On.March.The25th当前年份三月的第 25 天System.DateTime
On.March.The26th当前年份三月的第 26 天System.DateTime
On.March.The27th当前年份三月的第 27 天System.DateTime
On.March.The28th当前年份三月的第 28 天System.DateTime
On.March.The29th当前年份三月的第 29 天System.DateTime
On.March.The30th当前年份三月的第 30 天System.DateTime
On.March.The31st当前年份三月的第 31 天System.DateTime

方法:The(int dayNumber)

除了 31 个命名属性,On.March还提供一个参数化方法,用于动态取得三月的任意一天:

public static System.DateTime The(int dayNumber);
  • 参数dayNumber:类型System.Int32,表示目标日期在三月中的日序号(1~31)。
  • 返回:System.DateTime,即"当前年份三月第dayNumber天"。
  • 边界行为:从源码new(DateTime.Now.Year, 3, dayNumber)可以看出,dayNumber会直接传入DateTime构造函数;超出 1~31 范围(例如The(32)或The(0))会抛出ArgumentOutOfRangeException,这是由System.DateTime构造函数本身强制校验的,Humanizer 未做额外包装。

参数化方法与命名属性的取舍很直接:写死业务日期(如营销活动固定为 3 月 14 日)用The14th更自文档化;日期来自变量或计算结果时用The(dayNumber)。

源码实现:一行表达式与 T4 模板批量生成

On.March的每个成员实现都极其精简,本质是对DateTime构造函数的封装。以属性The1st为例,源码为:

public static DateTime The1st => new(DateTime.Now.Year, 3, 1);

即"取当前系统时间的年份,固定月份 3,固定日序号",返回值带 0 时 0 分 0 秒,不携带时区信息。The(int dayNumber)同理:

public static DateTime The(int dayNumber) => new(DateTime.Now.Year, 3, dayNumber);

从源码结构看,这段代码并非手写 12 个月 × 各自天数的大量样板,而是由一个 T4 文本模板批量生成的。src/Humanizer/FluentDate/On.Days.tt 中,模板以 2012 年(闰年,用于覆盖 2 月 29 日)为基准遍历 12 个月,用firstDayOfMonth.ToString("MMMM")取得英文月份名作为嵌套类名,再用day.Ordinalize()生成The1st、The2nd……这种序数后缀:

for (var day = 1; day <= DateTime.DaysInMonth(leapYear, month); day++) { var ordinalDay = day.Ordinalize(); // 生成 public static DateTime The<ordinalDay> => new(DateTime.Now.Year, <month>, <day>); }

Ordinalize()是 Humanizer 自身的序数词扩展(实现位于 src/Humanizer/OrdinalizeExtensions.cs),模板由此保证1 → 1st、2 → 2nd、3 → 3rd、21 → 21st等英文序数后缀的规范性。这也是为什么On.March的 31 个属性名严格遵循英文序数词形。

顺带一提,模板对每个月的天数取自闰年 2012 的DateTime.DaysInMonth,所以二月生成到The29th,而三月固定生成 31 个属性——三月在任何年份都有 31 天,因此On.March不存在闰年下溢问题。

组合用法:从"三月某日"到完整时间点

On.March.TheNth只产出日期(时间为 00:00:00)。要拼出完整的业务时间点,可与 PrepositionsExtensions 提供的扩展方法链式组合:

using Humanizer; // 当前年份 3 月 14 日 14:30:00 var piDay = On.March.The14th.At(14, 30); // 当前年份 3 月 1 日 12:00:00 var noon = On.March.The1st.AtNoon(); // 当前年份 3 月 31 日 00:00:00 var monthEndMidnight = On.March.The31st.AtMidnight(); // 动态日序号:某月的第 n 天 var dynamicDay = On.March.The(dayNumber);

At(int hour, int min = 0, int second = 0, int millisecond = 0)允许一次性指定时、分、秒、毫秒;AtNoon()等价于At(12),AtMidnight()等价于At(0)。官方可运行示例 website/docs/_examples/scenarios-fluent-dates/Program.cs 演示了同类用法(如In.AprilOf(2025).AddDays(2).At(14, 30)),可直接参照此模式组织三月日程。

如需将三月日期固定到指定年份(而非"当前年份"),可用PrepositionsExtensions.In(int year):

var marchFirst2026 = On.March.The1st.In(2026); // 2026-03-01 00:00:00

若目标框架支持DateOnly(.NET 6+),可改用OnDate.March系列(源码见 src/Humanizer/FluentDate/OnDate.Days.cs),其 API 形状与On.March完全一致,只是返回System.DateOnly。

测试验证

Humanizer 测试套件 tests/Humanizer.Tests/FluentDate/OnTests.cs 直接验证了On系列访问器与"当前年份构造"的等价性:

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

这些断言确认了两点实现事实:命名属性与new DateTime(DateTime.Now.Year, month, day)完全等价;The(dayNumber)方法同样以DateTime.Now.Year为年份基准。On.March的成员遵循同一模板逻辑,行为可由此类推。

使用注意事项与边界

  • 依赖"当前年份":On.March所有成员都读取DateTime.Now.Year,因此结果随调用时刻变化。官方场景文档 website/docs/scenarios/fluent-dates-and-time-spans.mdx 明确建议:在需要可重复执行的代码或测试中,避免依赖"当前时间"的访问器,应注入固定起始日期(例如用In.Two.MonthsFrom(startingPoint)配合显式DateTime),或直接用In(2026)/OnDate固定年份。
  • 本地时间而非 UTC:DateTime.Now是本地时钟时间,跨时区部署时同一代码在不同服务器上会得到不同结果;需要 UTC 语义时应自行用DateTime.UtcNow.Year组合构造。
  • 时间部分恒为 0:属性与The(n)返回的时间均为午夜零点;需要具体时刻务必再接At/AtNoon/AtMidnight。
  • 参数范围:The(dayNumber)的dayNumber越界会抛异常;三月固定 31 天,不存在 2 月 29 日式的闰年特例。
  • API 归属:On.March属于 Humanizer 的Humanizer.FluentDate命名空间文件组(见 src/Humanizer/FluentDate 目录),随主程序集一并分发,引入using Humanizer;即可使用,无需额外安装独立包。

相关 API 与延伸阅读

  • 同族 API:[On类(12 个月完整访问器,源码 src/Humanizer/FluentDate/On.Days.cs)](website/docs/api/Humanizer.On.md)、OnDate类(DateOnly变体)
  • 配套扩展:PrepositionsExtensions(At/AtNoon/AtMidnight/In(year))
  • 实战场景:流式组合日期与时长 及官方示例 Program.cs
  • 测试佐证:OnTests.cs

简而言之,On.March.The14th一类调用把"三月十四日"变成了可读、可组合、类型安全的 C# 表达式——在报表截止日、活动排期、账单日等固定日历场景中,它比手写new DateTime(DateTime.Now.Year, 3, 14)更贴近业务语义,也让代码评审者一眼读懂意图。

  • 开发工具

【免费下载链接】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
点击查看免费下载
上一篇:ComfyUI-WanVideoWrapper:如何在10分钟内生成1025帧长视频的完整指南 🚀
下一篇:AI 文献综述怎么做?Scientific Agent Skills 论文全文检索 + 假设生成 + 证据溯源写作完整教程

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

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

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

立即咨询