換為自然語言的策略模式)
開發(fā)工具【免費(fèi)下載鏈接】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點擊查看免費(fèi)下載本篇圍繞 Humanizer 庫 v2.13.14 文檔中的Humanizer.DateTimeHumanizeStrategy命名空間索引頁展開。該命名空間是 Humanizer 實現(xiàn)“日期人性化”把DateTime、DateTimeOffset、DateOnly、TimeOnly轉(zhuǎn)換為 “3 days ago” 這類自然語言的核心擴(kuò)展點讀完后你將清楚 4 個策略接口的契約、8 個內(nèi)置策略類的分工、底層時間差算法的分檔與精度機(jī)制以及如何通過Configurator替換或自定義策略。命名空間概覽Humanizer.DateTimeHumanizeStrategy命名空間對應(yīng)源碼目錄 src/Humanizer/DateTimeHumanizeStrategy按文檔索引頁Humanizer.DateTimeHumanizeStrategy.md共包含 4 個接口和 8 個類全部服務(wù)于“距離時間distance of time→ 詞語”的計算類Classes類說明DefaultDateOnlyHumanizeStrategy默認(rèn)的“距離時間”→ 詞語計算器DateOnly 版本DefaultDateTimeHumanizeStrategy默認(rèn)的“距離時間”→ 詞語計算器DateTime 版本DefaultDateTimeOffsetHumanizeStrategy默認(rèn)的“距離時間”→ 詞語計算器DateTimeOffset 版本DefaultTimeOnlyHumanizeStrategy默認(rèn)的“距離時間”→ 詞語計算器TimeOnly 版本PrecisionDateOnlyHumanizeStrategy基于精度precision的時間距離計算器PrecisionDateTimeHumanizeStrategy基于精度的時間距離計算器PrecisionDateTimeOffsetHumanizeStrategy基于精度的時間距離計算器PrecisionTimeOnlyHumanizeStrategy基于精度的時間距離計算器接口Interfaces接口說明IDateOnlyHumanizeStrategy實現(xiàn)該接口以創(chuàng)建新的DateOnly.Humanize策略并掛接到Configurator.DateOnlyHumanizeStrategyIDateTimeHumanizeStrategy實現(xiàn)該接口以創(chuàng)建新的DateTime.Humanize策略并掛接到Configurator.DateTimeHumanizeStrategyIDateTimeOffsetHumanizeStrategy實現(xiàn)該接口以創(chuàng)建新的策略并掛接到Configurator.DateTimeOffsetHumanizeStrategyITimeOnlyHumanizeStrategy實現(xiàn)該接口以創(chuàng)建新的TimeOnly.Humanize策略并掛接到Configurator.TimeOnlyHumanizeStrategy四個策略接口的契約每個接口都是一個單方法契約簽名統(tǒng)一為string Humanize(輸入值, 比較基準(zhǔn), 文化)。以IDateTimeHumanizeStrategy為例見 IDateTimeHumanizeStrategy.cspublic interface IDateTimeHumanizeStrategy { /// summary /// Calculates the distance of time in words between two provided dates used for DateTime.Humanize /// /summary string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture); }其余三個接口與之同構(gòu)// IDateTimeOffsetHumanizeStrategyIDateTimeOffsetHumanizeStrategy.cs string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo? culture); // IDateOnlyHumanizeStrategyIDateOnlyHumanizeStrategy.cs#if NET6_0_OR_GREATER 下可用 string Humanize(DateOnly input, DateOnly comparisonBase, CultureInfo? culture); // ITimeOnlyHumanizeStrategyITimeOnlyHumanizeStrategy.cs#if NET6_0_OR_GREATER 下可用 string Humanize(TimeOnly input, TimeOnly comparisonBase, CultureInfo? culture);從源碼結(jié)構(gòu)看四個接口都刻意保持“值類型入?yún)? 顯式比較基準(zhǔn) 可空CultureInfo”的形態(tài)比較基準(zhǔn)comparisonBase已經(jīng)由擴(kuò)展方法層做過時區(qū)歸一化策略只負(fù)責(zé)“差值 → 詞”的純計算culture為 null 時由Configurator.GetFormatter(culture)回落到當(dāng)前線程文化。Default* 系列默認(rèn)策略與內(nèi)置算法四個Default*HumanizeStrategy類都是極簡的“委托式”實現(xiàn)。例如 DefaultDateTimeHumanizeStrategy.cspublic class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy { public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); }DefaultDateOnlyHumanizeStrategy、DefaultDateTimeOffsetHumanizeStrategy、DefaultTimeOnlyHumanizeStrategy結(jié)構(gòu)相同全部把實際計算委托給內(nèi)部靜態(tài)類 DateTimeHumanizeAlgorithms.cs。也就是說所有默認(rèn)行為的算法細(xì)節(jié)都集中在這一處。默認(rèn)算法的分檔邏輯DefaultHumanize(TimeSpan, bool sameMonth, int days, Tense, CultureInfo?)見 DateTimeHumanizeAlgorithms.cs#L192-L264使用固定閾值逐級向上取檔規(guī)則如下時間差條件輸出檔位說明TotalMilliseconds 500“now”0 毫秒檔不足半秒視為“現(xiàn)在”TotalSeconds 60N seconds秒檔TotalSeconds 120“a minute”不足 2 分鐘歸并為 1 分鐘TotalMinutes 60N minutes分鐘檔TotalMinutes 90“an hour”不足 1.5 小時歸并為 1 小時TotalHours 24N hours小時檔TotalHours 48N days不足 48 小時按自然日數(shù)計TotalDays 7N days日檔TotalDays 28N weeks周檔ts.Days / 728 TotalDays 30“a month” 或 N days是否說“一個月”取決于sameMonth標(biāo)志比較基準(zhǔn)加減一個月后日期是否等于輸入日期TotalDays 345N months月檔按TotalDays / 29.5向下取整其余N years年檔按TotalDays / 365向下取整最小為 1值得注意的兩個細(xì)節(jié)時區(qū)無關(guān)的日期比較DefaultHumanize(DateTime, DateTime, ...)L137-L147會先計算sameMonth比較基準(zhǔn)向前/向后推一個月后的日期是否等于輸入日期再取自然日差days用于 28~30 天區(qū)間的“a month”判斷。DateOnly 的“今天”特例DateOnly版本在input comparisonBase時直接走DateOnlyHumanizeToday(culture)L171-L178即先取 0 毫秒檔的本地化文案若 formatter 是DefaultFormatter再包裝為 “today”這與DateTime版本差值不足 500ms 輸出 “now” 的語義相互對應(yīng)。TimeOnly 版本固定以sameMonth: true, days: 0調(diào)用共享分檔函數(shù)L183-L189因此只會輸出到小時/分鐘/秒檔。Precision* 系列可配置精度的四舍五入四個Precision*HumanizeStrategy類與默認(rèn)策略同構(gòu)但構(gòu)造函數(shù)接受一個precision參數(shù)默認(rèn)值為0.75。以 PrecisionDateTimeHumanizeStrategy.cs 為例/// param nameprecisionprecision of approximation, if not provided 0.75 will be used as a default precision./param public class PrecisionDateTimeHumanizeStrategy(double precision .75) : IDateTimeHumanizeStrategy { readonly double precision precision; public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, precision, culture); }精度算法的進(jìn)位機(jī)制PrecisionHumanize(TimeSpan, Tense, double precision, CultureInfo?)DateTimeHumanizeAlgorithms.cs#L48-L131的思路與默認(rèn)算法相反先自小單位向大單位逐級“進(jìn)位”再自大單位向小單位選取第一個非零檔。進(jìn)位規(guī)則形如if (當(dāng)前單位值 進(jìn)位上限 * precision) 上一單位 1// 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; // 小時 → 天月與年的換算則使用“整除 精度補(bǔ)償”// 月30 天為一檔 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; } // 年365 天為一檔 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; }最后按 Year → Month → Day → Hour → Minute → Second → Millisecond 的順序返回第一個命中檔全部走Configurator.GetFormatter(culture).DateHumanize(TimeUnit, Tense, 值)完成本地化。precision越大進(jìn)位閾值越高文案越“保守”寧可說小一檔precision越小則越早向上取整。以默認(rèn)0.75為例測試文件 DateTimeHumanizePrecisionStrategyTests.cs 固化了邊界行為en-US文化過去時輸入毫秒期望輸出命中規(guī)則1 / 749now毫秒 999 × 0.75 749.25750one second ago毫秒 ≥ 749.25進(jìn)位 1 秒17502 seconds ago1750ms ≈ 1.75s向秒進(jìn)位后為 2輸入天期望輸出說明2222 days ago未達(dá) 30 × 0.75 22.5 天的進(jìn)月閾值23one month ago23 ≥ 22.5 且 ≤ 31月檔532 months ago53 ≥ 30 × (1 0.75) 52.5向上取 2 個月7302 years ago730 ≥ 365 × (1 0.75)向上取 2 年小時與分鐘檔同理17 小時仍為17 hours ago18 小時≥ 23 × 0.75 17.25進(jìn)位為yesterday見 L74-L97。通過 Configurator 掛載策略策略與擴(kuò)展方法之間的橋梁是靜態(tài)配置中心Configurator。在 Configurator.cs 中可以看到各策略的默認(rèn)裝配節(jié)選public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } new DefaultDateTimeHumanizeStrategy(); public static IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } new DefaultDateTimeOffsetHumanizeStrategy(); public static IDateOnlyHumanizeStrategy DateOnlyHumanizeStrategy { get; set; } new DefaultDateOnlyHumanizeStrategy(); public static ITimeOnlyHumanizeStrategy TimeOnlyHumanizeStrategy { get; set; } new DefaultTimeOnlyHumanizeStrategy();因此“替換策略”只需給對應(yīng)屬性賦值無需改任何調(diào)用代碼// 使用內(nèi)置精度策略把進(jìn)位閾值提高到 0.9更接近四舍五入 Configurator.DateTimeHumanizeStrategy new PrecisionDateTimeHumanizeStrategy(0.9); // 或自定義策略例如統(tǒng)一把不足 5 分鐘的輸出說成“剛剛” public sealed class MyStrategy : IDateTimeHumanizeStrategy { public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo? culture) { var diff Math.Abs(comparisonBase - input); if (diff.TotalMinutes 5) return just now; return new DefaultDateTimeHumanizeStrategy().Humanize(input, comparisonBase, culture); } } Configurator.DateTimeHumanizeStrategy new MyStrategy();注意Configurator的屬性是靜態(tài)且非線程安全的賦值即全局生效適合在應(yīng)用啟動階段配置一次。入口擴(kuò)展方法的參數(shù)語義策略最終由 DateHumanizeExtensions.cs 中的擴(kuò)展方法觸發(fā)參數(shù)語義取自源碼 XML 注釋如下DateTimeHumanize(this DateTime input, bool? utcDate null, DateTime? dateToCompareAgainst null, CultureInfo? culture null)。dateToCompareAgainst為 null 時以DateTime.UtcNow為基準(zhǔn)utcDate為 null 時按input.Kind ! DateTimeKind.Local推斷并據(jù)此把比較基準(zhǔn)轉(zhuǎn)換到同一時區(qū)L16-L23。DateTimeOffsetHumanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst null, CultureInfo? culture null)基準(zhǔn)為 null 時取DateTimeOffset.UtcNowL52-L57。DateOnly/TimeOnly#if NET6_0_OR_GREATER下可用基準(zhǔn)分別為DateOnly.FromDateTime(DateTime.UtcNow)和TimeOnly.FromDateTime(useUtc ? DateTime.UtcNow : DateTime.Now)其中TimeOnly提供useUtc開關(guān)默認(rèn)trueL86-L124??煽罩剌d的統(tǒng)一行為DateTime?、DateTimeOffset?、DateOnly?、TimeOnly?的 null 輸入一律通過Configurator.GetFormatter(culture).DateHumanize_Never()返回本地化的 “never”如 L33-L43避免在策略層處理空值。一個典型的調(diào)用組合示例using Humanizer; var now new DateTime(2024, 6, 1, 12, 0, 0, DateTimeKind.Utc); // “3 days ago” now.AddHours(-72).Humanize(utcDate: true, dateToCompareAgainst: now, culture: CultureInfo.GetCultureInfo(en-US)); Configurator.DateOnlyHumanizeStrategy new PrecisionDateOnlyHumanizeStrategy(0.8); // 使用自定義精度策略人性化 DateOnly 差值 var result new DateOnly(2024, 5, 15).Humanize(new DateOnly(2024, 6, 1));參考文件匯總內(nèi)容路徑命名空間索引文檔Humanizer.DateTimeHumanizeStrategy.md策略接口與內(nèi)置策略實現(xiàn)src/Humanizer/DateTimeHumanizeStrategy/核心算法分檔 精度DateTimeHumanizeAlgorithms.cs擴(kuò)展方法入口DateHumanizeExtensions.cs策略裝配點Configurator.cs精度策略邊界測試DateTimeHumanizePrecisionStrategyTests.cs小結(jié)Humanizer.DateTimeHumanizeStrategy用“接口 靜態(tài)裝配點 算法集中化”的三層結(jié)構(gòu)實現(xiàn)了日期人性化的可插拔擴(kuò)展接口層定義 4 個值類型的策略契約實現(xiàn)層提供 Default固定閾值分檔與 Precisionprecision可調(diào)、自下而上進(jìn)位兩套算法的 8 種類型化封裝配置層則通過Configurator的 4 個靜態(tài)屬性完成掛載。理解本文的分檔表、精度進(jìn)位規(guī)則與擴(kuò)展方法參數(shù)語義后你可以直接復(fù)用內(nèi)置策略或按業(yè)務(wù)需要如“不足 5 分鐘一律說 just now”編寫并注冊自己的策略。贊分享開發(fā)工具【免費(fèi)下載鏈接】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點擊查看免費(fèi)下載相關(guān)推薦chrono 中的時間戳轉(zhuǎn)換從自然語言到 Unix 時間戳chrono 中的時間戳轉(zhuǎn)換從自然語言到 Unix 時間戳 chrono 是一個強(qiáng)大的自然語言日期解析庫它能夠?qū)⑷祟惪勺x的時間描述轉(zhuǎn)換為標(biāo)準(zhǔn)的 Unix 時開發(fā)工具Hugo 模板中 Duration 的 Hours 方法將時間間隔轉(zhuǎn)換為浮點小時數(shù)Hugo 模板中 Duration 的 Hours 方法將時間間隔轉(zhuǎn)換為浮點小時數(shù) 導(dǎo)讀 本文講解 Hugo 模板語言中 time.Duration 值的 H開發(fā)工具前端CLIHumanizer時間跨度人性化從TimeSpan到2周1天的魔法轉(zhuǎn)換在.NET開發(fā)中處理時間間隔顯示時經(jīng)常遇到這樣的問題如何將冰冷的 TimeSpan 對象轉(zhuǎn)換成用戶友好的自然語言描述Humanizer時間跨度人性化功能就開發(fā)工具上一篇如何快速掌握Hitboxer面向新手的SOCD鍵盤重映射完全實戰(zhàn)指南下一篇Hitboxer終極指南專業(yè)級SOCD鍵盤重映射工具深度解析與實戰(zhàn)應(yīng)用創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考