Skip to content

Commit

Permalink
Add TimeSpan.ToAge() extension method + tests
Browse files Browse the repository at this point in the history
- Introduce the `"TimeSpanHumanize_Age"` resource, indicating how to format a TimeSpan to an age expression.
- Add `Resources.TryGetResource` method, which attempts to retrieve a resource for a given culture but without falling back on the default culture. This will allow to define the resource for en-US (aka the default culture), but not have other cultures for which the resource is undefined fall back on the default culture.
- Add `DefaultFormatter.TimeSpanHumanize_Age()`, which resorts to `Resources.TryGetResource()` to determine how to express a TimeSpan as age. If no resource found, simply output the standard humanized TimeSpan as is. (This means that for certain cultures where standard TimeSpan and age expression differ, such as germanic languages, TimeSpanHumanize_Age resources will eventually need to be added.)
- Add tests for both English & 1 non-English (i.e. French) cultures
  • Loading branch information
louis-z committed Mar 20, 2022
1 parent 073db3a commit 5cca1a5
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,18 +167,6 @@ public void Age(int days, bool toWords, string expected)
Assert.Equal(expected, actual);
}

[Theory]
[InlineData(4, true, "")]
[InlineData(23, true, "")]
[InlineData(64, true, "")]
[InlineData(367, false, "")]
[InlineData(750, false, "")]
public void HyphenatedAge(int days, bool toWords, string expected)
{
var actual = TimeSpan.FromDays(days).ToHyphenatedAge(toWords: toWords);
Assert.Equal(expected, actual);
}

[Theory]
[InlineData(TimeUnit.Year, "0 an")]
[InlineData(TimeUnit.Month, "0 mois")]
Expand Down
12 changes: 0 additions & 12 deletions src/Humanizer.Tests.Shared/TimeSpanHumanizeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,6 @@ public void Age(int days, bool toWords, string expected)
Assert.Equal(expected, actual);
}

[Theory]
[InlineData(4, true, "four-day-old")]
[InlineData(23, true, "three-week-old")]
[InlineData(64, true, "two-month-old")]
[InlineData(367, false, "1-year-old")]
[InlineData(750, false, "2-year-old")]
public void HyphenatedAge(int days, bool toWords, string expected)
{
var actual = TimeSpan.FromDays(days).ToHyphenatedAge(toWords: toWords);
Assert.Equal(expected, actual);
}

