news 2026/9/27 21:28:58

Humanizer OnDate 流式日期访问器详解:用 DateOnly 优雅表达“某月某日“

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Humanizer OnDate 流式日期访问器详解:用 DateOnly 优雅表达“某月某日“
  • 开发工具

【免费下载链接】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 的 FluentDate 子模块为 .NET 开发者提供了一套"自然语言式"的日期构建 API。本文聚焦其中的OnDate类:它通过嵌套的月份类型与The(int)、The1st~The31st等一系列静态成员,让你在 .NET 6+ 项目中以近乎口语的方式直接构造DateOnly实例。读完本文,你将掌握OnDate的完整成员构成、它与On/In/InDate的关系、底层代码生成原理,以及如何在测试与业务代码中正确使用这套流式 API。

OnDate 类概述

OnDate是 Humanizer 中负责"用流式语法表达某个日期"的公开类,定义如下:

public class OnDate

它继承自System.Object,位于Humanizer命名空间下,因此只要项目引用了 Humanizer 包,即可直接使用OnDate.January.The23rd这样的写法。该类的全部实现位于 src/Humanizer/FluentDate/OnDate.Days.cs,并且整个文件被#if NET6_0_OR_GREATER条件编译指令包裹——这意味着它依赖 .NET 6 引入的System.DateOnly类型,仅在 .NET 6 及以上目标框架(TFM)中可用。

从类结构看,OnDate本身是一个纯静态外观(facade)容器,其真正的访问能力来自嵌套其中的 12 个月份类型:January、February、March、April、May、June、July、August、September、October、November、December。每个月份类型都对应"当前年份中该月的某一天"这一语义。

月份嵌套类型与两种访问方式

以 OnDate.Days.cs 中的January为例,可以看到每个月份类型都提供两类静态成员:

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

1. 动态方法:The(int dayNumber)

  • 签名:public static DateOnly The(int dayNumber)
  • 语义:返回当前年份中该月的第dayNumber天;
  • 取值范围:1 到该月实际天数。传入超出范围的值会由new DateTime(...)的构造逻辑抛出ArgumentOutOfRangeException(如 2 月传入 31);
  • 典型用途:当日期数字来自变量、循环或用户输入时使用,例如OnDate.February.The(11)。

2. 静态属性:The1st~The31st

  • 语义:为每月的每一天生成一个命名属性,如The1st、The2nd……The31st;
  • 覆盖范围:按月实际天数生成。1 月、3 月等大月生成到The31st,2 月仅生成到The28th(模板基于闰年 2012 计算DateTime.DaysInMonth,平年 2 月 29 日通过The(int)才能表达);
  • 命名风格:采用英文序数词格式(1st、2nd、3rd、4th…),与Humanizer.Ordinalize()扩展的输出一致;
  • 典型用途:表达固定不变的"纪念日"式日期,如OnDate.December.The25th表示"今年圣诞节"。

源码级实现:T4 模板生成与 DateOnly 语义

OnDate.Days.cs并非手写维护的 2300 多行代码,而是由 T4 文本模板 src/Humanizer/FluentDate/OnDate.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"); // 生成月份嵌套类型 for (var day = 1; day <= DateTime.DaysInMonth(leapYear, month); day++) { var ordinalDay = day.Ordinalize(); // 生成 TheNth 属性 } }

这段模板说明了三件事:

  1. 月份命名:借助DateTime.ToString("MMMM")输出英文月份名(January…December),因此月份类型名与当前区域性设置相关;
  2. 天数上限:以 2012 这个闰年为基准调用DateTime.DaysInMonth,保证 2 月 29 日(The29th)能被生成出来,而平年 2 月只有 28 天;
  3. 序数词生成:day.Ordinalize()复用了 Humanizer 自身的序数词扩展,与The1st/The2nd的命名保持一致。

每个访问器最终都收敛到一行构造代码:

=> new(DateTime.Now.Year, <month>, <day>);

注意这里显式使用了DateTime.Now.Year,即"当前年份",这是OnDate与下面将要对比的On系列共同的核心语义:它们永远指向"今年"的某一天,而不是任意年份。

与 On、In、InDate 的关系:一套 API 的四种形态

FluentDate 模块围绕"用英文介词表达时间"这一设计,提供了四个相互对照的入口类,全部位于 src/Humanizer/FluentDate 目录:

类返回类型语义源码文件
OnDateTime今年某月某日(可变日期时间)On.Days.cs
OnDateDateOnly今年某月某日(仅日期)OnDate.Days.cs
InDateTime今年某月第一天等In.Months.cs、In.SomeTimeFrom.cs
InDateDateOnly今年某月第一天等InDate.Months.cs、InDate.cs
  • OnvsOnDate:两者成员结构完全一致(On也有January.The(int)、January.The1st等),唯一差别是返回类型——On返回DateTime(带时间部分,时间默认为零点),OnDate返回DateOnly。On的实现位于 On.Days.cs,同样由 On.Days.tt 生成,但不限定 .NET 6;
  • InvsInDate:In/InDate语义为"某月(的第一天)",例如In.April表示今年 4 月 1 日;InDate同样仅在NET6_0_OR_GREATER下编译(见 InDate.Months.cs)。OnDate与InDate的区别可概括为:OnDate精确到"日",InDate只到"月的第一天"。

