ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Humanizer 的 DefaultDateTimeOffsetHumanizeStrategy 深度解析:DateTimeOffset 相对时间人文化的默认实现指南

Humanizer 的 DefaultDateTimeOffsetHumanizeStrategy 深度解析:DateTimeOffset 相对时间人文化的默认实现指南 开发工具【免费下载链接】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点击查看免费下载导读DefaultDateTimeOffsetHumanizeStrategy是 Humanizer 中负责把DateTimeOffset时间差转换为人类可读句子例如an hour from now、30 minutes ago的默认策略类。本文以其 API 参考文档为核心结合仓库源码与测试用例完整讲解该类的继承关系、Humanize方法签名与参数语义、底层分段量化算法、UTC 归一化处理、与扩展方法及Configurator的调用链并演示如何替换为精度策略、如何处理时区差异与多语言输出。读完后你将掌握 Humanizer 相对时间人文化的完整机制并能针对自己的业务场景定制策略。类概览定位与继承关系在 Humanizer 的文档体系中DefaultDateTimeOffsetHumanizeStrategy被定义为the default distance of time - words calculator默认的时间距离 → 文字计算器其 API 参考位于 Humanizer.DateTimeHumanizeStrategy.DefaultDateTimeOffsetHumanizeStrategy.md。其完整类声明为public class DefaultDateTimeOffsetHumanizeStrategy : Humanizer.DateTimeHumanizeStrategy.IDateTimeOffsetHumanizeStrategy命名空间Humanizer与接口所在的Humanizer.DateTimeHumanizeStrategy命名空间不同类本身直接位于根命名空间下继承链System.Object→DefaultDateTimeOffsetHumanizeStrategy没有额外的基类依赖实现的接口IDateTimeOffsetHumanizeStrategy。源码实现位于 src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeOffsetHumanizeStrategy.cs全文非常精简——整个类的核心逻辑只有一行调用真正复杂的计算被委托给了内部的算法工具类这一点下文会详细展开。Humanize 方法签名、参数与返回值该类只有一个公开方法也是其唯一对外能力public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo culture);方法说明为 Calculates the distance of time in words between two provided dates计算两个给定日期之间的时间距离并以文字形式返回。参数语义参数类型含义inputDateTimeOffset要被人文化的日期即需要描述其与基准之间距离的那个时间点comparisonBaseDateTimeOffset比较基准日期距离是相对它计算的cultureCultureInfo用于本地化输出的区域性。参考文档中该参数为非空类型实际源码声明为CultureInfo? culture可空传入null时表示使用当前线程的区域性返回值返回System.String即距离的文字描述。例如在美国英语文化下input比comparisonBase晚 1 小时会得到an hour from now早 30 分钟会得到30 minutes ago。源码实现一行委托背后的语义public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.DefaultHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, culture);这一行代码揭示了两个关键设计决策算法复用DateTimeOffset与DateTime两个版本共享同一个内部算法入口DateTimeHumanizeAlgorithms.DefaultHumanize定义于 src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs避免逻辑重复UTC 归一化两个输入都被转换为UtcDateTime后再参与计算这保证了不同时区偏移量Offset的DateTimeOffset之间可以正确比较——这正是DateTimeOffset场景下最容易出错的细节下文专节说明。底层算法DefaultHumanize 的分段量化逻辑DateTimeHumanizeAlgorithms.DefaultHumanize是整个策略的核心值得逐段分析。它首先根据输入大小关系确定时态Tense然后按时间跨度从小到大命中不同的输出区间。时态与跨度计算public static string DefaultHumanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) { var tense input comparisonBase ? Tense.Future : Tense.Past; var ts new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); var sameMonth comparisonBase.Date.AddMonths(tense Tense.Future ? 1 : -1) input.Date; var days Math.Abs((input.Date - comparisonBase.Date).Days); return DefaultHumanize(ts, sameMonth, days, tense, culture); }时态判定input晚于comparisonBase记为Tense.Future输出from now类文案否则记为Tense.Past输出ago类文案跨度计算取两者Ticks差值的绝对值构造TimeSpan同月判定比较comparisonBase前/后推一个月的日期是否等于input的日期用于 2830 天区间的特殊处理日差按DateTime.Date级别忽略时分秒计算天数差供天/周/月/年输出使用。分段量化表关键边界内部的DefaultHumanize(TimeSpan, bool, int, Tense, CultureInfo)重载见 DateTimeHumanizeAlgorithms.cs按以下阈值逐级返回条件输出单位数值总毫秒 500毫秒0如 now / 刚刚总秒 60秒ts.Seconds总秒 120分钟1a minute总分钟 60分钟ts.Minutes总分钟 90小时1an hour总小时 24小时ts.Hours总小时 48天日差1 天总天数 7天ts.Days总天数 28周ts.Days / 7总天数 ≥ 28 且 30月/天若sameMonth为 1 个月否则为天数总天数 345月floor(ts.TotalDays / 29.5)其余年floor(ts.TotalDays / 365)最小为 1从源码结构看这套阈值刻意模仿了日常口语的约数表达习惯90 分钟以内说一个小时而不是90 分钟48 小时以内说一天28 天到 30 天之间则根据是否跨月决定说一个月还是具体天数。月、年都采用近似平均长度29.5 天 / 月、365 天 / 年取整保证输出为自然整数。本地化输出最终所有分支都会调用var formatter Configurator.GetFormatter(culture); return formatter.DateHumanize(TimeUnit.Year, tense, years); // 以最大单位为例即通过 Configurator.cs 的Formatters注册表按culture解析出对应的IFormatter再调用DateHumanize(TimeUnit, Tense, int)生成词句。因此同样的时间差在不同语言下会自动输出本地化文案例如中文、日语、德语环境各自使用 src/Humanizer/Locales 下对应 yml 驱动的语言资源。时区处理为什么先转 UTCDateTimeOffset本身携带时区偏移量Offset两个值即使墙上时钟读数不同实际时刻也可能相同。DefaultDateTimeOffsetHumanizeStrategy在委托前统一执行input.UtcDateTime // 将 input 转为 UTC 时刻 comparisonBase.UtcDateTime // 将基准转为 UTC 时刻从源码结构看这一转换使得时间差计算完全基于绝对时刻从而保证跨时区场景的正确性。对应的测试用例 DateTimeOffsetHumanizeTests.cs 专门验证了这一行为DefaultStrategy_DifferentOffsetsinput为02:00的 03:00comparisonBase为01:00的 02:30实际时刻相差 30 分钟输出30 minutes agoDefaultStrategy_WeekAcrossDifferentOffsetsinput为-05:00的 2024-01-08 03:00comparisonBase为02:00的 2024-01-01 10:00跨了 6 天多输出one week from now。这些用例证明即便偏移量不同只要绝对时刻差值正确输出就准确。这是使用DateTimeOffset人文化时最重要的心智模型——比较的是时刻不是墙上时间。完整调用链扩展方法、策略注册与 ConfiguratorDefaultDateTimeOffsetHumanizeStrategy通常不直接调用而是通过扩展方法触发。完整链路如下input.Humanize(comparisonBase, culture); // ↓ 进入 DateHumanizeExtensions.Humanize(this DateTimeOffset, ...) // 见 src/Humanizer/DateHumanizeExtensions.csDateHumanizeExtensions.cs 中的实现为public static string Humanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst null, CultureInfo? culture null) { var comparisonBase dateToCompareAgainst ?? DateTimeOffset.UtcNow; return Configurator.DateTimeOffsetHumanizeStrategy.Humanize(input, comparisonBase, culture); }要点默认基准不传dateToCompareAgainst时以DateTimeOffset.UtcNow为基准因此DateTimeOffset.Now.Humanize()这类调用描述的是距离当前时刻的相对时间策略入口实际执行的是Configurator.DateTimeOffsetHumanizeStrategy属性见 Configurator.cs其默认值正是new DefaultDateTimeOffsetHumanizeStrategy()可空重载DateTimeOffset?的扩展方法在值为null时返回never通过formatter.DateHumanize_Never()测试用例Never验证了该行为。策略可插拔如何切换与定制IDateTimeOffsetHumanizeStrategy接口定义于 src/Humanizer/DateTimeHumanizeStrategy/IDateTimeOffsetHumanizeStrategy.cs只有Humanize(DateTimeOffset, DateTimeOffset, CultureInfo?)一个方法是实现自定义策略的唯一契约public interface IDateTimeOffsetHumanizeStrategy { string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture); }切换到精度策略仓库内置了另一套实现PrecisionDateTimeOffsetHumanizeStrategy见 src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeOffsetHumanizeStrategy.cs其构造函数接受double precision默认值为0.75public class PrecisionDateTimeOffsetHumanizeStrategy(double precision .75) : IDateTimeOffsetHumanizeStrategy { readonly double precision precision; public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.PrecisionHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, precision, culture); }与默认策略不同精度策略采用近似进位算法当小单位数值达到59 * precision、23 * precision、30 * precision、365 * precision等阈值时向上进位到更大单位见 DateTimeHumanizeAlgorithms.cs 中的PrecisionHumanize。例如测试用例PrecisionStrategy_TwoMonthsAroundSixtyDays验证了 60 天左右统一输出2 months ago。在应用启动时替换由于Configurator.DateTimeOffsetHumanizeStrategy是公开可写的静态属性可在启动阶段替换// 在应用启动、任何 Humanize 调用发生之前设置 Configurator.DateTimeOffsetHumanizeStrategy new PrecisionDateTimeOffsetHumanizeStrategy(precision: 0.9);从 Configurator.cs 的注释可见官方提醒该属性应只在应用启动时设置一次多线程场景下需要volatile读取或同步保护生产环境避免在提供服务后再修改。这意味着策略切换应放在Main、Startup或ModuleInitializer等初始化代码中。测试验证行为即文档仓库用一套完整的测试锁定了该类的行为边界见 tests/Humanizer.Tests/DateTimeOffsetHumanizeTests.cs可作为使用时的行为基准测试用例场景期望输出DefaultStrategy_SameOffset相同偏移量、相差 1 小时an hour from nowDefaultStrategy_DifferentOffsets不同偏移量、相差 30 分钟30 minutes agoDefaultStrategy_WeekAcrossDifferentOffsets跨时区相差约一周one week from nowPrecisionStrategy_SameOffset精度策略下相差约一天tomorrowPrecisionStrategy_DifferentOffsets精度策略跨时区6 hours agoHumanize_UsesSpecifiedCulture指定文化的本地化输出与各语言 Formatter 期望一致Never/Nullable_ExpectSame可空类型的空与非空行为never/ 与值类型一致其中Humanize_UsesSpecifiedCulture通过LocaleCoverageData.FormatterExpectationTheoryData对所有支持的区域性做了全量校验进一步印证了culture参数在本地化输出中的决定性作用。使用示例汇总综合上述机制典型用法如下using Humanizer; // 1) 相对当前时刻UTC 基准 var now DateTimeOffset.UtcNow; Console.WriteLine(now.AddHours(1).Humanize()); // en-US: an hour from now // 2) 相对指定基准 var baseTime new DateTimeOffset(2024, 1, 1, 10, 0, 0, TimeSpan.FromHours(2)); var inputTime new DateTimeOffset(2024, 1, 8, 3, 0, 0, TimeSpan.FromHours(-5)); Console.WriteLine(inputTime.Humanize(baseTime)); // one week from now // 3) 指定文化例如中文 Console.WriteLine(now.AddDays(-2).Humanize(culture: new CultureInfo(zh-CN))); // 4) 可空类型null 输出 never DateTimeOffset? never null; Console.WriteLine(never.Humanize()); // never // 5) 启动时切换到精度策略 Configurator.DateTimeOffsetHumanizeStrategy new PrecisionDateTimeOffsetHumanizeStrategy(0.75);小结DefaultDateTimeOffsetHumanizeStrategy虽然类体只有一行委托但其背后串联了 Humanizer 相对时间人文化的完整体系UTC 归一化保证跨时区正确、DateTimeHumanizeAlgorithms.DefaultHumanize的分段量化表决定口语化粒度、Configurator.GetFormatter完成多语言本地化、IDateTimeOffsetHumanizeStrategy契约使策略可插拔。理解这一默认实现就等于理解了DateTimeOffset.Humanize()的全部行为边界——无论是直接使用默认策略还是通过Configurator.DateTimeOffsetHumanizeStrategy替换为精度策略或自定义实现都能做到心中有数、结果可预期。赞分享开发工具【免费下载链接】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 中 DefaultDateTimeOffsetHumanizeStrategy 源码解析DateTimeOffset 相对时间人性化默认策略Humanizer 中 DefaultDateTimeOffsetHumanizeStrategy 源码解析DateTimeOffset 相对时间人性化默认策开发工具Humanizer DefaultDateTimeOffsetHumanizeStrategy 源码解析DateTimeOffset 相对时间转自然语言的核心策略Humanizer DefaultDateTimeOffsetHumanizeStrategy 源码解析DateTimeOffset 相对时间转自然语言的核心开发工具Humanizer 中 DefaultTimeOnlyHumanizeStrategy 源码解读TimeOnly 相对时间人性化的默认策略实现Humanizer 中 DefaultTimeOnlyHumanizeStrategy 源码解读TimeOnly 相对时间人性化的默认策略实现 本文围绕开发工具上一篇mold 内嵌 oneTBB 内存池详解memory_pool_allocator 模板类完全指南下一篇oauth2-proxy 配置体系完全指南命令行参数、环境变量、配置文件与三类日志详解7.15.x创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表