☰
Humanizer `OnDate.November` 指南:用 Fluent API 直接构造当前年 11 月的任意 `DateOnly`
2026/9/28 7:44:19 网站建设 项目流程
  • 开发工具

【免费下载链接】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 的OnDate.November是一个面向 11 月的流式(Fluent)日期访问类:它把"当前年份 11 月的某一天"封装成 30 个静态只读属性(The1st~The30th)与一个通用方法The(int dayNumber),全部返回 .NET 6+ 的System.DateOnly类型。本文以 3.0.1 版本文档为基础,结合源码与测试,完整讲解该类 30 个属性、The(int)方法的签名与语义、T4 模板生成机制、与On.November(返回DateTime)的差异,以及可直接运行的实战示例,帮助你告别new DateTime(...)式的样板代码,用一行表达式写出可读性极强的日期字面量。

类概览:位置、命名空间与编译条件

OnDate.November是Humanizer.OnDate类的内嵌(嵌套)公共类,声明如下:

public class OnDate.November
  • 命名空间:Humanizer,因此引入using Humanizer;即可直接使用;
  • 继承关系:System.Object→November,本身不继承任何自定义基类;
  • 成员性质:所有成员均为public static,类为无状态工具类,无需实例化;
  • 编译条件:整个OnDate类型族被#if NET6_0_OR_GREATER包裹(见 OnDate.Days.cs),因为其成员返回System.DateOnly——这是 .NET 6 起引入的"只含日期、不含时间"的值类型。如果你的目标框架低于 .NET 6,该类不可用,此时应改用返回DateTime的 On.November。

该类解决的问题很具体:构造"当前年份 + 11 月 + 指定日"的日期值。无论今天是哪一年,OnDate.November.The10th总是返回当年 11 月 10 日的DateOnly,年份由DateTime.Now.Year在运行时动态取用。

30 个静态属性:The1st到The30th完整清单

OnDate.November为 11 月的每一天(1 日到 30 日)都预置了一个静态只读属性。完整清单如下(签名统一为public static System.DateOnly,语义均为"当前年份 11 月的对应日期"):

属性语义属性语义
The1st当前年 11 月 1 日The16th当前年 11 月 16 日
The2nd当前年 11 月 2 日The17th当前年 11 月 17 日
The3rd当前年 11 月 3 日The18th当前年 11 月 18 日
The4th当前年 11 月 4 日The19th当前年 11 月 19 日
The5th当前年 11 月 5 日The20th当前年 11 月 20 日
The6th当前年 11 月 6 日The21st当前年 11 月 21 日
The7th当前年 11 月 7 日The22nd当前年 11 月 22 日
The8th当前年 11 月 8 日The23rd当前年 11 月 23 日
The9th当前年 11 月 9 日The24th当前年 11 月 24 日
The10th当前年 11 月 10 日The25th当前年 11 月 25 日
The11th当前年 11 月 11 日The26th当前年 11 月 26 日
The12th当前年 11 月 12 日The27th当前年 11 月 27 日
The13th当前年 11 月 13 日The28th当前年 11 月 28 日
The14th当前年 11 月 14 日The29th当前年 11 月 29 日
The15th当前年 11 月 15 日The30th当前年 11 月 30 日

例如,OnDate.November.The10th的完整声明(摘自源码,属性实现为表达式体):

/// <summary> /// The 10th day of November of the current year /// </summary> public static DateOnly The10th => new(DateTime.Now.Year, 11, 10);

可以看到,属性名中的1st / 2nd / 3rd / 21st / 22nd / 23rd等后缀使用了英文序数词(ordinal)而非简单数字,这与 Humanizer 整体的"自然语言优先"设计一致——代码读起来就像一句英文句子:"On November, the 10th"。

通用方法:The(int dayNumber)

当需要以变量形式指定日期(例如来自用户输入或循环遍历)时,使用通用方法:

public static System.DateOnly The(int dayNumber);
  • 参数:dayNumber,类型System.Int32,表示 11 月中的第几天;
  • 返回值:System.DateOnly;
  • 实现:new(DateTime.Now.Year, 11, dayNumber)(见 OnDate.Days.cs)。

典型用法:

using Humanizer; int day = 17; DateOnly meetingDay = OnDate.November.The(day); // 当前年 11 月 17 日

需要注意,The(int)与 30 个固定属性在语义上完全等价:OnDate.November.The(10)与OnDate.November.The10th返回相同的DateOnly值。dayNumber的取值范围应落在 1~30 之间(11 月有 30 天);传入超出范围的值时,DateOnly构造器会抛出ArgumentOutOfRangeException,这与直接new DateOnly(year, 11, day)的行为一致。

源码级原理:T4 模板自动生成整个OnDate月份族

OnDate.November并不是手写的 30 个重复属性,而是由 T4 文本模板 OnDate.Days.tt 在构建时生成到 OnDate.Days.cs 的。模板的核心逻辑(节选):