由此可以总结选型建议:目标框架为 .NET 6+、且只需要"日期"概念时优先用OnDate/InDate;需要与DateTimeAPI 混用、或目标框架为 .NET Framework/.NET Core 3.1 时,使用On/In。

实战示例:从构造到断言

基础用法

using Humanizer; // 今年 1 月 23 日(DateOnly) DateOnly jan23 = OnDate.January.The23rd; // 今年 2 月 11 日(动态天数) DateOnly feb11 = OnDate.February.The(11); // 今年 12 月 25 日 DateOnly christmas = OnDate.December.The25th; // 与 InDate 对照:今年 4 月 1 日 DateOnly aprilFirst = InDate.April;

与现有日期逻辑衔接

DateOnly可以直接参与比较、作为数据库(如 EF Core 8+ 的date列)映射类型:

if (OnDate.January.The1st == DateOnly.FromDateTime(DateTime.Now)) { // 今天是今年元旦 }

测试侧验证

Humanizer 官方测试在 tests/Humanizer.Tests/FluentDate/OnDateTests.cs 中对该 API 做了直接断言,例如:

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

更全面的覆盖见 GeneratedFluentDateTests.cs(该文件同样由生成逻辑产出,逐月逐日验证TheNth属性)。由于实现依赖DateTime.Now.Year,测试只断言"年份与当前一致",这也提示了一个使用注意点:测试中不要硬编码具体年份,除非先 mock 掉时钟。

使用注意事项与边界

  1. 年份语义:OnDate所有成员都基于DateTime.Now.Year,无法直接表达"明年/去年某日"。跨年份的日期需要自行组合,例如new DateOnly(DateTime.Now.Year + 1, 12, 25),或借助InDate.TheYear(int)(见 InDate.cs)表达"某年 1 月 1 日";
  2. 框架限制:OnDate仅对NET6_0_OR_GREATER目标框架编译,老框架请使用返回DateTime的 On.Days.cs;
  3. 月份类型与属性数量:12 个月份类型中,属性生成数量按 2012 闰年计算,因此 2 月含The29th,但平年调用它会在运行时构造失败;大月与小月属性个数不同(31 天 vs 30 天);
  4. 可读性收益:OnDate.January.The1st比new DateOnly(DateTime.Now.Year, 1, 1)更具自描述性,尤其适合在领域规则、报表默认值、配置默认日期等位置使用,使代码贴近业务语言。

小结

OnDate是 Humanizer FluentDate 家族中专为 .NET 6+DateOnly场景设计的流式日期构造器:通过 12 个嵌套月份类型 +The(int)方法 +The1st~The31st命名属性,把"今年某月某日"的构造过程变成了可读性极强的链式表达式。其源码由 OnDate.Days.tt 模板生成、由 OnDate.Days.cs 承载实现、并由 OnDateTests.cs 与 GeneratedFluentDateTests.cs 双重验证。当你需要把"特定日期"写进代码且希望它读起来像一句英文时,OnDate就是 Humanizer 给出的答案。

  • 开发工具

【免费下载链接】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
点击查看免费下载
上一篇:百度ERNIE-4.5-VL-28B-A3B-Base-PT深度解析:多模态路由优化技术架构与实现
下一篇:如何免费使用AI视频放大神器Video2X:3步让老旧视频重获新生

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

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

5个坑教你搞定婚介网站建设的策划最佳实践

5个坑教你搞定婚介网站建设的策划最佳实践 域名选错、服务器配置混乱,这是新手做婚介站最容易翻车的两个点。很多老板花几万块做完网站,打开速度比蜗牛还慢,甚至直接打不开,根本原因就在这。搞懂这俩,才是婚介网站建设的策划里的 最佳实践 。 需求分析:别把相亲站做成商城…

作者头像 李华
网站建设 2026/9/27 21:28:54

商务网站设计与制作:一文搞懂SEO与备案避坑指南

商务网站设计与制作:一文搞懂SEO与备案避坑指南 很多项目经理在接手新项目时,最怕听到的不是预算削减,而是客户问:“为什么我的商务网站设计与制作做完后,百度搜不到?”或者更让人头疼的——“备案号下来了吗?”…

作者头像 李华
网站建设 2026/9/27 21:28:48

一文搞懂wordpress用户中心按钮不弹出,3招解决

一文搞懂wordpress用户中心按钮不弹出,3招解决 网站被黑挂马不知道怎么办?别慌,先别急着删库重装。很多站长一看到后台报错或者前台页面异常,第一反应就是服务器被拖了,其实大部分情况下,是代码冲突或者权限配置出了问题。以WordPress用户中心按钮不弹出为例,这种前端交互失效往往隐藏着更深层的…

作者头像 李华
网站建设 2026/9/27 21:28:10

小白从零搭建WordPress网站,避开wordpressseo教程网的3大坑

小白从零搭建WordPress网站,避开wordpressseo教程网的3大坑 自己不会代码,想做网站却总被劝退?别慌,这正是你需要的实战指南。很多新手拿着“wordpressseo教程网”这种关键词去搜教程,结果陷入信息迷宫,要么买错模板,要么服务器配置一塌糊涂。其实, 从零搭建…

作者头像 李华