
开发工具【免费下载链接】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点击查看免费下载DefaultDateTimeHumanizeStrategy是 Humanizer 库中把“两个时刻之间的距离”翻译成人话如yesterday、3 hours ago、a month from now的默认计算器。本文围绕它在 Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy 中的角色逐步拆解其类定义、Humanize方法签名、底层分级判定算法、文化本地化机制、配置与替换方式并结合测试代码与官方场景示例给出可直接运行的代码帮助你彻底掌握DateTime.Humanize()的默认行为及其边界。类定位默认的“时间距离 → 文字”计算器DefaultDateTimeHumanizeStrategy是DateTime.Humanize()扩展方法在默认配置下使用的策略实现。其完整类声明为public class DefaultDateTimeHumanizeStrategy : Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy继承链System.Object→DefaultDateTimeHumanizeStrategy实现的接口IDateTimeHumanizeStrategy该接口定义了唯一的契约方法string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture)用于“计算两个日期之间的时间距离并转化为文字”。从实现上看这个类本身非常薄是典型的“策略封装 算法委托”结构。DefaultDateTimeHumanizeStrategy.cs 的完整源码仅有一个方法体将全部计算委托给内部的算法类public class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy { public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); }其中DateTimeHumanizeAlgorithms定义在 DateTimeHumanizeAlgorithms.cs是Default、Precision两套策略共享的算法引擎DefaultDateTimeHumanizeStrategy走DefaultHumanizePrecisionDateTimeHumanizeStrategy走PrecisionHumanize。Humanize 方法签名、参数与返回语义原 API 文档给出的方法签名如下public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture);三个参数的语义分别是参数类型含义inputSystem.DateTime要被“人性化”的目标时刻即希望被描述为相对时间的那一侧comparisonBaseSystem.DateTime参照基准时刻input相对它计算时间距离过去 / 未来cultureSystem.Globalization.CultureInfo用于输出本地化文案的文化对象传入null时使用当前线程文化返回值System.String为本地化的相对时间文案例如yesterday、3 hours ago、a month from now等。该方法直接实现了IDateTimeHumanizeStrategy.Humanize(DateTime, DateTime, CultureInfo)因此可以被Configurator.DateTimeHumanizeStrategy以多态方式调用详见下文“配置与替换”一节。扩展方法层谁在调用它DefaultDateTimeHumanizeStrategy并不是直接暴露给业务代码的真正入口是 DateHumanizeExtensions.cs 中的DateTime.Humanize()扩展方法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); }几个值得注意的默认行为基准时刻不传dateToCompareAgainst时默认取DateTime.UtcNow时区语义utcDate为null时依据input.Kind推断非 Local 即按 UTC 处理随后把基准时刻统一换算到同一时区避免“本地时间与 UTC 时间混比”造成的边界漂移可空重载DateTime?的重载在值为null时返回该文化的never短语由Formatter.DateHumanize_Never()提供见 DefaultFormatter.cs该方法返回后文案中出现的数字由DefaultFormatter通过当前文化的数字系统呈现如 DefaultFormatter.cs 所示FormatCountValue使用CultureInfo.CurrentCulture格式化计数值。核心算法DefaultHumanize 的分级判定整个策略的灵魂在DateTimeHumanizeAlgorithms.DefaultHumanize。它先计算两个基础量再做分层阈值判断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);tenseinput晚于基准为Future否则为Past决定输出… from now还是… agots两时刻Ticks差的绝对值作为细分判断的依据sameMonth判断“相差整一个月”的情况用于 28~30 天窗口内区分“1 个月”与“N 天”days按日历日计算的整日差。随后按时间跨度从小到大依次命中唯一分支源码位于 DateTimeHumanizeAlgorithms.cs判定条件输出单位计数值英文示例过去式TotalMilliseconds 500Millisecond0nowTotalSeconds 60Secondts.Seconds5 seconds agoTotalSeconds 120Minute1a minute agoTotalMinutes 60Minutets.Minutes30 minutes agoTotalMinutes 90Hour1an hour agoTotalHours 24Hourts.Hours5 hours agoTotalHours 48Daydays日历日差yesterday1 天TotalDays 7Dayts.Days3 days agoTotalDays 28Weekts.Days / 72 weeks agoTotalDays ∈ [28, 30)MonthsameMonth为真或 Day1 或ts.Daysa month ago/28 days agoTotalDays 345Monthfloor(TotalDays / 29.5)3 months ago其余≥ 345 天Yearfloor(TotalDays / 365)至少 12 years ago几个容易被忽略的细节毫秒级即“现在”只要跨度小于 500ms直接返回now而DateOnly特例还会进一步映射为today见 DateTimeHumanizeAlgorithms.csDateOnlyHumanizeToday在DefaultFormatter下把now改写为today四舍五入式的取整惯例120 秒归为 “1 分钟”、90 分钟归为 “1 小时”、48 小时归为 “1 天”这是一种向下取整的近似策略与PrecisionDateTimeHumanizeStrategy的“按精度渐进进位”形成对比年与月的估算月份按29.5天、年份按365天估算years计算结果为 0 时强制置 1因此任何超过 345 天的跨度至少会输出a year …。与 Precision 策略的分工同一算法文件中还提供了PrecisionHumanizeDateTimeHumanizeAlgorithms.cs由 PrecisionDateTimeHumanizeStrategy.cs 使用其构造函数接受一个precision参数默认0.75。区别在于默认策略以“自然语言习惯”为优先例如 48 小时直接说 “2 days ago” 或 “yesterday”精度策略以“数值近似精度”为优先当ts.Seconds 59 * precision时才进位到分钟适合需要更渐进、更精确的阈值场景。两者共用同一套Formatter.DateHumanize输出管线只是“单位与计数”的判定算法不同。本地化文案从哪来DefaultHumanize判定出(TimeUnit, tense, count)后统一交给Configurator.GetFormatter(culture)解析出的IFormatter渲染DateTimeHumanizeAlgorithms.cs最终由 DefaultFormatter.cs 的DateHumanize(TimeUnit, Tense, int)完成“单位 时态 数量 → 短语”的映射数据来自生成的LocalePhraseTable。英语短语数据位于 Locales/en.yml结构为relativeDate下的now / today / never以及past / future两组phrases: relativeDate: now: now today: today never: never past: day: single: yesterday multiple: afterCount: ago forms: singular: day default: days future: day: single: tomorrow multiple: afterCount: from now forms: singular: day default: days要点单复数与特例count 1时优先命中single短语如yesterday、a minute ago否则使用multiple下的单复数forms并拼接afterCountago/from now文化覆盖Humanizer 在 Locales 目录为 90 种语言提供同类短语表Configurator.GetFormatter(culture)按文化解析culture为null时回退到当前线程文化这与DateTime.Humanize()的culture参数语义一致不匹配即抛错若某文化缺少所需短语DateHumanize会抛出InvalidOperationExceptionDefaultFormatter.cs提示缺失的 culture 与时间单位。配置与替换如何换掉默认策略DefaultDateTimeHumanizeStrategy之所以是“默认”是因为它在 Configurator.cs 中被设为DateTimeHumanizeStrategy属性的初始值public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } new DefaultDateTimeHumanizeStrategy();因此有两种使用方式1. 不配置直接用默认行为using Humanizer; var comparison new DateTime(2025, 1, 20, 12, 0, 0, DateTimeKind.Utc); Console.WriteLine(comparison.AddDays(-1).Humanize(utcDate: true, dateToCompareAgainst: comparison)); // yesterday Console.WriteLine(comparison.AddMinutes(-90).Humanize(utcDate: true, dateToCompareAgainst: comparison)); // an hour ago2. 启动期替换策略当应用需要更精细的阈值如“90 分钟才算 1 小时”时可在启动阶段替换Configurator.DateTimeHumanizeStrategy new PrecisionDateTimeHumanizeStrategy(0.75);官方文档明确提醒Configurator.cs 的 remarks该属性只应在应用启动期设置一次任何Humanize操作发生之后再修改可能造成多线程下的不一致生产应用中避免在开始服务请求后动态变更多线程场景下应使用volatile读取或合适的同步机制。可空值与 DateOnly/TimeOnlyDateTime?的Humanize重载在值为null时直接返回文化的never短语不会进入DefaultDateTimeHumanizeStrategy。对于 .NET 6 的DateOnly、TimeOnlyHumanizer 分别通过DateOnlyHumanizeStrategy、TimeOnlyHumanizeStrategy属性提供独立策略默认同为各自“默认策略”类其中DateOnly的相等特例会被渲染为today而非nowDateTimeHumanizeAlgorithms.cs。测试验证与官方示例测试侧tests/Humanizer.Tests/DateHumanize.cs 的Verify辅助方法展示了策略如何参与断言它按timeUnit把单位映射为TimeSpan其中Month 31 天、Year 366 天然后注入固定的基准时刻UTC2013-06-20 09:58:22与本地2013-06-20 11:58:22来消除“CPU 滴答导致测试不稳定”的问题并通过Configurator.DateTimeHumanizeStrategy new DefaultDateTimeHumanizeStrategy()显式切换策略后再断言输出文案。同时ApiApprover 的快照文件确认了该类型对外公开的 API 形态。官方场景示例 website/docs/scenarios/relative-dates-and-times.mdx 提供了覆盖DateTime/DateTimeOffset/DateOnly/TimeOnly的完整可运行样例Program.cs其输出为DateTime: yesterday DateTimeOffset: yesterday DateOnly: yesterday TimeOnly: a minute from now Duration: 2 hours, 5 minutes示例中反复强调一个实践要点当输出必须是确定性的时候显式传入dateToCompareAgainst与culture避免隐式读取机器时钟造成的结果漂移。使用建议与边界提醒显式注入基准日志、审计等场景应传dateToCompareAgainst让输出与数据产生时刻一致而不是与“读取日志那一刻”绑定UTC/本地分离不要无意中把本地DateTime与 UTC 基准混比utcDate参数负责统一换算混合Kind会移动 48 小时、28 天等边界选择合适的类型TimeOnly没有日期上下文跨午夜比较时无法区分“昨天”还是“明天”应避免用TimeOnly表达跨日相对时间需要更精确的阈值时优先考虑PrecisionDateTimeHumanizeStrategy但要注意精度参数影响的是“进位时机”而非文案本身的措辞空值语义可空重载返回never适合可选活动时间戳但领域逻辑中仍应显式处理缺失值。小结DefaultDateTimeHumanizeStrategy以极小的类体封装了完整的相对时间判定管线DateTime.Humanize()扩展方法负责基准与时区归一化DateTimeHumanizeAlgorithms.DefaultHumanize负责“单位 数量”的阈值判定DefaultFormatter与LocalePhraseTable负责把结果渲染成目标文化的自然语言。理解这三层分工你就既能预测默认策略在任何跨度下的输出也能在需要时通过Configurator.DateTimeHumanizeStrategy无缝切换到自定义或精度策略。赞分享开发工具【免费下载链接】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 相对时间人性化DefaultDateTimeHumanizeStrategy 默认策略源码级解析Humanizer 相对时间人性化DefaultDateTimeHumanizeStrategy 默认策略源码级解析 Humanizer 的 DefaultD开发工具Humanizer DefaultDateTimeHumanizeStrategy 详解默认相对时间短语化算法与本地化实现Humanizer DefaultDateTimeHumanizeStrategy 详解默认相对时间短语化算法与本地化实现 导读 本文围绕 Humanizer开发工具Humanizer 默认日期人性化策略解析DefaultDateTimeHumanizeStrategy 的算法、调用链与本地化原理Humanizer 默认日期人性化策略解析DefaultDateTimeHumanizeStrategy 的算法、调用链与本地化原理 导读 DefaultDa开发工具上一篇为什么你的PHP测试这么慢phpunit-speedtrap揭示真相下一篇202309051233 异步编程模式创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考