尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Humanizer 的 Tense 枚举:相对时间表达中过去与未来的语义枢纽

Humanizer 的 Tense 枚举:相对时间表达中过去与未来的语义枢纽 开发工具【免费下载链接】HumanizerHumanizer 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 2.11.10 版本 API 文档中的Humanizer.Localisation.Tense枚举展开讲解它在日期人性化Date Humanize链路中的角色、定义方式、底层调用关系以及本地化实现原理。读完你将掌握Tense的语义、它与TimeUnit、IFormatter的协作方式以及如何在多语言环境下利用它实现 2 days ago / in 2 days 这类相对时间表达。一、Tense 是什么一次相对时间引用的“时态开关”Humanizer 是一个专注于把字符串、枚举、日期、时间、时长、数字和数量转换为人类可读形式的 .NET 库。其中将DateTime与当前时间或指定基准时间的差值表达为自然语言是它最常用的能力之一——例如把DateTime.UtcNow.AddDays(-2)输出为 2 days ago把DateTime.UtcNow.AddDays(3)输出为 in 3 days。要完成这种表达引擎必须先回答一个基础问题被描述的相对时间点落在基准时刻之前还是之后这正是Tense枚举的职责。根据 2.11.10 版 API 文档Humanizer.Localisation.Tense.mdTense枚举“枚举了可能的时间引用过去或未来”Enumerates the possible time references; past or future包含两个字段字段值含义Future0指示未来Indicates the futurePast1指示过去Indicates the past对应的源码定义位于 src/Humanizer/Localisation/Tense.csnamespace Humanizer; /// summary /// Indicates whether a relative time reference is in the past or the future. /// /summary public enum Tense { /// summary /// A future reference such as in 2 days. /// /summary Future, /// summary /// A past reference such as 2 days ago. /// /summary Past }从源码注释可以直观地看到两个成员的典型输出Future对应 in 2 days 这类将来表达Past对应 2 days ago 这类过去表达。二、Tense 在人性化调用链中的位置Tense并不是一个需要开发者直接调用的 API而是被 Humanizer 内部算法计算并向下传递的“语义参数”。它的完整调用链如下1. 入口DateHumanizeExtensions.Humanize开发者通过扩展方法发起人性化请求例如DateTime.Humanize()。在 src/Humanizer/DateHumanizeExtensions.cs 中Humanize先确定比较基准时间默认DateTime.UtcNow然后委托给策略对象public static string Humanize(this DateTime input, bool? utcDate null, DateTime? dateToCompareAgainst null, CultureInfo? culture null) { var comparisonBase dateToCompareAgainst ?? DateTime.UtcNow; utcDate ?? input.Kind ! DateTimeKind.Local; comparisonBase utcDate.Value ? comparisonBase.ToUniversalTime() : comparisonBase.ToLocalTime(); return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture); }2. 计算DateTimeHumanizeAlgorithms判定 Tense无论是默认策略还是精度策略最终都会进入 src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs 的核心算法。算法首先通过时间比较得出时态方向var tense input comparisonBase ? Tense.Future : Tense.Past; var ts new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks));也就是说只要input晚于基准时间tense就是Tense.Future否则就是Tense.Past。这个判断对DateTime、DateTimeOffset以及 .NET 6 的DateOnly、TimeOnly都是统一的见PrecisionHumanize与DefaultHumanize的多组重载。测试侧也印证了这一点——tests/Humanizer.Tests/DateHumanize.cs 中Verify辅助方法在tense Tense.Past时把单位取负以构造“基准时间之前”的增量if (tense Tense.Past) { unit -unit; }3. 下钻按单位分级并携带 Tense 调用 Formatter算出Tense后算法按“从大到小”的优先级年 → 月 → 日 → 时 → 分 → 秒 → 毫秒确定TimeUnit然后调用格式化器var formatter Configurator.GetFormatter(culture); if (years 0) { return formatter.DateHumanize(TimeUnit.Year, tense, years); } // ... 其余单位同理这里TimeUnit定义于 src/Humanizer/Localisation/TimeUnit.cs负责“单位是什么”而Tense负责“方向是过去还是未来”两者共同决定了最终短语。三、IFormatter 如何消费 Tense接口契约与默认实现Tense被正式消费的位置是本地化格式化接口IFormatter。在 src/Humanizer/Localisation/Formatters/IFormatter.cs 中接口方法明确把Tense作为参数/// summary /// Returns the localized representation of a relative date phrase. /// /summary /// param nametimeUnitThe unit being described./param /// param nametimeUnitTenseWhether the reference is in the past or the future./param /// param nameunitThe number of units being described./param string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit);默认实现 src/Humanizer/Localisation/Formatters/DefaultFormatter.cs 在拿到(TimeUnit, Tense, unit)三元组后会先去本地化短语表中查词public virtual string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit) TryFormatDateFromPhraseTable(timeUnit, timeUnitTense, unit, out var result) ? result : throw new InvalidOperationException($Missing generated relative-date phrase for {Culture.Name} and unit {timeUnit}.);短语表查找逻辑TryFormatDateFromPhraseTable会依次处理几个分支见 DefaultFormatter.cscount 0直接返回“现在”类短语如 nowcount 1优先使用单数专用短语如 yesterday / tomorrow其余情况取复数形式模板把数量值嵌入短语如 2 days ago / in 2 days。如果当前文化在短语表中找不到对应条目DefaultFormatter会抛出InvalidOperationException提示缺失了哪个文化、哪个单位的相对日期短语——这保证了“查不到词”时不会静默输出错误文本。四、Tense 与本地化数据以 en.yml 为例看 past / future 分支Tense的语义最终映射到每种语言的本地化资源中。Humanizer 的短语表由src/Humanizer/Locales/*.yml这一大批 YAML 文件提供以en.yml为例见 src/Humanizer/Locales/en.yml其relativeDate节点下明确按past与future两个方向组织数据relativeDate: now: now today: today never: never past: second: single: one second ago multiple: afterCount: ago forms: singular: second default: seconds day: single: yesterday multiple: afterCount: ago forms: singular: day default: days future: second: single: one second from now multiple: afterCount: from now forms: singular: second default: seconds day: single: tomorrow multiple: afterCount: from now forms: singular: day default: days从这份数据可以看出Tense与短语生成的对应关系场景组合英文输出示例过去 1 秒PastSecond 1one second ago过去 2 天PastDay 22 days ago未来 1 天FutureDay 1tomorrow未来 3 小时FutureHour 3in 3 hours由模板/占位符渲染值得注意的细节单数短语可以完全脱离常规句式——英语的Past Day 1输出 yesterday 而不是 one day agoFuture Day 1输出 tomorrow 而不是 one day from now。这正是TryFormatDateFromPhraseTable中count 1优先匹配single短语的体现也是本地化数据里single与multiple分开建模的原因。复数形式的afterCount字段如 ago / from now则负责把方向性词缀拼接到数量短语之后。从源码结构看这套past/future双分支模型在各语言的 YAML 中保持一致zh-CN.yml、ja.yml、de.yml等几十种语言文件都遵循同样的结构只是具体词汇不同。这意味着Tense抽象让“过去/未来”这一语义方向在任何语言下都有一致的程序化表达。五、高级场景ProfiledFormatter 中的时态感知规则除默认实现外仓库还提供了对特定语言进行细粒度定制的ProfiledFormatter。在 src/Humanizer/Localisation/Formatters/ProfiledFormatter.cs 中可以看到一个内部的FormatterTenseMask枚举含Future/Past掩码位以及把Tense映射为掩码的辅助方法static FormatterTenseMask GetTenseMask(Tense tense) tense Tense.Future ? FormatterTenseMask.Future : FormatterTenseMask.Past;这类“时态掩码”配合FormatterDateFormRule见 ProfiledFormatter.cs使用public bool AppliesTo(TimeUnit unit, Tense tense, int number) // 匹配单位掩码 (Units GetUnitMask(unit)) ! 0 // 匹配时态掩码 (Tenses GetTenseMask(tense)) ! 0;从实现看某些语言如斯拉夫语系的复数形式singular / paucal / plural 等会随数量变化而某些语言在“未来”和“过去”方向上的用词规则并不对称因此需要按(TimeUnit, Tense, number)组合配置不同的短语形态规则。ProfiledFormatter通过掩码规则实现“同一单位、不同时态、不同数量”的差异化选择这正是Tense枚举在高级本地化中的核心用途。六、实践要点与常见误区综合以上分析使用与理解Tense时有几点值得注意无需直接使用Tense是内部语义参数日常开发只需要调用Humanize()扩展方法时态方向由算法自动判定。例如// 输出形如 2 days ago DateTime.UtcNow.AddDays(-2).Humanize(); // 输出形如 in 3 days DateTime.UtcNow.AddDays(3).Humanize();方向判定规则是input base只要输入时间严格晚于基准时间即为Future否则为PastDateTime、DateTimeOffset、DateOnly、TimeOnly均遵循同一规则。时态与单位是正交维度TimeUnit决定“讲的是秒、分钟、小时还是年”Tense决定“往过去还是往未来讲”两者在IFormatter.DateHumanize(TimeUnit, Tense, int)中作为独立参数组合使用。本地化数据的双分支结构任何语言的relativeDate节点下都必须从结构上同时提供past与future两个分支单数短语如 yesterday/tomorrow 也在各自分支中独立建模因此即使某个语言没有独立词汇也会回退到常规句式模板。缺失短语会抛异常而非静默DefaultFormatter.DateHumanize在短语表缺失条目时抛出InvalidOperationException提示缺失的文化与单位便于排查本地化数据问题。七、总结Humanizer.Localisation.Tense是 Humanizer 相对时间人性化能力中一个“小却关键”的枚举它以两个成员Future 0、Past 1概括了所有相对时间引用在时间轴上的方向并贯穿“日期人性化算法 → 格式化器接口 → 本地化短语表”的完整调用链。理解它就理解了 2 days ago 与 in 2 days 背后的语义建模方式也为深入阅读 DateTimeHumanizeAlgorithms.cs、IFormatter.cs 与各语言 Locales 资源提供了清晰的地图。赞分享开发工具【免费下载链接】HumanizerHumanizer 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 的 Tense 枚举过去与未来相对时间引用背后的实现机制Humanizer 的 Tense 枚举过去与未来相对时间引用背后的实现机制 本篇技术指南聚焦 Humanizer 项目中的 Tense 枚举 Humani开发工具Humanizer.Tense 枚举解析过去与未来的相对时间表达在 Humanizer 中的完整机制Humanizer.Tense 枚举解析过去与未来的相对时间表达在 Humanizer 中的完整机制 本篇技术指南聚焦 Humanizer 中 Tense 枚开发工具Humanizer 的 Tense 枚举深入解析过去与未来时态在 .NET 时间人性化中的定位与用法Humanizer 的 Tense 枚举深入解析过去与未来时态在 .NET 时间人性化中的定位与用法 导读 Tense 是 Humanizer 本地化Loc开发工具上一篇JupyterLab-LSP 语言服务器完全配置手册支持Python、R、JavaScript等下一篇gogcli 读取 Google Sheets 数据源表Connected Sheets Extractgog sheets datasource table read 实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表