- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
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~The9th | public static System.DateTime The1st { get; } | 当前年份 2 月 1 日 ~ 9 日 |
The10th~The19th | public static System.DateTime The10th { get; } | 当前年份 2 月 10 日 ~ 19 日 |
The20th~The29th | public 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 月"推广到任意年份的同一日期。
需要注意的限制:
- 基于
DateTime.Now:所有属性与The(int)都读取当前时刻的年份,代码在跨年瞬间(12 月 31 日 23:59:59 附近)执行时年份可能"漂移";官方场景文档明确建议在可重复的代码或测试中注入起始日期,而不是依赖"现在"; - 闰年约束:
The29th平年抛异常,使用前应先判断DateTime.IsLeapYear或捕获异常; - 非法日号:
The(30)等越界参数由DateTime构造函数抛出ArgumentOutOfRangeException; - 框架要求:
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
相关推荐
探索 V2exOS 核心功能:主题浏览、评论互动与通知管理全解析
探索 V2exOS 核心功能:主题浏览、评论互动与通知管理全解析 V2exOS 是一款采用 SwiftUI 开发的跨平台客户端,支持 macOS、iOS 和 t
开发工具Humanizer 流式日期 API 详解:InDate.Ten 的 10 天 / 周 / 月 / 年日期计算
Humanizer 流式日期 API 详解:InDate.Ten 的 10 天 / 周 / 月 / 年日期计算 本篇技术指南聚焦 Humanizer 流式日期(
开发工具Humanizer InDate.Ten 详解:用 DateOnly 流式 API 计算 10 天/周/月/年后的日期
Humanizer InDate.Ten 详解:用 DateOnly 流式 API 计算 10 天/周/月/年后的日期 InDate.Ten 是 Humaniz
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考