const int leapYear = 2012; for (var month = 1; month <= 12; month++) { var firstDayOfMonth = new DateTime(leapYear, month, 1); var monthName = firstDayOfMonth.ToString("MMMM"); // 为每个月生成一个嵌套类,类名即月份英文名 public class <#= monthName #> { public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, <#= month #>, dayNumber); // 遍历该月每一天(天数取自闰年 2012,保证 2 月有 29 天) for (var day = 1; day <= DateTime.DaysInMonth(leapYear, month); day++) { var ordinalDay = day.Ordinalize(); // 1 -> 1st, 2 -> 2nd, 3 -> 3rd ... public static DateOnly The<#= ordinalDay #> => new(DateTime.Now.Year, <#= month #>, <#= day #>); } } }

从中可以提炼三个关键实现事实:

  1. 月份名来自ToString("MMMM"):November这个类名由 2012 年 11 月的MMMM格式输出生成,因此 12 个嵌套类(January~December)的命名规则完全一致;
  2. 属性名使用Ordinalize():属性后缀(1st、2nd、3rd……)由 Humanizer 自己的序数化扩展(OrdinalizeExtensions.cs)生成,这也是整个 FluentDate 系列 API 名称风格的来源;
  3. 以闰年 2012 为模板计算每月天数:DateTime.DaysInMonth(2012, 11)得到 30,因此 11 月的生成产物恰好是The1st~The30th共 30 个属性,与文档中的 API 清单一一对应。

从源码结构可以推断,OnDate系列共包含 12 个月份嵌套类,每个类都遵循同一套"30 天左右固定属性 + 1 个通用The(int)方法"的模式,本文讨论的November只是其中之一。

OnDate.November与On.November的区别

Humanizer 的 FluentDate 里还有一对容易混淆的姊妹类:On.November(位于 On.Days.cs)与OnDate.November。两者表面签名一致,但返回值类型不同:

对比项On.NovemberOnDate.November
返回类型System.DateTimeSystem.DateOnly
典型成员The(int)、The1st~The30thThe(int)、The1st~The30th
框架要求无特殊要求仅NET6_0_OR_GREATER
适用场景需要同时携带时间部分、或与DateTimeAPI 互操作只关心日期本身、需要纯净的日期语义

选择建议:在 .NET 6+ 且业务上"只关心年月日"(如节日、账单日、纪念日)时优先使用OnDate.November,能避免DateTime携带的00:00:00时间分量带来的比较与格式化歧义;需要保留时间或兼容旧框架时再使用On.November。

实战示例:与At()组合构造精确时间点

FluentDate 家族不止提供"哪一天",还通过PrepositionsExtensions提供.At(hour, minute)扩展,可以把DateOnly/DateTime与时刻组合起来。结合 scenarios-fluent-dates 示例 的用法风格,一个完整的"11 月会议安排"示例可以这样写:

using Humanizer; // 当前年 11 月 10 日(DateOnly) DateOnly auditDay = OnDate.November.The10th; // 当前年 11 月第 17 天(变量形式) DateOnly reviewDay = OnDate.November.The(17); // 直接打印 Console.WriteLine($"Audit: {auditDay:yyyy-MM-dd}"); // 如 2026-11-10 Console.WriteLine($"Review: {reviewDay:yyyy-MM-dd}"); // 如 2026-11-17

如果项目目标是 .NET 6+,还可以把DateOnly与DateTime统一到同一套流式表达中——例如用In.AprilOf(2025).AddDays(2).At(14, 30)表达"2025 年 4 月 2 日 14:30",与OnDate.November的语义互补。

测试佐证:行为已被单元测试锁定

Humanizer 为 FluentDate 系列编写了专门的测试 OnDateTests.cs,其中针对"固定属性"与"通用方法"两类 API 都有断言:

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

从这些测试可以确认三条行为约定,同样适用于OnDate.November:

  1. 年份始终取DateTime.Now.Year,即"当前自然年",测试期望值也是用DateTime.Now.Year构造的;
  2. 固定属性与The(int)方法结果一致,内部都走new DateOnly(year, month, day)这一条路径;
  3. 测试文件同样以#if NET6_0_OR_GREATER条件编译,与 API 的框架约束保持一致。

使用注意事项小结

  • 框架前提:OnDate.November仅在 .NET 6 及以上目标框架可用(DateOnly类型依赖),项目文件需满足该条件;
  • 年份语义:返回的是当前运行年份的 11 月日期,而不是指定年份——如果需要指定年份,应改用In.AprilOf(year)这类接受年份参数的方法族,或自行new DateOnly(year, 11, day);
  • 取值范围:11 月固定 30 天,The(int)的参数建议在 1~30 之间,越界会抛出参数异常;
  • 与DateTime的互操作:若需要把结果转成DateTime,可直接使用DateOnly的ToDateTime(TimeOnly)实例方法补上时刻分量。

总而言之,OnDate.November用 31 个静态成员(30 个属性 + 1 个方法)把"当前年 11 月任意一天"这一常见日期构造需求收敛为纯流式、零样板代码的表达式,配合 Humanizer 其他 FluentDate 类(On、OnDate、In、InDate),可以组成一套完整的、可读性极强的日期 DSL。

  • 开发工具

【免费下载链接】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
点击查看免费下载
上一篇:Tesseract4Android终极指南:打造智能文字识别应用
下一篇:终极免费唇语识别工具:5分钟让你的嘴唇变成输入法

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

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

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

立即咨询