diff --git a/readme.md b/readme.md index e96a64159..1839ab43a 100644 --- a/readme.md +++ b/readme.md @@ -263,7 +263,7 @@ By default both methods throw a `NoMatchFoundException` when they cannot match t In the non-generic method you can also ask the method to return null by setting the second optional parameter to `NoMatch.ReturnsNull`. ###Humanize DateTime -You can `Humanize` an instance of `DateTime` and get back a string telling how far back or forward in time that is: +You can `Humanize` an instance of `DateTime` or `DateTimeOffset` and get back a string telling how far back or forward in time that is: ```C# DateTime.UtcNow.AddHours(-30).Humanize() => "yesterday" @@ -271,14 +271,17 @@ DateTime.UtcNow.AddHours(-2).Humanize() => "2 hours ago" DateTime.UtcNow.AddHours(30).Humanize() => "tomorrow" DateTime.UtcNow.AddHours(2).Humanize() => "2 hours from now" + +DateTimeOffset.AddHours(1).Humanize() => "an hour from now" ``` -Humanizer supports local as well as UTC dates. You could also provide the date you want the input date to be compared against. If null, it will use the current date as comparison base. +Humanizer supports both local and UTC dates as well as dates with offset (`DateTimeOffset`). You could also provide the date you want the input date to be compared against. If null, it will use the current date as comparison base. Also, culture to use can be specified explicitly. If it is not, current thread's current UI culture is used. Here is the API signature: ```C# public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null) +public static string Humanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst = null, CultureInfo culture = null) ``` Many localizations are available for this method. Here is a few examples: @@ -302,7 +305,10 @@ DateTime.UtcNow.AddMinutes(-40).Humanize() => "40 минут назад" There are two strategies for `DateTime.Humanize`: the default one as seen above and a precision based one. To use the precision based strategy you need to configure it: -`Configurator.DateTimeHumanizeStrategy = new PrecisionDateTimeHumanizeStrategy(precision = .75)`. +```C# +Configurator.DateTimeHumanizeStrategy = new PrecisionDateTimeHumanizeStrategy(precision = .75); +Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(precision = .75); // configure when humanizing DateTimeOffset +``` The default precision is set to .75 but you can pass your desired precision too. With precision set to 0.75: diff --git a/release_notes.md b/release_notes.md index 5577ff553..99a6374d1 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,4 +1,5 @@ ###In Development + - [#399](https://github.com/MehdiK/Humanizer/pull/399): Support for humanizing DateTimeOffset [Commits](https://github.com/MehdiK/Humanizer/compare/v1.34.0...master) diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt index 17307cfd5..46ef0744c 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -125,6 +125,7 @@ public class Configurator { public Humanizer.Configuration.LocaliserRegistry CollectionFormatters { get; } public Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; } + public Humanizer.DateTimeHumanizeStrategy.IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy { get; set; } public System.Func EnumDescriptionPropertyLocator { get; set; } public Humanizer.Configuration.LocaliserRegistry Formatters { get; } public Humanizer.Configuration.LocaliserRegistry NumberToWordsConverters { get; } @@ -144,6 +145,7 @@ public class LocaliserRegistry`1 public class DateHumanizeExtensions { public string Humanize(System.DateTime input, bool utcDate, System.Nullable dateToCompareAgainst, System.Globalization.CultureInfo culture) { } + public string Humanize(System.DateTimeOffset input, System.Nullable dateToCompareAgainst, System.Globalization.CultureInfo culture) { } } public class DefaultDateTimeHumanizeStrategy @@ -152,17 +154,34 @@ public class DefaultDateTimeHumanizeStrategy public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture) { } } +public class DefaultDateTimeOffsetHumanizeStrategy +{ + public DefaultDateTimeOffsetHumanizeStrategy() { } + public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo culture) { } +} + public interface IDateTimeHumanizeStrategy { string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture); } +public interface IDateTimeOffsetHumanizeStrategy +{ + string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo culture); +} + public class PrecisionDateTimeHumanizeStrategy { public PrecisionDateTimeHumanizeStrategy(double precision) { } public string Humanize(System.DateTime input, System.DateTime comparisonBase, System.Globalization.CultureInfo culture) { } } +public class PrecisionDateTimeOffsetHumanizeStrategy +{ + public PrecisionDateTimeOffsetHumanizeStrategy(double precision) { } + public string Humanize(System.DateTimeOffset input, System.DateTimeOffset comparisonBase, System.Globalization.CultureInfo culture) { } +} + public class EnumDehumanizeExtensions { public TTargetEnum DehumanizeTo(string input) { } diff --git a/src/Humanizer.Tests/DateTimeOffsetHumanizeTests.cs b/src/Humanizer.Tests/DateTimeOffsetHumanizeTests.cs new file mode 100644 index 000000000..c77357f41 --- /dev/null +++ b/src/Humanizer.Tests/DateTimeOffsetHumanizeTests.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Humanizer.Configuration; +using Humanizer.DateTimeHumanizeStrategy; +using Xunit; + +namespace Humanizer.Tests +{ + public class DateTimeOffsetHumanizeTests : AmbientCulture + { + public DateTimeOffsetHumanizeTests() : base("en-US") + { + } + + [Fact] + public void DefaultStrategy_SameOffset() + { + Configurator.DateTimeOffsetHumanizeStrategy = new DefaultDateTimeOffsetHumanizeStrategy(); + + var inputTime = new DateTimeOffset(2015, 07, 05, 04, 0, 0, TimeSpan.Zero); + var baseTime = new DateTimeOffset(2015, 07, 05, 03, 0, 0, TimeSpan.Zero); + + const string expectedResult = "an hour from now"; + var actualResult = inputTime.Humanize(baseTime); + + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void DefaultStrategy_DifferentOffsets() + { + Configurator.DateTimeOffsetHumanizeStrategy = new DefaultDateTimeOffsetHumanizeStrategy(); + + var inputTime = new DateTimeOffset(2015, 07, 05, 03, 0, 0, new TimeSpan(2, 0, 0)); + var baseTime = new DateTimeOffset(2015, 07, 05, 02, 30, 0, new TimeSpan(1, 0, 0)); + + const string expectedResult = "30 minutes ago"; + var actualResult = inputTime.Humanize(baseTime); + + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void PrecisionStrategy_SameOffset() + { + Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(0.75); + + var inputTime = new DateTimeOffset(2015, 07, 05, 04, 0, 0, TimeSpan.Zero); + var baseTime = new DateTimeOffset(2015, 07, 04, 05, 0, 0, TimeSpan.Zero); + + const string expectedResult = "tomorrow"; + var actualResult = inputTime.Humanize(baseTime); + + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void PrecisionStrategy_DifferentOffsets() + { + Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(0.75); + + var inputTime = new DateTimeOffset(2015, 07, 05, 03, 45, 0, new TimeSpan(2, 0, 0)); + var baseTime = new DateTimeOffset(2015, 07, 05, 02, 30, 0, new TimeSpan(-5, 0, 0)); + + const string expectedResult = "6 hours ago"; + var actualResult = inputTime.Humanize(baseTime); + + Assert.Equal(expectedResult, actualResult); + } + } +} \ No newline at end of file diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 556419e99..2e9aa81c0 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -67,6 +67,7 @@ + diff --git a/src/Humanizer/Configuration/Configurator.cs b/src/Humanizer/Configuration/Configurator.cs index c3605537b..facdd033b 100644 --- a/src/Humanizer/Configuration/Configurator.cs +++ b/src/Humanizer/Configuration/Configurator.cs @@ -99,6 +99,16 @@ public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy set { _dateTimeHumanizeStrategy = value; } } + private static IDateTimeOffsetHumanizeStrategy _dateTimeOffsetHumanizeStrategy = new DefaultDateTimeOffsetHumanizeStrategy(); + /// + /// The strategy to be used for DateTimeOffset.Humanize + /// + public static IDateTimeOffsetHumanizeStrategy DateTimeOffsetHumanizeStrategy + { + get { return _dateTimeOffsetHumanizeStrategy; } + set { _dateTimeOffsetHumanizeStrategy = value; } + } + private static readonly Func DefaultEnumDescriptionPropertyLocator = p => p.Name == "Description"; private static Func _enumDescriptionPropertyLocator = DefaultEnumDescriptionPropertyLocator; /// diff --git a/src/Humanizer/DateHumanizeExtensions.cs b/src/Humanizer/DateHumanizeExtensions.cs index 70874e073..9a6b0b0c0 100644 --- a/src/Humanizer/DateHumanizeExtensions.cs +++ b/src/Humanizer/DateHumanizeExtensions.cs @@ -26,5 +26,19 @@ public static string Humanize(this DateTime input, bool utcDate = true, DateTime return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture); } + + /// + /// Turns the current or provided date into a human readable sentence + /// + /// The date to be humanized + /// Date to compare the input against. If null, current date is used as base + /// Culture to use. If null, current thread's UI culture is used. + /// distance of time in words + 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); + } } } \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs b/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs new file mode 100644 index 000000000..ad1646c6c --- /dev/null +++ b/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs @@ -0,0 +1,116 @@ +using System; +using System.Globalization; +using Humanizer.Configuration; +using Humanizer.Localisation; + +namespace Humanizer.DateTimeHumanizeStrategy +{ + /// + /// Algorithms used to convert distance between two dates into words. + /// + internal static class DateTimeHumanizeAlgorithms + { + /// + /// Returns localized & humanized distance of time between two dates; given a specific precision. + /// + public static string 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; + + 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) + { + int factor = Convert.ToInt32(Math.Floor((double)days / 30)); + int maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 30)); + months = (days >= 30 * (factor + precision)) ? maxMonths : maxMonths - 1; + } + + // year calculation + if (days >= 365 * precision && days <= 366) years = 1; + if (days > 365) + { + int factor = Convert.ToInt32(Math.Floor((double)days / 365)); + int maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 365)); + years = (days >= 365 * (factor + precision)) ? maxMonths : maxMonths - 1; + } + + // start computing result from larger units to smaller ones + var formatter = Configurator.GetFormatter(culture); + if (years > 0) return formatter.DateHumanize(TimeUnit.Year, tense, years); + if (months > 0) return formatter.DateHumanize(TimeUnit.Month, tense, months); + if (days > 0) return formatter.DateHumanize(TimeUnit.Day, tense, days); + if (hours > 0) return formatter.DateHumanize(TimeUnit.Hour, tense, hours); + if (minutes > 0) return formatter.DateHumanize(TimeUnit.Minute, tense, minutes); + if (seconds > 0) return formatter.DateHumanize(TimeUnit.Second, tense, seconds); + return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); + } + + // http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time + /// + /// Calculates the distance of time in words between two provided dates + /// + 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 formatter = Configurator.GetFormatter(culture); + + if (ts.TotalMilliseconds < 500) + return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); + + if (ts.TotalSeconds < 60) + return formatter.DateHumanize(TimeUnit.Second, tense, ts.Seconds); + + if (ts.TotalSeconds < 120) + return formatter.DateHumanize(TimeUnit.Minute, tense, 1); + + if (ts.TotalMinutes < 60) + return formatter.DateHumanize(TimeUnit.Minute, tense, ts.Minutes); + + if (ts.TotalMinutes < 90) + return formatter.DateHumanize(TimeUnit.Hour, tense, 1); + + if (ts.TotalHours < 24) + return formatter.DateHumanize(TimeUnit.Hour, tense, ts.Hours); + + if (ts.TotalHours < 48) + { + var days = Math.Abs((input.Date - comparisonBase.Date).Days); + return formatter.DateHumanize(TimeUnit.Day, tense, days); + } + + if (ts.TotalDays < 28) + return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); + + if (ts.TotalDays >= 28 && ts.TotalDays < 30) + { + if (comparisonBase.Date.AddMonths(tense == Tense.Future ? 1 : -1) == input.Date) + return formatter.DateHumanize(TimeUnit.Month, tense, 1); + return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); + } + + if (ts.TotalDays < 345) + { + int months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); + return formatter.DateHumanize(TimeUnit.Month, tense, months); + } + + int years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); + if (years == 0) years = 1; + + return formatter.DateHumanize(TimeUnit.Year, tense, years); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs index 876cf7f9b..e8c97fdb0 100644 --- a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs +++ b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs @@ -1,7 +1,5 @@ using System; using System.Globalization; -using Humanizer.Configuration; -using Humanizer.Localisation; namespace Humanizer.DateTimeHumanizeStrategy { @@ -10,65 +8,12 @@ namespace Humanizer.DateTimeHumanizeStrategy /// public class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy { - // http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time /// - /// Calculates the distance of time in words between two provided dates + /// Calculates the distance of time in words between two provided dates /// - /// - /// - /// - /// public string Humanize(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 formatter = Configurator.GetFormatter(culture); - - if (ts.TotalMilliseconds < 500) - return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); - - if (ts.TotalSeconds < 60) - return formatter.DateHumanize(TimeUnit.Second, tense, ts.Seconds); - - if (ts.TotalSeconds < 120) - return formatter.DateHumanize(TimeUnit.Minute, tense, 1); - - if (ts.TotalMinutes < 60) - return formatter.DateHumanize(TimeUnit.Minute, tense, ts.Minutes); - - if (ts.TotalMinutes < 90) - return formatter.DateHumanize(TimeUnit.Hour, tense, 1); - - if (ts.TotalHours < 24) - return formatter.DateHumanize(TimeUnit.Hour, tense, ts.Hours); - - if (ts.TotalHours < 48) - { - var days = Math.Abs((input.Date - comparisonBase.Date).Days); - return formatter.DateHumanize(TimeUnit.Day, tense, days); - } - - if (ts.TotalDays < 28) - return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); - - if (ts.TotalDays >= 28 && ts.TotalDays < 30) - { - if (comparisonBase.Date.AddMonths(tense == Tense.Future ? 1 : -1) == input.Date) - return formatter.DateHumanize(TimeUnit.Month, tense, 1); - return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days); - } - - if (ts.TotalDays < 345) - { - int months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); - return formatter.DateHumanize(TimeUnit.Month, tense, months); - } - - int years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); - if (years == 0) years = 1; - - return formatter.DateHumanize(TimeUnit.Year, tense, years); + return DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture); } } } \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeOffsetHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeOffsetHumanizeStrategy.cs new file mode 100644 index 000000000..7f0ffc45c --- /dev/null +++ b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeOffsetHumanizeStrategy.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; + +namespace Humanizer.DateTimeHumanizeStrategy +{ + /// + /// The default 'distance of time' -> words calculator. + /// + public class DefaultDateTimeOffsetHumanizeStrategy : IDateTimeOffsetHumanizeStrategy + { + /// + /// Calculates the distance of time in words between two provided dates + /// + public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo culture) + { + return DateTimeHumanizeAlgorithms.DefaultHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, culture); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeOffsetHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeOffsetHumanizeStrategy.cs new file mode 100644 index 000000000..0cde54186 --- /dev/null +++ b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeOffsetHumanizeStrategy.cs @@ -0,0 +1,16 @@ +using System; +using System.Globalization; + +namespace Humanizer.DateTimeHumanizeStrategy +{ + /// + /// Implement this interface to create a new strategy for DateTime.Humanize and hook it in the Configurator.DateTimeOffsetHumanizeStrategy + /// + public interface IDateTimeOffsetHumanizeStrategy + { + /// + /// Calculates the distance of time in words between two provided dates used for DateTimeOffset.Humanize + /// + string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo culture); + } +} \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs index 64e9ba567..37bef4b9e 100644 --- a/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs +++ b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs @@ -1,12 +1,10 @@ using System; using System.Globalization; -using Humanizer.Configuration; -using Humanizer.Localisation; namespace Humanizer.DateTimeHumanizeStrategy { /// - /// + /// Precision-based calculator for distance between two times /// public class PrecisionDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy { @@ -24,51 +22,9 @@ public PrecisionDateTimeHumanizeStrategy(double precision = .75) /// /// Returns localized & humanized distance of time between two dates; given a specific precision. /// - /// - /// - /// - /// public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture) { - var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); - var tense = input > comparisonBase ? Tense.Future : Tense.Past; - - 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) - { - int factor = Convert.ToInt32(Math.Floor((double)days / 30)); - int maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 30)); - months = (days >= 30 * (factor + _precision)) ? maxMonths : maxMonths - 1; - } - - // year calculation - if (days >= 365 * _precision && days <= 366) years = 1; - if (days > 365) - { - int factor = Convert.ToInt32(Math.Floor((double)days / 365)); - int maxMonths = Convert.ToInt32(Math.Ceiling((double)days / 365)); - years = (days >= 365 * (factor + _precision)) ? maxMonths : maxMonths - 1; - } - - // start computing result from larger units to smaller ones - var formatter = Configurator.GetFormatter(culture); - if (years > 0) return formatter.DateHumanize(TimeUnit.Year, tense, years); - if (months > 0) return formatter.DateHumanize(TimeUnit.Month, tense, months); - if (days > 0) return formatter.DateHumanize(TimeUnit.Day, tense, days); - if (hours > 0) return formatter.DateHumanize(TimeUnit.Hour, tense, hours); - if (minutes > 0) return formatter.DateHumanize(TimeUnit.Minute, tense, minutes); - if (seconds > 0) return formatter.DateHumanize(TimeUnit.Second, tense, seconds); - return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0); + return DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, _precision, culture); } } } \ No newline at end of file diff --git a/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeOffsetHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeOffsetHumanizeStrategy.cs new file mode 100644 index 000000000..5b1738b5f --- /dev/null +++ b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeOffsetHumanizeStrategy.cs @@ -0,0 +1,30 @@ +using System; +using System.Globalization; + +namespace Humanizer.DateTimeHumanizeStrategy +{ + /// + /// Precision-based calculator for distance between two times + /// + public class PrecisionDateTimeOffsetHumanizeStrategy : IDateTimeOffsetHumanizeStrategy + { + private readonly double _precision; + + /// + /// Constructs a precision-based calculator for distance of time with default precision 0.75. + /// + /// precision of approximation, if not provided 0.75 will be used as a default precision. + public PrecisionDateTimeOffsetHumanizeStrategy(double precision = .75) + { + _precision = precision; + } + + /// + /// Returns localized & humanized distance of time between two dates; given a specific precision. + /// + public string Humanize(DateTimeOffset input, DateTimeOffset comparisonBase, CultureInfo culture) + { + return DateTimeHumanizeAlgorithms.PrecisionHumanize(input.UtcDateTime, comparisonBase.UtcDateTime, _precision, culture); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 78d0e49b4..e05415c86 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -52,6 +52,11 @@ + + + + + @@ -88,7 +93,6 @@ -