Humanize relative dates and times
Orientation
Relative humanization compares a temporal value with a known base and returns text such as yesterday, 3 hours ago, or a month from now. Pass both the comparison base and culture when output must be deterministic. Choose the overload that preserves the semantics of DateTime, DateTimeOffset, DateOnly, or TimeOnly.
Example
The example compares two UTC DateTime values and never reads the machine clock.
The same explicit CultureInfo argument is available on the DateTimeOffset,
DateOnly, and TimeOnly overloads:
using System.Globalization;
using Humanizer;
var culture = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
var comparison = new DateTime(2025, 1, 20, 12, 0, 0, DateTimeKind.Utc);
var relative = comparison.AddDays(-1).Humanize(
utcDate: true,
dateToCompareAgainst: comparison,
culture: culture);
var offsetComparison = new DateTimeOffset(comparison);
var offsetRelative = offsetComparison.AddDays(-1).Humanize(offsetComparison, culture);
var dateOnlyComparison = new DateOnly(2025, 1, 20);
var dateOnlyRelative = dateOnlyComparison.AddDays(-1).Humanize(dateOnlyComparison, culture);
var timeOnlyComparison = new TimeOnly(12, 0);
var timeOnlyRelative = timeOnlyComparison.AddMinutes(1).Humanize(timeOnlyComparison, culture: culture);
var duration = TimeSpan.FromMinutes(125).Humanize(precision: 2, culture: culture);
AssertEqual("yesterday", relative);
AssertEqual("yesterday", offsetRelative);
AssertEqual("yesterday", dateOnlyRelative);
AssertEqual("a minute from now", timeOnlyRelative);
AssertEqual("2 hours, 5 minutes", duration);
Console.WriteLine($"{relative}; {offsetRelative}; {dateOnlyRelative}; {timeOnlyRelative}; {duration}");
static void AssertEqual(string expected, string actual)
{
if (actual != expected)
throw new InvalidOperationException($"Expected '{expected}', got '{actual}'.");
}
Choose the temporal type
| Type | Comparison meaning |
|---|---|
DateTime | Local or UTC behavior selected by utcDate and Kind |
DateTimeOffset | Two offset-aware instants |
DateOnly | Calendar dates without a time of day |
TimeOnly | Times of day without a calendar date |
Nullable overloads return the locale’s “never” phrase for null. That is useful for optional activity timestamps but should not replace explicit missing-value handling in domain logic.
Configure thresholds once
The default strategies choose familiar boundaries such as “yesterday.” PrecisionDateTimeHumanizeStrategy and its sibling strategies use a precision factor when applications need more gradual thresholds. Assign a strategy through Configurator once during startup.
Pitfall
Do not compare a local DateTime with a UTC base accidentally. Humanizer converts the injected comparison according to utcDate; mixed Kind values can move the boundary. TimeOnly has no date context, so a comparison around midnight cannot know whether the intended event was yesterday or tomorrow.
Version notes
DateTime and DateTimeOffset support span the documented corpus. DateOnly and TimeOnly humanization begin in 2.11.10 on compatible target frameworks. Strategy types and thresholds are selected-version behavior.