- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
本篇技术指南以 Humanizer 的InDate.Seven类为核心,系统讲解 Humanizer FluentDate API 中"从现在起 7 天、7 周、7 个月、7 年之后"这一组日期计算能力:包括 4 个静态属性(Days、Weeks、Months、Years)与 8 个静态方法(DaysFrom等,各自提供DateOnly与DateTime两种重载)。读完本文,你将掌握InDate.Seven每个成员的确切签名、返回语义与底层实现原理,并能与In(基于DateTime的兄弟类)、InDate.Five等相邻 API 对照使用,写出可读性更强的日期偏移代码。
InDate.Seven 是什么:FluentDate 中的"七"号门面
Humanizer 提供了一组以自然语言命名的 FluentDate API,让日期计算代码读起来像一句英文短语。InDate.Seven是其中专门表达"7"这个数量单位的嵌套静态类,命名空间为Humanizer:
public static class InDate.Seven从继承关系看,它直接继承自System.Object(InDate是一个public partial class,内部嵌套了一组数字类One到Ten)。与返回DateTime的In.Seven不同,InDate.Seven的全部成员都返回System.DateOnly——只携带"年/月/日",不携带时刻与时区信息,适用于日历日级别的计算场景。
需要特别注意的是,InDate系列的源码被#if NET6_0_OR_GREATER条件编译指令包裹(见 InDate.SomeTimeFrom.cs),因为DateOnly是 .NET 6 才引入的 BCL 类型。也就是说,InDate.Seven仅在 .NET 6 及更高版本的运行时可用;面向旧版本框架的项目应改用In.Seven(返回DateTime,定义于 In.SomeTimeFrom.cs)。
四个静态属性:从"现在"起算的日期
InDate.Seven暴露了 4 个只读静态属性,全部以DateTime.UtcNow(UTC 当前时刻)为基准向后偏移,再经DateOnly.FromDateTime截取日期部分。下表汇总了每个属性的语义与底层调用:
| 属性 | 含义 | 返回类型 | 底层实现(对应 InDate.SomeTimeFrom.cs) |
|---|---|---|---|
Days | 7 天后的今天 | System.DateOnly | DateOnly.FromDateTime(DateTime.UtcNow.AddDays(7)) |
Weeks | 7 周后的今天 | System.DateOnly | DateOnly.FromDateTime(DateTime.UtcNow.AddDays(49)) |
Months | 7 个月后的今天 | System.DateOnly | DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(7)) |
Years | 7 年后的今天 | System.DateOnly | DateOnly.FromDateTime(DateTime.UtcNow.AddYears(7)) |
使用方式非常简单:
using Humanizer; DateOnly sevenDaysLater = InDate.Seven.Days; // 例如 2026-09-24 → 2026-10-01 DateOnly sevenWeeksLater = InDate.Seven.Weeks; // 49 天后 DateOnly sevenMonthsLater = InDate.Seven.Months; // 7 个自然月后 DateOnly sevenYearsLater = InDate.Seven.Years; // 7 年后两个细节值得留意:
- UTC 基准:属性基于
DateTime.UtcNow计算,而不是本地时间。如果调用方期望"本地时区的 7 天后",结果可能与本地日历相差一天(取决于时区偏移),这一点从源码中的DateTime.UtcNow调用可以得到直接印证。 - 周 = 自然日叠加:
Weeks不是调用AddDays(7 * 7)之外的任何"周"语义,而是纯粹的AddDays(49),与Days一样按日历日推进。
八个静态方法:从"指定日期"起算
除了基于当前时刻的属性,InDate.Seven还提供 8 个静态方法,允许以任意给定日期为基准计算偏移。每个时间单位都有DateOnly重载与DateTime重载两个版本,完整清单如下:
DaysFrom —— 7 天后的日期
public static System.DateOnly DaysFrom(System.DateOnly date); public static System.DateOnly DaysFrom(System.DateTime date);DaysFrom(DateOnly date):返回date.AddDays(7),直接对DateOnly做天数加法。DaysFrom(DateTime date):返回DateOnly.FromDateTime(date.AddDays(7)),先对DateTime加 7 天,再截取日期部分。
WeeksFrom —— 7 周后的日期
public static System.DateOnly WeeksFrom(System.DateOnly date); public static System.DateOnly WeeksFrom(System.DateTime date);WeeksFrom(DateOnly date):返回date.AddDays(49)。WeeksFrom(DateTime date):返回DateOnly.FromDateTime(date.AddDays(49))。
MonthsFrom —— 7 个月后的日期
public static System.DateOnly MonthsFrom(System.DateOnly date); public static System.DateOnly MonthsFrom(System.DateTime date);MonthsFrom(DateOnly date):返回date.AddMonths(7),遵循"自然月"语义(例如 1 月 31 日 + 7 个月,会按 .NET 的AddMonths规则做月末截断)。MonthsFrom(DateTime date):返回DateOnly.FromDateTime(date.AddMonths(7))。
YearsFrom —— 7 年后的日期
public static System.DateOnly YearsFrom(System.DateOnly date); public static System.DateOnly YearsFrom(System.DateTime date);YearsFrom(DateOnly date):返回date.AddYears(7),闰日(2 月 29 日)会按AddYears的规则收敛。YearsFrom(DateTime date):返回DateOnly.FromDateTime(date.AddYears(7))。
典型用法:
using Humanizer; DateOnly dueDate = new(2026, 9, 24); DateOnly newDate1 = InDate.Seven.DaysFrom(dueDate); // 2026-10-01 DateOnly newDate2 = InDate.Seven.WeeksFrom(dueDate); // 2026-11-12 DateOnly newDate3 = InDate.Seven.MonthsFrom(dueDate); // 2027-04-24 DateOnly newDate4 = InDate.Seven.YearsFrom(dueDate); // 2033-09-24 // DateTime 重载:自动剥掉时刻,只保留日期 DateOnly newDate5 = InDate.Seven.DaysFrom(new DateTime(2026, 9, 24, 15, 30, 0)); // 2026-10-01DateOnly 与 DateTime 两种重载的取舍
同一单位出现两个重载并非冗余,而是对应两种常见调用场景:
- 传入
DateOnly:输入本身就只有日历语义,方法内部直接调用DateOnly.AddDays / AddMonths / AddYears,不经过任何转换,路径最直接(源码见 InDate.SomeTimeFrom.cs)。 - 传入
DateTime:输入携带时刻(甚至Kind属性),方法先用Add*完成偏移,再通过DateOnly.FromDateTime丢弃时刻部分。这样设计保证了"无论传入什么时刻,结果永远是纯日期"。
如果你的代码上游只有DateTime(例如从数据库或DateTime.Now获取的值),可以直接使用DateTime重载而无需手动DateOnly.FromDateTime转换;如果上游已经是DateOnly(.NET 6+ 的日历型数据),则优先选择DateOnly重载,语义更精确、零转换开销。
源码深挖:T4 模板如何批量生成 One 到 Ten
InDate.Seven并不是手写一次就完事,它与InDate.One到InDate.Ten全部由同一个 T4 文本模板批量生成。打开 InDate.SomeTimeFrom.tt 可以看到核心循环逻辑:
for (var i = 1; i <= 10; i++) { var plural = i > 1 ? "s" : ""; // 类名通过 i.ToWords().Dehumanize() 生成:1 → One、7 → Seven public static class <#= i.ToWords().Dehumanize() #> { // Days / Weeks / Months / Years 及其 From 方法 } }这个模板揭示了几个工程细节:
- 类名自动生成:
i.ToWords()把数字转成英文单词(7→seven),再经Dehumanize()变成 PascalCase 的Seven,最终得到InDate.Seven。 - 单复数约定:
One内部的成员是单数形式(Day、Week、Month、Year),而Two到Ten(含Seven)统一使用复数形式(Days、Weeks、Months、Years)。模板中的plural变量正是为此而设。 - 周数按天折算:
Weeks的模板代码是DateTime.UtcNow.AddDays(i * 7),因此Seven.Weeks固定等于AddDays(49),与手写实现完全一致。 - 配套的 DateTime 版本:同目录下的 In.SomeTimeFrom.cs(及对应的 In.SomeTimeFrom.tt)用同样的模板思路生成
In.One到In.Ten,但返回类型是DateTime而非DateOnly,两个门面类互为补充。
测试验证:生成代码的行为契约
仓库测试对这批生成的相对日期 API 做了系统性的契约校验,可作为使用时的行为依据:
- InDateTests.cs 中的
InFiveDays用例验证了组合用法:先用OnDate.January.The21st构造基准日期,再调用InDate.Five.DaysFrom(baseDate),断言结果等于baseDate.AddDays(5)——InDate.Seven的方法族遵循完全相同的偏移契约。 - GeneratedFluentDateTests.cs 通过反射遍历
InDate下所有嵌套类型:InDateRelativeDatePropertiesReturnExpectedUtcOffsets在调用前后各取一次DateTime.UtcNow,断言属性返回值落在[Add(before, amount, unit), Add(after, amount, unit)]区间内;InDateRelativeDateOnlyMethodsReturnExpectedOffsetsFromProvidedDate与InDateRelativeDateTimeMethodsReturnExpectedOffsetsFromProvidedDateTime则分别验证两类From方法。其中RelativeAmounts字典把"Seven"映射为7(见 GeneratedFluentDateTests.cs),正是这套反射校验的数据来源。
使用注意与延伸阅读
- 适用框架:
InDate.Seven依赖DateOnly,仅存在于 .NET 6 及以上目标框架;In.Seven则面向所有框架版本。 - 时区语义:四个属性基于 UTC 计算;需要本地时区语义时,请使用
From方法并传入本地日期。 - 月份/年份边界:
Months、Years沿用 .NETAddMonths/AddYears的边界收敛规则(如月末、闰日),不会抛异常。 - 相邻 API:本文档同属 FluentDate 系列 API 文档,可对照
InDate的其他数字类(如 InDate.Five)与InDate的月份类(如 InDate.January 相关页面);需要"每年/每月的某个具体日期"时,可配合 InDate.cs 中的TheYear(int year)使用;若追求DateTime语义,参考 In.Seven。
一句话总结:InDate.Seven把"7 天/周/月/年后的日期"这一高频计算封装成自然语言级 API——用属性表达"从现在起",用From方法表达"从指定日期起",两者都返回纯DateOnly,让日期偏移代码既清晰又不易出错。
- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
相关推荐
Humanizer InDate.Seven 完全指南:用流式 API 一步算出 7 天/周/月/年后的日期
Humanizer InDate.Seven 完全指南:用流式 API 一步算出 7 天/周/月/年后的日期 InDate.Seven 是 Humanizer
开发工具Humanizer InDate.Four API 详解:用 DateOnly 构建"从某日起 4 天/周/月/年"的流式日期计算
Humanizer InDate.Four API 详解:用 DateOnly 构建"从某日起 4 天/周/月/年"的流式日期计算 本文基于 Humanizer
开发工具Humanizer InDate.Ten 详解:用 DateOnly 流式 API 计算 10 天/周/月/年后的日期
Humanizer InDate.Ten 详解:用 DateOnly 流式 API 计算 10 天/周/月/年后的日期 InDate.Ten 是 Humaniz
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考