From 7130b2ba0940e6cf08bf30c96bdaead711035fa6 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Sat, 21 Feb 2015 00:25:30 -0600 Subject: [PATCH 1/6] Added maximum time unit to TimeSpan humanization. --- src/Humanizer.Tests/TimeSpanHumanizeTests.cs | 13 +++++++ src/Humanizer/TimeSpanHumanizeExtensions.cs | 38 ++++++++++---------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/Humanizer.Tests/TimeSpanHumanizeTests.cs b/src/Humanizer.Tests/TimeSpanHumanizeTests.cs index 345dbd5c2..9108b5a4a 100644 --- a/src/Humanizer.Tests/TimeSpanHumanizeTests.cs +++ b/src/Humanizer.Tests/TimeSpanHumanizeTests.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using Humanizer.Localisation; using Xunit; using Xunit.Extensions; @@ -68,6 +69,18 @@ public void Milliseconds(int ms, string expected) Assert.Equal(expected, actual); } + [Theory] + [InlineData(7 * 24 * 60 * 60 * 1000, "7 days", TimeUnit.Day)] + [InlineData(24 * 60 * 60 * 1000, "24 hours", TimeUnit.Hour)] + [InlineData(60 * 60 * 1000, "60 minutes", TimeUnit.Minute)] + [InlineData(60 * 1000, "60 seconds", TimeUnit.Second)] + [InlineData(1000, "1000 milliseconds", TimeUnit.Millisecond)] + public void TimeSpanWithMaxTimeUnit(int ms, string expected, TimeUnit maxUnit) + { + var actual = TimeSpan.FromMilliseconds(ms).Humanize(maxUnit: maxUnit); + Assert.Equal(expected, actual); + } + [Theory] [InlineData(0, 3, "no time")] [InlineData(0, 2, "no time")] diff --git a/src/Humanizer/TimeSpanHumanizeExtensions.cs b/src/Humanizer/TimeSpanHumanizeExtensions.cs index 6914b9cef..bd22bc627 100644 --- a/src/Humanizer/TimeSpanHumanizeExtensions.cs +++ b/src/Humanizer/TimeSpanHumanizeExtensions.cs @@ -19,10 +19,11 @@ public static class TimeSpanHumanizeExtensions /// /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned /// Culture to use. If null, current thread's UI culture is used. + /// The maximum unit of time to use. /// - public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo culture = null) + public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week) { - return Humanize(timeSpan, precision, false, culture); + return Humanize(timeSpan, precision, false, culture, maxUnit); } /// @@ -32,10 +33,11 @@ public static string Humanize(this TimeSpan timeSpan, int precision = 1, Culture /// The maximum number of time units to return. /// Controls whether empty time units should be counted towards maximum number of time units. Leading empty time units never count. /// Culture to use. If null, current thread's UI culture is used. + /// The maximum unit of time to use. /// - public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo culture = null) + public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week) { - var timeParts = GetTimeParts(timeSpan, culture); + var timeParts = GetTimeParts(timeSpan, culture, maxUnit); if (!countEmptyUnits) timeParts = timeParts.Where(x => x != null); timeParts = timeParts.Take(precision); @@ -44,27 +46,27 @@ public static string Humanize(this TimeSpan timeSpan, int precision, bool countE return string.Join(", ", timeParts); } - private static IEnumerable GetTimeParts(TimeSpan timespan, CultureInfo culture) + private static IEnumerable GetTimeParts(TimeSpan timespan, CultureInfo culture, TimeUnit maxUnit) { - var weeks = timespan.Days / 7; - var daysInWeek = timespan.Days % 7; - var hours = timespan.Hours; - var minutes = timespan.Minutes; - var seconds = timespan.Seconds; - var milliseconds = timespan.Milliseconds; + var weeks = maxUnit > TimeUnit.Day ? timespan.Days / 7 : 0; + var days = maxUnit > TimeUnit.Day ? timespan.Days % 7 : (int)timespan.TotalDays; + var hours = maxUnit > TimeUnit.Hour ? timespan.Hours : (int)timespan.TotalHours; + var minutes = maxUnit > TimeUnit.Minute ? timespan.Minutes : (int)timespan.TotalMinutes; + var seconds = maxUnit > TimeUnit.Second ? timespan.Seconds : (int)timespan.TotalSeconds; + var milliseconds = maxUnit > TimeUnit.Millisecond ? timespan.Milliseconds : (int)timespan.TotalMilliseconds; - var outputWeeks = weeks > 0; - var outputDays = outputWeeks || daysInWeek > 0; - var outputHours = outputDays || hours > 0; - var outputMinutes = outputHours || minutes > 0; - var outputSeconds = outputMinutes || seconds > 0; - var outputMilliseconds = outputSeconds || milliseconds > 0; + var outputWeeks = weeks > 0 && maxUnit == TimeUnit.Week; + var outputDays = (outputWeeks || days > 0) && maxUnit >= TimeUnit.Day; + var outputHours = (outputDays || hours > 0) && maxUnit >= TimeUnit.Hour; + var outputMinutes = (outputHours || minutes > 0) && maxUnit >= TimeUnit.Minute; + var outputSeconds = (outputMinutes || seconds > 0) && maxUnit >= TimeUnit.Second; + var outputMilliseconds = (outputSeconds || milliseconds > 0) && maxUnit >= TimeUnit.Millisecond; var formatter = Configurator.GetFormatter(culture); if (outputWeeks) yield return GetTimePart(formatter, TimeUnit.Week, weeks); if (outputDays) - yield return GetTimePart(formatter, TimeUnit.Day, daysInWeek); + yield return GetTimePart(formatter, TimeUnit.Day, days); if (outputHours) yield return GetTimePart(formatter, TimeUnit.Hour, hours); if (outputMinutes) From 2c65bde11bced7643821a1a53a986dbff1dd9555 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Sat, 21 Feb 2015 01:48:32 -0600 Subject: [PATCH 2/6] Updated API approval test. --- .../PublicApiApprovalTest.approve_public_api.approved.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 955bf1c34..17307cfd5 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -468,8 +468,8 @@ public class StringHumanizeExtensions public class TimeSpanHumanizeExtensions { - public string Humanize(System.TimeSpan timeSpan, int precision, System.Globalization.CultureInfo culture) { } - public string Humanize(System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo culture) { } + public string Humanize(System.TimeSpan timeSpan, int precision, System.Globalization.CultureInfo culture, Humanizer.Localisation.TimeUnit maxUnit) { } + public string Humanize(System.TimeSpan timeSpan, int precision, bool countEmptyUnits, System.Globalization.CultureInfo culture, Humanizer.Localisation.TimeUnit maxUnit) { } } public class To From d0b03c284612833a3281178fef319f1319e23d44 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 23 Feb 2015 10:28:48 -0600 Subject: [PATCH 3/6] Changed comments. --- src/Humanizer/TimeSpanHumanizeExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Humanizer/TimeSpanHumanizeExtensions.cs b/src/Humanizer/TimeSpanHumanizeExtensions.cs index bd22bc627..d9fb7d41c 100644 --- a/src/Humanizer/TimeSpanHumanizeExtensions.cs +++ b/src/Humanizer/TimeSpanHumanizeExtensions.cs @@ -19,7 +19,7 @@ public static class TimeSpanHumanizeExtensions /// /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned /// Culture to use. If null, current thread's UI culture is used. - /// The maximum unit of time to use. + /// The maximum unit of time to output. /// public static string Humanize(this TimeSpan timeSpan, int precision = 1, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week) { @@ -33,7 +33,7 @@ public static string Humanize(this TimeSpan timeSpan, int precision = 1, Culture /// The maximum number of time units to return. /// Controls whether empty time units should be counted towards maximum number of time units. Leading empty time units never count. /// Culture to use. If null, current thread's UI culture is used. - /// The maximum unit of time to use. + /// The maximum unit of time to output. /// public static string Humanize(this TimeSpan timeSpan, int precision, bool countEmptyUnits, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Week) { From 0d5f02f41d62d2f529af2555bf9f0619b79b4a8f Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 23 Feb 2015 10:30:06 -0600 Subject: [PATCH 4/6] Updated readme. --- readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.md b/readme.md index eb4c35b3c..84e9a1d7c 100644 --- a/readme.md +++ b/readme.md @@ -370,6 +370,12 @@ Culture to use can be specified explicitly. If it is not, current thread's curre TimeSpan.FromDays(1).Humanize(culture: "ru-RU") => "один день" ``` +In addition, a maximum unit of time may be specified to avoid rolling up to the next largest unit. For example: +```C# +TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Days) => "7 days" // instead of 1 week +TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Milliseconds) => "2000 milliseconds" // instead of 2 seconds +``` + ###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`. From 2744ae4bbdcca9c22dd6632295464c17dca474a6 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 23 Feb 2015 10:48:34 -0600 Subject: [PATCH 5/6] Fixed enum names. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 84e9a1d7c..e96a64159 100644 --- a/readme.md +++ b/readme.md @@ -372,8 +372,8 @@ TimeSpan.FromDays(1).Humanize(culture: "ru-RU") => "один день" In addition, a maximum unit of time may be specified to avoid rolling up to the next largest unit. For example: ```C# -TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Days) => "7 days" // instead of 1 week -TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Milliseconds) => "2000 milliseconds" // instead of 2 seconds +TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Day) => "7 days" // instead of 1 week +TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Millisecond) => "2000 milliseconds" // instead of 2 seconds ``` ###Humanize Collections From f80064cdffd98df0431e464384db02efc179a6c0 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 23 Feb 2015 10:59:26 -0600 Subject: [PATCH 6/6] Added release notes entry. --- release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release_notes.md b/release_notes.md index afa84d524..311731fbc 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,6 +1,7 @@ ###In Development - [#381](https://github.com/MehdiK/Humanizer/pull/381): Fixes trailing question mark reported in #378. - [#382](https://github.com/MehdiK/Humanizer/pull/382): Fix 90000th and -thousandth in RussianNumberToWordsConverter. + - [#384](https://github.com/MehdiK/Humanizer/pull/384): Added maximum TimeUnit to TimeSpanHumanizeExtensions.Humanize to enable prevention of rolling up the next largest unit of time. [Commits](https://github.com/MehdiK/Humanizer/compare/v1.33.7...master)