news 2026/9/29 8:19:07

Humanizer 流式日期 API 详解:On.August 类的全部成员、实现原理与实战用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Humanizer 流式日期 API 详解:On.August 类的全部成员、实现原理与实战用法
  • 开发工具

【免费下载链接】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静态类为 .NET 开发者提供了一套"口语化"的流式日期访问器(fluent date accessors),让你可以用On.August.The23rd这样接近自然语言的表达式直接获得"当前年份的 8 月 23 日"。本篇以On.August类为切入点,逐一解析其全部 31 个静态属性与The(int)方法,并结合源码揭示其由 T4 模板自动生成的实现机制、On与OnDate两个入口的差异,以及实际使用中的注意事项,帮助你彻底掌握 Humanizer 流式日期 API 的正确用法。

一、类概览:On.August 是什么

On.August是 On 类 内部嵌套的一个公开类,其唯一职责是提供 8 月(August)的流式日期访问器。官方 API 文档(Humanizer.On.August.md)中给出的类声明为:

public class On.August

该类直接继承自System.Object,本身不携带任何状态,全部成员均为public static,因此使用时不需要实例化,直接通过On.August.xxx静态访问即可。类的官方摘要为:"Provides fluent date accessors for August",即"为 8 月提供流式日期访问器"。

从源码角度看,On是一个容器类,内部为一年 12 个月各嵌套了一个同名字类(January、February、…、December),August只是其中之一。完整的生成代码位于 On.Days.cs(约第 1370 行开始是August类的定义)。

二、31 个静态属性:The1st 到 The31st 完整清单

On.August的核心成员是 31 个静态只读属性,分别对应 8 月的第 1 天到第 31 天(8 月为大月,共 31 天)。每个属性的声明形态完全一致,例如文档中的The10th声明为:

public static System.DateTime The10th { get; }

全部 31 个属性及含义如下(属性值均为System.DateTime,年份取自当前年):

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

属性命名遵循英文序数词规则:1 为st、2 为nd、3 为rd,其余为th(11、12、13 也遵循th,8 月不涉及这些特例)。每个属性的值都精确指向"当前年份"的 8 月对应日期,这一点非常关键:它永远返回的是DateTime.Now.Year这一年的 8 月某天,而不是固定年份。

源码实现印证

On.Days.cs 中August类开头的实现为:

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

可见每个属性本质上都是new DateTime(DateTime.Now.Year, 8, dayNumber)的语法糖封装,属性的 Ordinalize 后缀只是为了让调用点读起来更像人话。测试用例 OnTests.cs 验证了这一行为模式(以其他月份为例):

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

测试确认了"属性/方法返回值 = 当年 + 指定月份 + 指定日"这一等式。

三、动态方法:The(int dayNumber)

除 31 个固定属性外,On.August还提供一个参数化方法,用于获取 8 月任意一天:

public static System.DateTime The(int dayNumber);
  • 参数dayNumber:System.Int32类型,表示 8 月内的天数(1 到 31)。
  • 返回值:System.DateTime,即当年 8 月dayNumber日的零点时刻。

使用示例:

DateTime d1 = On.August.The(1); // 当年 8 月 1 日 DateTime d2 = On.August.The(15); // 当年 8 月 15 日 DateTime d3 = On.August.The(31); // 当年 8 月 31 日

The(int)与The1st~The31st固定属性的关系是:固定属性是The(int)对 1~31 各参数值的预生成特化。二者底层实现完全一致,都走new(DateTime.Now.Year, 8, dayNumber)这条路径,差别只在于调用点的可读性——On.August.The23rd比On.August.The(23)更接近自然语言。当日期在循环、配置驱动等动态场景中才能确定时,应使用The(int);当日期是写死的常量时,优先使用固定属性以获得最佳可读性。

需要提醒的是,如果传入超出 1~31 范围的值(如The(0)或The(32)),DateTime构造函数会抛出ArgumentOutOfRangeException,因为 8 月没有对应的日期。使用动态方法时应对输入做合法性校验。

四、实现原理:T4 模板自动生成

On.August及另外 11 个月份类并非手写代码,而是由 T4 文本模板(Text Template Transformation Toolkit)批量生成的。生成模板位于 On.Days.tt,其核心逻辑为:

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> { ... } 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>); } }

这段模板揭示了三个重要事实:

  1. 年份基准采用 2012 闰年:模板以 2012 年作为"标尺"来计算每个月的天数,因为 2012 是闰年,能覆盖 2 月 29 日这一极端情况。月份名通过new DateTime(2012, month, 1).ToString("MMMM")获得本地化英文名,从而生成January~December12 个嵌套类。
  2. 天数由DateTime.DaysInMonth决定:每个类生成多少个TheNth属性,取决于该月在 2012 年有多少天。8 月有 31 天,因此August恰好生成 31 个属性;而 2 月因闰年会生成 29 个属性。
  3. 序数后缀由Ordinalize()产生:属性名中的1st/2nd/3rd/th后缀正是 Humanizer 自身的 OrdinalizeExtensions 能力在生成期内的复用——库用它生成自己的 API,属于"自举"(dogfooding)设计。