[Theory]
[InlineData((long)366 * 24 * 60 * 60 * 1000, "12 months", TimeUnit.Month)]
[InlineData((long)6 * 7 * 24 * 60 * 60 * 1000, "6 weeks", TimeUnit.Week)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,6 @@ 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 static string ToAge(this System.TimeSpan timeSpan, System.Globalization.CultureInfo culture = null, bool toWords = False) { }
public static string ToHyphenatedAge(this System.TimeSpan timeSpan, System.Globalization.CultureInfo culture = null, bool toWords = False) { }
}
public class static TimeUnitToSymbolExtensions
{
Expand Down Expand Up @@ -1945,7 +1944,6 @@ 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_Age() { }
public virtual string TimeSpanHumanize_HyphenatedAge() { }
public virtual string TimeSpanHumanize_Zero() { }
public virtual string TimeUnitHumanize(Humanizer.Localisation.TimeUnit timeUnit) { }
}
Expand All @@ -1957,7 +1955,6 @@ namespace Humanizer.Localisation.Formatters
string DateHumanize_Now();
string TimeSpanHumanize(Humanizer.Localisation.TimeUnit timeUnit, int unit, bool toWords = False);
string TimeSpanHumanize_Age();
string TimeSpanHumanize_HyphenatedAge();
string TimeSpanHumanize_Zero();
string TimeUnitHumanize(Humanizer.Localisation.TimeUnit timeUnit);
}
Expand Down
10 changes: 3 additions & 7 deletions src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,9 @@ public virtual string TimeSpanHumanize(TimeUnit timeUnit, int unit, bool toWords
/// <inheritdoc/>
public virtual string TimeSpanHumanize_Age()
{
return Resources.GetResource("TimeSpanHumanize_Age", _culture);
}

/// <inheritdoc/>
public virtual string TimeSpanHumanize_HyphenatedAge()
{
return Resources.GetResource("TimeSpanHumanize_HyphenatedAge", _culture);
if (Resources.TryGetResource("TimeSpanHumanize_Age", _culture, out var ageFormat))
return ageFormat;
return "{0}";
}

/// <inheritdoc cref="IFormatter.DataUnitHumanize(DataUnit, double, bool)"/>
Expand Down
9 changes: 0 additions & 9 deletions src/Humanizer/Localisation/Formatters/IFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@ public interface IFormatter
/// <returns>Age format</returns>
string TimeSpanHumanize_Age();

/// <summary>
/// Returns the age format that converts a humanized TimeSpan string to an hyphenated age expression.
/// </summary>
/// <returns>Hyphenated age format</returns>
/// <remarks>
/// In all languages but English an empty string is returned, as the notion of hyphenated age does not exist.
/// </remarks>
string TimeSpanHumanize_HyphenatedAge();

/// <summary>
/// Returns the string representation of the provided DataUnit, either as a symbol or full word
/// </summary>
Expand Down
23 changes: 23 additions & 0 deletions src/Humanizer/Localisation/Resources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,28 @@ public static string GetResource(string resourceKey, CultureInfo culture = null)
{
return ResourceManager.GetString(resourceKey, culture);
}

/// <summary>
/// Tries to get the value of the specified string resource, without fallback
/// </summary>
/// <param name="resourceKey">The name of the resource to retrieve.</param>
/// <param name="culture">The culture of the resource to retrieve. If not specified, current thread's UI culture is used.</param>
/// <param name="result">The value of the resource localized for the specified culture if found; null otherwise.</param>
/// <returns>true if the specified string resource was found for the given culture; otherwise, false.</returns>
/// <remarks>
/// (In .NET Standard 1.0, this method will not strictly adhere to the above contract.
/// It may fall back on the default culture.)
/// </remarks>
public static bool TryGetResource(string resourceKey, CultureInfo culture, out string result)
{
#if NETSTANDARD1_0
result = GetResource(resourceKey, culture);
#else
culture ??= CultureInfo.CurrentUICulture;
var resourceSet = ResourceManager.GetResourceSet(culture, createIfNotExists: false, tryParents: false);
result = resourceSet?.GetString(resourceKey);
#endif
return result is not null;
}
}
}
6 changes: 0 additions & 6 deletions src/Humanizer/Properties/Resources.fr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,4 @@
<data name="DataUnit_TerabyteSymbol" xml:space="preserve">
<value>To</value>
</data>
<data name="TimeSpanHumanize_Age" xml:space="preserve">
<value>{0}</value>
</data>
<data name="TimeSpanHumanize_HyphenatedAge" xml:space="preserve">
<value></value>
</data>
</root>
3 changes: 0 additions & 3 deletions src/Humanizer/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,4 @@
<data name="TimeSpanHumanize_Age" xml:space="preserve">
<value>{0} old</value>
</data>
<data name="TimeSpanHumanize_HyphenatedAge" xml:space="preserve">
<value>{0}-old</value>
</data>
</root>
22 changes: 3 additions & 19 deletions src/Humanizer/TimeSpanHumanizeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,19 @@ public static string Humanize(this TimeSpan timeSpan, int precision, bool countE
/// </summary>
/// <param name="timeSpan">Elapsed time</param>
/// <param name="culture">Culture to use. If null, current thread's UI culture is used.</param>
/// <param name="maxUnit">The maximum unit of time to output. The default value is <see cref="TimeUnit.Year"/>.</param>
/// <param name="toWords">Uses words instead of numbers if true. E.g. "forty years old".</param>
/// <returns>Age expression in the given culture/language</returns>
public static string ToAge(this TimeSpan timeSpan, CultureInfo culture = null, bool toWords = false)
public static string ToAge(this TimeSpan timeSpan, CultureInfo culture = null, TimeUnit maxUnit = TimeUnit.Year, bool toWords = false)
{
var timeSpanExpression = timeSpan.Humanize(maxUnit: TimeUnit.Year, culture: culture, toWords: toWords);
var timeSpanExpression = timeSpan.Humanize(culture: culture, maxUnit: maxUnit, toWords: toWords);

var cultureFormatter = Configurator.GetFormatter(culture);
var ageExpression = string.Format(cultureFormatter.TimeSpanHumanize_Age(), timeSpanExpression);

return ageExpression;
}

/// <summary>
/// Turns a TimeSpan into an hyphenated age expression, e.g. a "40-year-old"
/// </summary>
/// <param name="timeSpan">Elapsed time</param>
/// <param name="culture">Culture to use. If null, current thread's UI culture is used.</param>
/// <param name="toWords">Uses words instead of numbers if true. E.g. a "forty-year-old".</param>
/// <returns>Hyphenated age expression if the given language is English, empty string otherwise</returns>
public static string ToHyphenatedAge(this TimeSpan timeSpan, CultureInfo culture = null, bool toWords = false)
{
var timeSpanExpression = timeSpan.Humanize(maxUnit: TimeUnit.Year, culture: culture, toWords: toWords);

var cultureFormatter = Configurator.GetFormatter(culture);
var ageExpression = string.Format(cultureFormatter.TimeSpanHumanize_HyphenatedAge(), timeSpanExpression.Singularize().Replace(' ', '-'));

return ageExpression;
}

private static IEnumerable<string> CreateTheTimePartsWithUpperAndLowerLimits(TimeSpan timespan, CultureInfo culture, TimeUnit maxUnit, TimeUnit minUnit, bool toWords = false)
{
var cultureFormatter = Configurator.GetFormatter(culture);
Expand Down

0 comments on commit 5cca1a5

Please sign in to comment.