diff --git a/readme.md b/readme.md index a944800f9..79ab0e674 100644 --- a/readme.md +++ b/readme.md @@ -44,6 +44,7 @@ Humanizer meets all your .NET needs for manipulating and displaying strings, enu - [ByteSize](#bytesize) - [Heading to words](#heading-to-words) - [Tupleize](#tupleize) + - [Time unit to symbol](#timeunit-to-symbol) - [Mix this into your framework to simplify your life](#mix-this-into-your-framework-to-simplify-your-life) - - [How to contribute?](#how-to-contribute) - [Continuous Integration from AppVeyor](#continuous-integration) @@ -1109,6 +1110,18 @@ Humanizer can change whole numbers into their 'tuple' using `Tupleize`. For exa The numbers 1-10, 100 and 1000 will be converted into a 'named' tuple (i.e. "single", "double" etc.). Any other number "n" will be converted to "n-tuple". +### Time unit to symbol +Humanizer can translate time units to their symbols: + +```C# +TimeUnit.Day.ToSymbol(); +// d +TimeUnit.Week.ToSymbol(); +// week +TimeUnit.Year.ToSymbol(); +// y +``` + ## Mix this into your framework to simplify your life This is just a baseline and you can use this to simplify your day to day job. For example, in Asp.Net MVC we keep chucking `Display` attribute on ViewModel properties so `HtmlHelper` can generate correct labels for us; but, just like enums, in vast majority of cases we just need a space between the words in property name - so why not use `"string".Humanize` for that?! diff --git a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems index 17c44126e..590113f49 100644 --- a/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems +++ b/src/Humanizer.Tests.Shared/Humanizer.Tests.Shared.projitems @@ -71,6 +71,7 @@ + @@ -203,6 +204,7 @@ + diff --git a/src/Humanizer.Tests.Shared/Localisation/de/TimeUnitToSymbolTests.cs b/src/Humanizer.Tests.Shared/Localisation/de/TimeUnitToSymbolTests.cs new file mode 100644 index 000000000..2b334ba26 --- /dev/null +++ b/src/Humanizer.Tests.Shared/Localisation/de/TimeUnitToSymbolTests.cs @@ -0,0 +1,27 @@ +using System; + +using Humanizer.Localisation; + +using Xunit; + +namespace Humanizer.Tests.Localisation.de +{ + [UseCulture("de-DE")] + public class TimeUnitToSymbolTests + { + [Theory] + [Trait("Translation", "Native speaker")] + [InlineData(TimeUnit.Millisecond, "ms")] + [InlineData(TimeUnit.Second, "s")] + [InlineData(TimeUnit.Minute, "min")] + [InlineData(TimeUnit.Hour, "h")] + [InlineData(TimeUnit.Day, "d")] + [InlineData(TimeUnit.Week, "Woche")] + [InlineData(TimeUnit.Month, "M")] + [InlineData(TimeUnit.Year, "a")] + public void ToSymbol(TimeUnit unit, string expected) + { + Assert.Equal(expected, unit.ToSymbol()); + } + } +} diff --git a/src/Humanizer.Tests.Shared/TimeUnitToSymbolTests.cs b/src/Humanizer.Tests.Shared/TimeUnitToSymbolTests.cs new file mode 100644 index 000000000..759b17e1e --- /dev/null +++ b/src/Humanizer.Tests.Shared/TimeUnitToSymbolTests.cs @@ -0,0 +1,24 @@ +using Humanizer.Localisation; + +using Xunit; + +namespace Humanizer.Tests +{ + [UseCulture("en-US")] + public class TimeUnitToSymbolTests + { + [Theory] + [InlineData(TimeUnit.Millisecond, "ms")] + [InlineData(TimeUnit.Second, "s")] + [InlineData(TimeUnit.Minute, "min")] + [InlineData(TimeUnit.Hour, "h")] + [InlineData(TimeUnit.Day, "d")] + [InlineData(TimeUnit.Week, "week")] + [InlineData(TimeUnit.Month, "mo")] + [InlineData(TimeUnit.Year, "y")] + public void ToSymbol(TimeUnit unit, string expected) + { + Assert.Equal(expected, unit.ToSymbol()); + } + } +} 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 53cfd1a1c..f41cef7d1 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -1583,6 +1583,10 @@ namespace Humanizer 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 = ", ", bool toWords = False) { } 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 = ", ", bool toWords = False) { } } + public class static TimeUnitToSymbolExtensions + { + public static string ToSymbol(this Humanizer.Localisation.TimeUnit unit, System.Globalization.CultureInfo culture = null) { } + } public class static To { public static Humanizer.ICulturedStringTransformer LowerCase { get; } @@ -1852,6 +1856,10 @@ namespace Humanizer.Localisation { public static string GetResourceKey(Humanizer.Localisation.TimeUnit unit, int count = 1, bool toWords = False) { } } + public class static TimeUnitSymbol + { + public static string GetResourceKey(Humanizer.Localisation.TimeUnit unit) { } + } } public class static Resources { @@ -1902,6 +1910,7 @@ namespace Humanizer.Localisation.Formatters protected virtual string GetResourceKey(string resourceKey) { } public virtual string TimeSpanHumanize(Humanizer.Localisation.TimeUnit timeUnit, int unit, bool toWords = False) { } public virtual string TimeSpanHumanize_Zero() { } + public virtual string TimeUnitHumanize(Humanizer.Localisation.TimeUnit timeUnit) { } } public interface IFormatter { @@ -1911,6 +1920,7 @@ namespace Humanizer.Localisation.Formatters string DateHumanize_Now(); string TimeSpanHumanize(Humanizer.Localisation.TimeUnit timeUnit, int unit, bool toWords = False); string TimeSpanHumanize_Zero(); + string TimeUnitHumanize(Humanizer.Localisation.TimeUnit timeUnit); } } namespace Humanizer.Localisation.NumberToWords diff --git a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs index d3b410990..baa74d7e6 100644 --- a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs @@ -83,6 +83,13 @@ public virtual string DataUnitHumanize(DataUnit dataUnit, double count, bool toS return resourceValue; } + /// + public virtual string TimeUnitHumanize(TimeUnit timeUnit) + { + var resourceKey = ResourceKeys.TimeUnitSymbol.GetResourceKey(timeUnit); + return Format(resourceKey); + } + private string GetResourceForDate(TimeUnit unit, Tense timeUnitTense, int count) { var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count); diff --git a/src/Humanizer/Localisation/Formatters/IFormatter.cs b/src/Humanizer/Localisation/Formatters/IFormatter.cs index 64e06c3dd..772d66c24 100644 --- a/src/Humanizer/Localisation/Formatters/IFormatter.cs +++ b/src/Humanizer/Localisation/Formatters/IFormatter.cs @@ -51,5 +51,12 @@ public interface IFormatter /// Indicates whether the data unit should be expressed as symbol or full word /// String representation of the provided DataUnit string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true); + + /// + /// Returns the symbol for the given TimeUnit + /// + /// Time unit + /// String representation of the provided TimeUnit + string TimeUnitHumanize(TimeUnit timeUnit); } } diff --git a/src/Humanizer/Localisation/ResourceKeys.TimeUnitSymbol.cs b/src/Humanizer/Localisation/ResourceKeys.TimeUnitSymbol.cs new file mode 100644 index 000000000..c008fdb47 --- /dev/null +++ b/src/Humanizer/Localisation/ResourceKeys.TimeUnitSymbol.cs @@ -0,0 +1,28 @@ +namespace Humanizer.Localisation +{ + public partial class ResourceKeys + { + /// + /// Encapsulates the logic required to get the resource keys for TimeUnit.ToSymbol + /// + public static class TimeUnitSymbol + { + /// + /// Examples: TimeUnit_Minute, TimeUnit_Hour. + /// + private const string TimeUnitFormat = "TimeUnit_{0}"; + + /// + /// Generates Resource Keys according to convention. + /// + /// Time unit, . + /// Number of units, default is One. + /// Result to words, default is false. + /// Resource key, like TimeSpanHumanize_SingleMinute + public static string GetResourceKey(TimeUnit unit) + { + return TimeUnitFormat.FormatWith(unit); + } + } + } +} diff --git a/src/Humanizer/Properties/Resources.de.resx b/src/Humanizer/Properties/Resources.de.resx index 37f688366..b127c0b49 100644 --- a/src/Humanizer/Properties/Resources.de.resx +++ b/src/Humanizer/Properties/Resources.de.resx @@ -402,4 +402,28 @@ TB + + ms + + + s + + + min + + + h + + + d + + + Woche + + + M + + + a + \ No newline at end of file diff --git a/src/Humanizer/Properties/Resources.resx b/src/Humanizer/Properties/Resources.resx index 8683674b6..d1c7050c4 100644 --- a/src/Humanizer/Properties/Resources.resx +++ b/src/Humanizer/Properties/Resources.resx @@ -711,4 +711,28 @@ TB + + ms + + + s + + + min + + + h + + + d + + + week + + + mo + + + y + \ No newline at end of file diff --git a/src/Humanizer/TimeUnitToSymbolExtensions.cs b/src/Humanizer/TimeUnitToSymbolExtensions.cs new file mode 100644 index 000000000..86a3b6bd6 --- /dev/null +++ b/src/Humanizer/TimeUnitToSymbolExtensions.cs @@ -0,0 +1,24 @@ +using System.Globalization; + +using Humanizer.Localisation; +using Humanizer.Configuration; + +namespace Humanizer +{ + /// + /// Transform a time unit into a symbol; e.g. => "a" + /// + public static class TimeUnitToSymbolExtensions + { + /// + /// TimeUnit.Day.ToSymbol() -> "d" + /// + /// Unit of time to be turned to a symbol + /// Culture to use. If null, current thread's UI culture is used. + /// + public static string ToSymbol(this TimeUnit unit, CultureInfo culture = null) + { + return Configurator.GetFormatter(culture).TimeUnitHumanize(unit); + } + } +}