From ab8c2ff331d0e15f8537e02e95e968d081189bd3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sun, 3 Jan 2016 14:11:03 +0100 Subject: [PATCH] Use collection formatted to output of time indicators of humanized timespans. Fixes #497 --- readme.md | 22 ++++++++++ .../TimeSpanHumanizeTests.cs | 40 ++++++++++++++++++- ...provalTest.approve_public_api.approved.txt | 4 +- src/Humanizer/TimeSpanHumanizeExtensions.cs | 19 ++++++--- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/readme.md b/readme.md index e0be0c0d0..779e1fb1f 100644 --- a/readme.md +++ b/readme.md @@ -411,6 +411,28 @@ TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Day) => "7 days" // instead o TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Millisecond) => "2000 milliseconds" // instead of 2 seconds ``` +When there are multiple time units, they are combined using the `", "` string: + +```C# +TimeSpan.FromMilliseconds(1299630020).Humanize(3) => "2 weeks, 1 day, 1 hour" +```` + +Using the `collectionSeparator` parameter, you can specify your own separator string: + +```C# +TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: " - ") => "2 weeks - 1 day - 1 hour" +```` + +It is also possible to use the current culture's collection formatter to combine the time units. To do so, specify `null` as the `collectionSeparator` parameter: + +```C# +// in en-US culture +TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 weeks, 1 day, and 1 hour" + +// in de-DE culture +TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 Wochen, Ein Tag und Eine Stunde" +``` + ###Humanize Collections You can call `Humanize` on any `IEnumerable` to get a nicely formatted string representing the objects in the collection. By default `ToString()` will be called on each item to get its representation but a formatting function may be passed to `Humanize` instead. Additionally, a default separator is provided("and" in English), but a different separator may be passed into `Humanize`. diff --git a/src/Humanizer.Tests.Shared/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests.Shared/TimeSpanHumanizeTests.cs index 9355c89f1..9eadfb056 100644 --- a/src/Humanizer.Tests.Shared/TimeSpanHumanizeTests.cs +++ b/src/Humanizer.Tests.Shared/TimeSpanHumanizeTests.cs @@ -170,9 +170,9 @@ public void TimeSpanWithMinTimeUnit(int ms, string expected, TimeUnit minUnit) [InlineData(1299630020, 3, "2 weeks, 1 day, 1 hour")] [InlineData(1299630020, 4, "2 weeks, 1 day, 1 hour, 30 seconds")] [InlineData(1299630020, 5, "2 weeks, 1 day, 1 hour, 30 seconds, 20 milliseconds")] - public void TimeSpanWithPrecesion(int milliseconds, int precesion, string expected) + public void TimeSpanWithPrecision(int milliseconds, int precision, string expected) { - var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precesion); + var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision); Assert.Equal(expected, actual); } @@ -228,6 +228,42 @@ public void TimeSpanWithPrecisionAndCountingEmptyUnits(int milliseconds, int pre Assert.Equal(expected, actual); } + [Theory] + [InlineData(0, 3, "no time")] + [InlineData(0, 2, "no time")] + [InlineData(10, 2, "10 milliseconds")] + [InlineData(1400, 2, "1 second and 400 milliseconds")] + [InlineData(2500, 2, "2 seconds and 500 milliseconds")] + [InlineData(120000, 2, "2 minutes")] + [InlineData(62000, 2, "1 minute and 2 seconds")] + [InlineData(62020, 2, "1 minute and 2 seconds")] + [InlineData(62020, 3, "1 minute, 2 seconds, and 20 milliseconds")] + [InlineData(3600020, 4, "1 hour and 20 milliseconds")] + [InlineData(3600020, 3, "1 hour and 20 milliseconds")] + [InlineData(3600020, 2, "1 hour and 20 milliseconds")] + [InlineData(3600020, 1, "1 hour")] + [InlineData(3603001, 2, "1 hour and 3 seconds")] + [InlineData(3603001, 3, "1 hour, 3 seconds, and 1 millisecond")] + [InlineData(86400000, 3, "1 day")] + [InlineData(86400000, 2, "1 day")] + [InlineData(86400000, 1, "1 day")] + [InlineData(86401000, 1, "1 day")] + [InlineData(86401000, 2, "1 day and 1 second")] + [InlineData(86401200, 2, "1 day and 1 second")] + [InlineData(86401200, 3, "1 day, 1 second, and 200 milliseconds")] + [InlineData(1296000000, 1, "2 weeks")] + [InlineData(1296000000, 2, "2 weeks and 1 day")] + [InlineData(1299600000, 2, "2 weeks and 1 day")] + [InlineData(1299600000, 3, "2 weeks, 1 day, and 1 hour")] + [InlineData(1299630020, 3, "2 weeks, 1 day, and 1 hour")] + [InlineData(1299630020, 4, "2 weeks, 1 day, 1 hour, and 30 seconds")] + [InlineData(1299630020, 5, "2 weeks, 1 day, 1 hour, 30 seconds, and 20 milliseconds")] + public void TimeSpanWithPrecisionAndAlternativeCollectionFormatter(int milliseconds, int precision, string expected) + { + var actual = TimeSpan.FromMilliseconds(milliseconds).Humanize(precision, collectionSeparator: null); + Assert.Equal(expected, actual); + } + [Fact] public void NoTime() { 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 dd82aa384..b3eb3bf70 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -948,8 +948,8 @@ namespace Humanizer } public class static TimeSpanHumanizeExtensions { - public static string Humanize(this System.TimeSpan timeSpan, int precision = 1, System.Globalization.CultureInfo culture = null, Humanizer.Localisation.TimeUnit maxUnit = 5, Humanizer.Localisation.TimeUnit minUnit = 0) { } - public static string Humanize(this System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo culture = null, Humanizer.Localisation.TimeUnit maxUnit = 5, Humanizer.Localisation.TimeUnit minUnit = 0) { } + public static string Humanize(this System.TimeSpan timeSpan, int precision = 1, System.Globalization.CultureInfo culture = null, Humanizer.Localisation.TimeUnit maxUnit = 5, Humanizer.Localisation.TimeUnit minUnit = 0, string collectionSeparator = ", ") { } + public static string Humanize(this System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo culture = null, Humanizer.Localisation.TimeUnit maxUnit = 5, Humanizer.Localisation.TimeUnit minUnit = 0, string collectionSeparator = ", ") { } } public class static To { diff --git a/src/Humanizer/TimeSpanHumanizeExtensions.cs b/src/Humanizer/TimeSpanHumanizeExtensions.cs index 8461a2fa4..a384c9f19 100644 --- a/src/Humanizer/TimeSpanHumanizeExtensions.cs +++ b/src/Humanizer/TimeSpanHumanizeExtensions.cs @@ -24,10 +24,11 @@ public static class TimeSpanHumanizeExtensions /// Culture to use. If null, current thread's UI culture is used. /// The maximum unit of time to output. /// The minimum unit of time to output. + /// The separator to use when combining humanized time parts. If null, the default collection formatter for the current culture is used. /// - public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond) + public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ") { - return Humanize(timeSpan, precision, false, culture, maxUnit, minUnit); + return Humanize(timeSpan, precision, false, culture, maxUnit, minUnit, collectionSeparator); } /// @@ -39,13 +40,14 @@ public static string Humanize(this TimeSpan timeSpan, int precision = 1, Culture /// Culture to use. If null, current thread's UI culture is used. /// The maximum unit of time to output. /// The minimum unit of time to output. + /// The separator to use when combining humanized time parts. If null, the default collection formatter for the current culture is used. /// - public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond) + public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ") { var timeParts = CreateTheTimePartsWithUperAndLowerLimits(timeSpan, culture, maxUnit, minUnit); timeParts = SetPrecisionOfTimeSpan(timeParts, precision, countEmptyUnits); - return ConcatenateTimeSpanParts(timeParts); + return ConcatenateTimeSpanParts(timeParts, collectionSeparator); } private static IEnumerable CreateTheTimePartsWithUperAndLowerLimits(TimeSpan timespan, CultureInfo culture, TimeUnit maxUnit, TimeUnit minUnit) @@ -182,9 +184,14 @@ private static IEnumerable SetPrecisionOfTimeSpan(IEnumerable ti return timeParts; } - private static string ConcatenateTimeSpanParts(IEnumerable timeSpanParts) + private static string ConcatenateTimeSpanParts(IEnumerable timeSpanParts, string collectionSeparator) { - return string.Join(", ", timeSpanParts); + if (collectionSeparator == null) + { + return Configurator.CollectionFormatter.Humanize(timeSpanParts); + } + + return string.Join(collectionSeparator, timeSpanParts); } } } \ No newline at end of file