☰
Humanizer On.February 流式日期 API 详解:用自然语言构造 2 月日期
2026/9/25 5:27:04 网站建设 项目流程
  • 开发工具

【免费下载链接】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.February是 .NET 库 Humanizer FluentDate 体系中的一个静态嵌套类,专门用于以近乎自然语言的方式构造“当前年份 2 月某一天”的DateTime值。本篇以 API 参考文档 为主体,结合 On.Days.cs 源码 与 测试用例,讲解该类 29 个日期属性、The(int)工厂方法、闰年边界行为,以及At/AtMidnight/AtNoon等配套扩展的组合用法,帮助你写出可读性更强、无需手工拼new DateTime(...)的日期代码。

On 类与 On.February 的定位

On是一个公开的静态入口类,定义在 src/Humanizer/FluentDate/On.Days.cs 中。它为一年十二个月各提供一个同名的嵌套静态类:On.January、On.February、On.March……每个嵌套类的职责完全一致——用"自然语言式"的静态属性或方法返回"当前年份该月某一天"的DateTime。

API 文档对该类的定义如下:

public class On.February

其继承链为System.Object→February(嵌套在On之内,实际类型名是On.February)。从源码结构看,February类只包含一个无参构造函数(C# 默认提供)、29 个静态只读属性(The1st到The29th)和一个静态方法The(int dayNumber),没有任何实例状态——因此它本质上是一组"2 月日期工厂"。

每个属性的实现都非常简单,例如 源码第 218-219 行:

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

即:取DateTime.Now的年份,固定月份为 2,再拼上目标日号。这正是"当前年份 2 月的第 N 天"这一语义的直接落地。

成员清单:29 个静态属性 + 1 个工厂方法

On.February暴露的成员(与 API 文档一致)可以归为两类:

命名属性:The1st ~ The29th

成员签名语义
The1st~The9thpublic static System.DateTime The1st { get; }当前年份 2 月 1 日 ~ 9 日
The10th~The19thpublic static System.DateTime The10th { get; }当前年份 2 月 10 日 ~ 19 日
The20th~The29thpublic static System.DateTime The20th { get; }当前年份 2 月 20 日 ~ 29 日

所有属性返回值类型均为System.DateTime。命名规则直接沿用英文序数词的后缀(1st、2nd、3rd、4th…),与 2 月的最大天数 28/29 天一一对应——这 29 个属性恰好覆盖 2 月的全部合法日期。

动态方法:The(int)

public static System.DateTime The(int dayNumber);
  • 参数:dayNumber(System.Int32),表示想要的日号;
  • 返回:System.DateTime,即"当前年份 2 月第 dayNumber 天";
  • 实现:new(DateTime.Now.Year, 2, dayNumber),见 源码第 211-212 行。

测试 OnTests.cs 第 12-13 行 验证了该方法的行为:

[Fact] public void OnFebruaryThe() => Assert.Equal(new(DateTime.Now.Year, 2, 11), On.February.The(11));

当dayNumber超出 2 月的合法范围(如The(30))时,DateTime构造函数会直接抛出ArgumentOutOfRangeException;这一行为是System.DateTime构造语义的一部分,并非 Humanizer 单独做的校验。

闰年语义:The29th 只在闰年有效

2 月在 FluentDate 体系中是个特殊月份——它最多只有 29 天。The29th属性(源码 中实现为new(DateTime.Now.Year, 2, 29))在平年会抛出异常,只有闰年(能被 4 整除且不被 100 整除,或能被 400 整除的年份)才返回合法日期。

关于这一点,官方场景指南 Compose dates and time spans fluently 给出了一个重要提示:这些"当前年份"属性读取的是DateTime.Now,不适合在确定性代码或测试中使用。需要固定日期时,应当注入起始日期或使用In(int year)之类的扩展(见下文组合用法)。

此外,Humanizer 还提供了配套的OnDate.February(返回DateOnly,见 OnDate.Days.cs 源码),同样包含The1st~The29th和The(int),但仅在支持DateOnly的框架(.NET 6+)上可用。两者语义完全一致,区别只在返回类型。

组合用法:At / AtNoon / AtMidnight / In

On.February.The10th返回的DateTime时间部分恒为午夜 00:00:00。要指定具体时刻,可以链式调用 PrepositionsExtensions 提供的扩展方法:

using Humanizer; // 当前年份 2 月 14 日 14:30:00(情人节下午两点半) var valentineAppointment = On.February.The14th.At(14, 30); // 当前年份 2 月 1 日 00:00(午夜) var startOfFeb = On.February.The1st.AtMidnight(); // 当前年份 2 月 1 日 12:00(正午) var noonOfFeb1 = On.February.The1st.AtNoon(); // 把 2 月 14 日固定到指定年份,例如 2030 年 var fixedValentine = On.February.The14th.In(2030);

这些扩展的实现(PrepositionsExtensions.cs 第 12-31 行)如下:

public static DateTime At(this DateTime date, int hour, int min = 0, int second = 0, int millisecond = 0) => new(date.Year, date.Month, date.Day, hour, min, second, millisecond); public static DateTime AtMidnight(this DateTime date) => date.At(0); public static DateTime AtNoon(this DateTime date) => date.At(12); public static DateTime In(this DateTime date, int year) => new(year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);

注意In(year)与DateTime.AddYears的区别(同样记录在 场景指南 中):In(year)是在目标年份原样重建相同的月/日,如果该日期在目标年份不存在(例如把 2 月 29 日搬到平年)会抛出异常;而AddMonths/AddYears是"进位归一化"语义,闰年 2 月 29 日加一年会得到 2 月 28 日。

测试如何保障 29 个属性与 The 方法

FluentDate 的完整生成代码由 T4 模板(如 On.Days.tt)驱动,On.Days.cs是模板产物。仓库通过反射式的生成测试统一校验所有月份嵌套类,见 GeneratedFluentDateTests.cs:

  • OnDayPropertiesCoverAllGeneratedDayAccessors:遍历On的所有嵌套类型,断言每个TheNth属性都返回DateTime且值正确(第 17-18 行);
  • OnTheMethodsCoverAllGeneratedMonthFactories:断言每个月份的The(int)工厂方法行为一致(第 21-22 行)。

这意味着On.February的 29 个属性不是手写维护的,而是与其它 11 个月份共用同一套生成与校验机制,保证了 API 的一致性。

典型使用场景与注意事项

适合使用On.February的场景:

  • 领域可读的常量日期:如报表固定结算日On.February.The1st、活动截止日On.February.The28th,比new DateTime(year, 2, 28)意图更清晰;
  • 结合At/AtNoon构造日程:会议、提醒、预约等带时刻的业务日期;
  • 配合In(year)固定年份:从"今年 2 月"推广到任意年份的同一日期。

需要注意的限制:

  1. 基于DateTime.Now:所有属性与The(int)都读取当前时刻的年份,代码在跨年瞬间(12 月 31 日 23:59:59 附近)执行时年份可能"漂移";官方场景文档明确建议在可重复的代码或测试中注入起始日期,而不是依赖"现在";
  2. 闰年约束:The29th平年抛异常,使用前应先判断DateTime.IsLeapYear或捕获异常;
  3. 非法日号:The(30)等越界参数由DateTime构造函数抛出ArgumentOutOfRangeException;
  4. 框架要求:OnDate.February(DateOnly版本)仅在 .NET 6 及以上可用。

参考链接

  • On.February API 参考文档
  • On API 参考文档
  • On.Days.cs 源码(含 February 类)
  • OnDate.Days.cs 源码(DateOnly 版本)
  • PrepositionsExtensions 源码(At / AtNoon / AtMidnight / In)
  • OnTests.cs 测试
  • GeneratedFluentDateTests.cs 生成代码校验测试
  • Compose dates and time spans fluently 场景指南
  • 开发工具

【免费下载链接】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
点击查看免费下载

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

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

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

立即咨询