这意味着On.August的完整形态(31 属性 + 1 方法)全部由模板在构建期展开,最终产物是 On.Days.cs 中约 2345 行代码的一部分,开发者无需手工维护每个日期访问器。

五、On 与 OnDate:DateTime 与 DateOnly 双版本

除了返回System.DateTime的On系列,Humanizer 还提供了面向System.DateOnly的OnDate系列(OnDate.August、OnDate.August.The1st等),其定义在 OnDate.Days.cs:

public class August { public static DateOnly The(int dayNumber) => new(DateTime.Now.Year, 8, dayNumber); public static DateOnly The1st => new(DateTime.Now.Year, 8, 1); // ... The2nd ~ The31st }

OnDate系列的特点与使用建议:

  • 仅在 .NET 6 及以上目标框架可用。生成模板 OnDate.Days.tt 开头使用#if NET6_0_OR_GREATER指令包裹,低于该版本的编译目标不会包含OnDate类型。
  • 返回值类型为DateOnly(纯日期、无时间分量),而On系列返回DateTime(含零点时间分量)。如果你的业务只需要"某年某月某日"这一概念(如生日、纪念日、排期),优先用OnDate以避免无意义的时间分量;如果需要与DateTime.Now直接比较或参与时间运算,则用On。
  • 两者的月份类结构、属性命名、生成方式完全对称,OnDate.August同样拥有The1st~The31st与The(int)全部成员。

六、实战使用示例

6.1 获取指定日期

using Humanizer; // 当年 8 月 23 日(属性方式,可读性最佳) DateTime meetingDay = On.August.The23rd; // 当年 8 月 1 日与 8 月 31 日 DateTime monthStart = On.August.The1st; DateTime monthEnd = On.August.The31st; // 动态天数(变量方式) int targetDay = 15; DateTime dynamicDay = On.August.The(targetDay); // .NET 6+ 使用 DateOnly 版本 DateOnly anniversary = OnDate.August.The23rd;

6.2 计算距离某个 8 月日期的剩余天数

TimeSpan remaining = On.August.The31st - DateTime.Today; Console.WriteLine($"距当年 8 月 31 日还有 {remaining.Days} 天");

6.3 与 Humanizer 其他 API 组合使用

On.August返回的DateTime可以无缝接入 Humanizer 的其他扩展,例如用 DateHumanizeExtensions 做相对时间描述:

Console.WriteLine(On.August.The1st.Humanize()); // 例如 "3 days from now" Console.WriteLine(On.August.The1st.Ordinalize()); // 例如 "August 1st"

七、使用注意事项

  1. 年份是动态的:On.August.The23rd返回的是"当前年份"的 8 月 23 日,其年份取自DateTime.Now.Year。跨年运行时(如程序跨越 12 月 31 日持续运行),两次调用的返回值年份可能不同,这一点在缓存计算结果、日志落库等场景中要特别留意。
  2. 返回时刻为当天零点:On系列返回的DateTime时间分量为00:00:00,即当天的开始时刻;需要当天其他时刻时请在此基础上自行AddHours等操作。
  3. 参数范围校验:The(int dayNumber)仅接受 1~31 的合法天数,越界会抛出ArgumentOutOfRangeException。
  4. OnDate的框架门槛:OnDate系列仅在NET6_0_OR_GREATER目标下编译产出,若项目目标框架低于 .NET 6,请使用On系列。
  5. 可读性与动态性取舍:固定属性(The23rd)适合字面量日期,The(int)适合动态计算出的日期,二者返回值语义完全等价。

八、相关资源导航

  • API 参考文档:Humanizer.On.August.md
  • 生成源码:On.Days.cs(August类自第 1370 行起)
  • 生成模板:On.Days.tt
  • DateOnly 版本生成源码:OnDate.Days.cs
  • DateOnly 版本生成模板:OnDate.Days.tt
  • 单元测试:OnTests.cs 与 OnDateTests.cs
  • 其他月份类:On.January~On.December同位于 On.Days.cs,结构与On.August完全一致,仅月份参数与天数不同。
  • 开发工具

【免费下载链接】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:模块化AI视频生成框架的技术解析与实践指南
下一篇:快速上手抖音无水印下载:douyin-downloader 单条、批量与直播下载教程

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 8:15:51

CoppeliaSim 4.2 (V-REP) 添加3D轨迹:用 TaoToken 统一 Key 打通脚本配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华