
开发工具【免费下载链接】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.13.14 版本 API 参考中PrecisionDateTimeHumanizeStrategy类的文档页,结合仓库中的源码实现与测试用例,完整讲解这个精度型日期人性化策略的 API 表面、在Configurator中的接入方式、precision参数背后的逐级进位算法,以及一套由单元测试固化的可复现行为基线。读完本文,你将能够在 .NET 应用中替换默认的相对时间算法,精确控制什么时候进位到分钟/小时/天/月/年的阈值,并理解每个输出字符串背后的判定条件。类定位:距离时间计算器的一种可配置实现API 参考文档对PrecisionDateTimeHumanizeStrategy的定义如下:public class PrecisionDateTimeHumanizeStrategy : Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy职责:基于精度因子(precision)计算两个时间之间的距离,并输出本地化的人性化距离描述(如an hour ago)。继承链:System.Object → PrecisionDateTimeHumanizeStrategy(来自 API 参考的 Inheritance 部分)。实现的接口:IDateTimeHumanizeStrategy,该接口只有一个方法:public interface IDateTimeHumanizeStrategy { string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture); }接口的文档注释明确了扩展点语义:Implement this interface to create a new strategy for DateTime.Humanize and hook it in the Configurator.DateTimeHumanizeStrategy。接口在源码中定义于 IDateTimeHumanizeStrategy.cs,从接口注释与Configurator的结构看,策略是DateTime.Humanize()扩展方法唯一的算法入口——应用可以通过实现该接口替换任意自定义算法,这也是PrecisionDateTimeHumanizeStrategy存在的意义:它是 Humanizer 官方提供的渐进阈值型策略,与内置的另一实现 DefaultDateTimeHumanizeStrategy 形成对照。两者的算法差异在 DateTimeHumanizeAlgorithms.cs 中看得最清楚:默认策略走DefaultHumanize,使用一组写死的边界(如小于 500 毫秒输出 now、小于 120 秒输出 a minute、小于 48 小时输出 yesterday 等);精度策略走PrecisionHumanize,所有进位边界都由precision因子缩放。API 表面:构造函数与 Humanize 方法构造函数与默认精度API 参考给出的构造函数签名为:public PrecisionDateTimeHumanizeStrategy(double precision 0.75);参数说明(完整继承自原文档):参数类型说明precisionSystem.Double近似的精度因子;若不提供,默认使用0.75作为精度对照当前仓库源码 PrecisionDateTimeHumanizeStrategy.cs,该文件只有 19 行,类本体如下:public class PrecisionDateTimeHumanizeStrategy(double precision .75) : IDateTimeHumanizeStrategy { readonly double precision precision; /// summary /// Returns localized amp; humanized distance of time between two dates; given a specific precision. /// /summary public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, precision, culture); }从源码结构看,这个类是一个纯粹的参数持有者 委托器:它不实现任何算法,只把构造时捕获的precision连同input、comparisonBase、culture一起转发给静态算法类DateTimeHumanizeAlgorithms.PrecisionHumanize。这意味着同一套精度算法被DateTime家族的所有兄弟策略复用(见 PrecisionDateOnlyHumanizeStrategy.cs、PrecisionTimeOnlyHumanizeStrategy.cs 与 PrecisionDateTimeOffsetHumanizeStrategy.cs),修改算法只需改一处。Humanize 方法API 参考中方法的完整签名为:public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture);三个参数的语义(参数名来自 API 参考,语义结合 DateHumanizeExtensions.cs 的扩展方法注释补充):参数类型语义inputSystem.DateTime要被人性化的目标日期comparisonBaseSystem.DateTime比较基准日期;DateTime.Humanize中不显式传入时默认使用DateTime.UtcNowcultureSystem.Globalization.CultureInfo输出所使用的文化;为 null 时使用当前线程文化返回值是本地化字符串。注意方法实现中culture可空(CultureInfo?),Configurator.GetFormatter(culture)会按传入的文化解析对应的IFormatter(解析逻辑见 Configurator.cs 的Formatters.ResolveForCulture)。调用链:从扩展方法到策略理解这个类如何被使用,需要看完整调用链。以最常见的someDateTime.Humanize()为例:入口扩展方法:DateHumanizeExtensions.cs 中的Humanize(this DateTime input, bool? utcDate null, DateTime? dateToCompareAgainst null, CultureInfo? culture null)。该方法先确定比较基准(dateToCompareAgainst ?? DateTime.UtcNow),再根据utcDate与input.Kind做时区归一,最后调用:return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture);全局策略槽位:Configurator.cs 中的静态属性:public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } new DefaultDateTimeHumanizeStrategy();默认值是DefaultDateTimeHumanizeStrategy;将其替换为new PrecisionDateTimeHumanizeStrategy(...)后,所有DateTime.Humanize()调用都会走精度算法。该属性的remarks明确给出使用约束:此属性应在应用启动时只设置一次,在开始任何人性化操作之前完成;多线程场景下读取该属性需要注意线程安全,生产环境中应避免在开始处理请求之后再变更该值。算法层:DateTimeHumanizeAlgorithms.cs 中的PrecisionHumanize(DateTime input, DateTime comparisonBase, double precision, CultureInfo? culture):var ts new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); var tense input comparisonBase ? Tense.Future : Tense.Past; return PrecisionHumanize(ts, tense, precision, culture);时态判定规则很简单:input comparisonBase为未来(Future,输出 from now),否则为过去(Past,输出 ago);两值相等时为 Past,且最终落到 0 毫秒档位,输出 now。格式化层:算法只产出哪个时间单位、几、什么时态,最终字符串由IFormatter.DateHumanize(TimeUnit, Tense, int)按文化生成(见 DateTimeHumanizeAlgorithms.cs 的收尾部分,单位按年→月→日→时→分→秒的优先级依次判定)。precision 算法拆解:逐级进位与阈值缩放核心实现在 DateTimeHumanizeAlgorithms.cs 的私有方法PrecisionHumanize(TimeSpan ts, Tense tense, double precision, CultureInfo? culture)。它的工作方式是从小单位向大单位逐级进位,每一步的进位阈值都是单位上限 − 1乘以precision:int seconds ts.Seconds, minutes ts.Minutes, hours ts.Hours, days ts.Days; int years 0, months 0; // start approximate from smaller units towards bigger ones if (ts.Milliseconds 999 * precision) { seconds 1; } if (seconds 59 * precision) { minutes 1; } if (minutes 59 * precision) { hours 1; } if (hours 23 * precision) { days 1; } // month calculation if (days 30 * precision days 31) { months 1; } if (days 31 days 365 * precision) { var factor Convert.ToInt32(Math.Floor((double)days / 30)); months days 30 * (factor precision) ? factor 1 : factor; } // year calculation if (days 365 * precision days 366) { years 1; } if (days 365) { var factor Convert.ToInt32(Math.Floor((double)days / 365)); years days 365 * (factor precision) ? factor 1 : factor; }以默认precision 0.75代入,得到各档位的实际进位阈值:进位档位判定条件(源码)precision 0.75 时的等效阈值毫秒 → 秒Milliseconds 999 * p≥ 749.25 ms 计 1 秒秒 → 分seconds 59 * p≥ 44.25 秒计 1 分钟分 → 时minutes 59 * p≥ 44.25 分钟计 1 小时时 → 天hours 23 * p≥ 17.25 小时计 1 天天 → 月(单月档)days 30 * p days 3123–31 天计 1 个月天 → 月(多月档)31 days 365 * p,月数 floor(days/30) 再按days 30*(factorp)进位53 天计 2 个月天 → 年(单年档)days 365 * p days 366274–366 天计 1 年天 → 年(多年档)days 365,年数 floor(days/365) 再按days 365*(factorp)进位730 天计 2 年调整precision的实际含义是:值越接近 1,阈值越严格(需要更接近满档才进位,例如 0.9 时秒→分要 ≥ 53.1 秒);值越小,越早进位到更大单位,描述更粗粒度。这与文档中precision of approximation的措辞一致——它控制的是近似进位的激进程度。可验证的行为基线:测试用例DateTimeHumanizePrecisionStrategyTests.cs 用一组Theory用例把上述阈值全部固化下来(测试文件头部的const double DefaultPrecision .75与类默认精度一致)。每个用例都断言过去时(Past,输出 ago)与未来时(Future,输出 from now)两个方向,代表性数据如下:输入(相对基准的偏移)期望输出命中的档位1–749 msnow毫秒未达 749.25,0 档750–1749 msone second ago毫秒进位 1 秒1750 ms2 seconds ago1 秒 毫秒再进位1–44 sN seconds ago秒档45–104 sa minute ago秒进位 1 分钟105 s2 minutes ago1 分钟 再进位45–104 minan hour ago分进位 1 小时1–17 hN hours ago小时档18–41 hyesterday时进位 1 天(单日用 yesterday/tomorrow 表达)42–60 h2 days ago2 天1–22 dN days ago(1 天为yesterday)天档23–43 done month ago单月档(23 ⌈30×0.75⌉)53 d2 months ago多月档进位89–91 d3 months ago多月档9–19 个月(按 31 天/月折算)one year ago单年档729–731 d2 years ago多年档这些测试通过测试辅助类 DateHumanize.cs 的Verify方法驱动,该方法的关键逻辑正是本文主题的实操接线:if (precision.HasValue) { Configurator.DateTimeHumanizeStrategy new PrecisionDateTimeHumanizeStrategy(precision.Value); } else { Configurator.DateTimeHumanizeStrategy new DefaultDateTimeHumanizeStrategy(); }随后Verify会分别用当前真实时间和注入的固定基准时间(2013-06-20)双通道断言,保证结果既与实时时钟一致又不受时钟跳动影响——这也是官方示例推荐显式传入dateToCompareAgainst以获得确定性输出的原因。完整使用示例仓库文档自带的配置示例 Program.cs 演示了替换策略 注入比较基准 固定文化的确定性用法(2.x 版本中需要using Humanizer.Configuration;与using Humanizer.DateTimeHumanizeStrategy;):using System.Globalization; using Humanizer; #if HUMANIZER_V2 using Humanizer.Configuration; using Humanizer.DateTimeHumanizeStrategy; #endif var culture CultureInfo.GetCultureInfo(en-US); var comparison new DateTime(2025, 1, 20, 12, 0, 0, DateTimeKind.Utc); Configurator.DateTimeHumanizeStrategy new PrecisionDateTimeHumanizeStrategy(precision: 0.75); var result comparison.AddMinutes(-45).Humanize( utcDate: true, dateToCompareAgainst: comparison, culture: culture); if (result ! an hour ago) throw new InvalidOperationException($Unexpected result: {result}); Console.WriteLine(result);输出an hour ago。用前文的阈值表可以快速手推验证:45 分钟 ≥ 44.25(59×0.75),分钟进位 1 小时 →formatter.DateHumanize(TimeUnit.Hour, Tense.Past, 1)→ an hour ago。配套的场景指南 relative-dates-and-times.mdx 进一步建议:需要确定性输出时,同时显式传入比较基准与culture;默认策略提供的是 yesterday 这类熟悉边界,而PrecisionDateTimeHumanizeStrategy及其兄弟策略适合应用需要更渐进阈值(more gradual thresholds)的场景;策略应通过Configurator在启动时一次性赋值。边界条件与使用注意事项结合源码与文档,使用PrecisionDateTimeHumanizeStrategy时有以下几点值得注意:时区一致性:入口扩展方法会依据utcDate参数把比较基准转换到 UTC 或本地时间(见 DateHumanizeExtensions.cs 中的comparisonBase.ToUniversalTime()/ToLocalTime()归一)。场景指南明确警告:不要无意中拿本地DateTime与 UTC 基准比较,混合的Kind值会让阈值边界漂移。策略是全局单例,启动时设置一次:Configurator.DateTimeHumanizeStrategy的 XML 注释要求启动期一次性赋值、运行期不再变更(见 Configurator.cs)。测试代码中频繁切换策略的做法仅适用于测试隔离,生产代码不应复制。进位是级联的:毫秒进位出的 1 秒会继续参与秒→分判定,因此 1750 ms 输出2 seconds ago而非1 second ago;同理 105 秒输出2 minutes ago。理解级联关系后,所有输出都可以用阈值表手推复现。命名空间与版本:2.13.14的 API 参考将此类文档化在Humanizer.DateTimeHumanizeStrategy命名空间下(见 Humanizer.DateTimeHumanizeStrategy.md 命名空间页);而当前仓库源码文件中该类位于namespace Humanizer(见 PrecisionDateTimeHumanizeStrategy.cs 第 1 行),仓库中的 NamespaceMigrationAnalyzer.cs 也表明存在命名空间迁移的分析器支持。升级版本时应以对应版本的 API 参考与目标框架为准。目标框架范围:与DateTime/DateTimeOffset不同,DateOnly、TimeOnly相关的精度策略(如 PrecisionDateOnlyHumanizeStrategy.cs)在源码中用#if NET6_0_OR_GREATER包裹,仅在 .NET 6 及更高版本的目标框架下可用;场景指南同样注明DateOnly/TimeOnly的人性化自 2.11.10 起在兼容框架上生效。本地化由 Formatter 决定:策略本身不产生任何文本,所有输出短语(a minute ago、yesterday、now、never)都由按文化解析的IFormatter提供;可空入参(如DateTime?)在 null 时返回本地化的 never 短语(见 DateHumanizeExtensions.cs)。相关文档与源码索引本文对应的 API 参考页:Humanizer.DateTimeHumanizeStrategy.PrecisionDateTimeHumanizeStrategy.md策略接口:IDateTimeHumanizeStrategy类实现:PrecisionDateTimeHumanizeStrategy.cs核心算法:DateTimeHumanizeAlgorithms.cs默认策略对照:DefaultDateTimeHumanizeStrategy.cs配置入口:Configurator.cs入口扩展方法:DateHumanizeExtensions.cs行为基线测试:DateTimeHumanizePrecisionStrategyTests.cs、DateHumanize.cs可运行示例:_examples/configuration/Program.cs场景指南:relative-dates-and-times.mdx赞分享开发工具【免费下载链接】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 深度解析DateTime 人性化策略的实现与定制Humanizer DefaultDateTimeHumanizeStrategy 深度解析DateTime 人性化策略的实现与定制 本文围绕 Humaniz开发工具Humanizer ITimeOnlyHumanizeStrategy 接口深度解析自定义 TimeOnly.Humanize 时间人性化策略Humanizer ITimeOnlyHumanizeStrategy 接口深度解析自定义 TimeOnly.Humanize 时间人性化策略 本文以 Hum开发工具Humanizer 中 IDateOnlyHumanizeStrategy 接口详解自定义 DateOnly 人性化日期策略Humanizer 中 IDateOnlyHumanizeStrategy 接口详解自定义 DateOnly 人性化日期策略 Humanizer 提供了 Da开发工具上一篇Marathon健康检查终极指南从HTTP到TCP的全面监控下一篇如何微调MiniMax-M2.7-NVFP4自定义AI助手的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考