diff --git a/src/Humanizer.Tests.Shared/DateHumanize.cs b/src/Humanizer.Tests.Shared/DateHumanize.cs
index edfd67c1a..78f40b4b2 100644
--- a/src/Humanizer.Tests.Shared/DateHumanize.cs
+++ b/src/Humanizer.Tests.Shared/DateHumanize.cs
@@ -11,30 +11,30 @@ public class DateHumanize
{
private static readonly object LockObject = new object();
- private static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow, CultureInfo culture)
+ private static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow, CultureInfo culture, DateTimeExpressionProvider dateTimeExpressionProvider)
{
var utcNow = DateTime.UtcNow;
var localNow = DateTime.Now;
// feels like the only way to avoid breaking tests because CPU ticks over is to inject the base date
- VerifyWithDate(expectedString, deltaFromNow, culture, localNow, utcNow);
+ VerifyWithDate(expectedString, deltaFromNow, culture, localNow, utcNow, dateTimeExpressionProvider);
}
- private static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow, CultureInfo culture)
+ private static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow, CultureInfo culture, DateTimeExpressionProvider dateTimeExpressionProvider)
{
var utcNow = new DateTime(2013, 6, 20, 9, 58, 22, DateTimeKind.Utc);
var now = new DateTime(2013, 6, 20, 11, 58, 22, DateTimeKind.Local);
- VerifyWithDate(expectedString, deltaFromNow, culture, now, utcNow);
+ VerifyWithDate(expectedString, deltaFromNow, culture, now, utcNow, dateTimeExpressionProvider);
}
- private static void VerifyWithDate(string expectedString, TimeSpan deltaFromBase, CultureInfo culture, DateTime baseDate, DateTime baseDateUtc)
+ private static void VerifyWithDate(string expectedString, TimeSpan deltaFromBase, CultureInfo culture, DateTime baseDate, DateTime baseDateUtc, DateTimeExpressionProvider dateTimeExpressionProvider)
{
- Assert.Equal(expectedString, baseDateUtc.Add(deltaFromBase).Humanize(utcDate: true, dateToCompareAgainst: baseDateUtc, culture: culture));
- Assert.Equal(expectedString, baseDate.Add(deltaFromBase).Humanize(false, baseDate, culture: culture));
+ Assert.Equal(expectedString, baseDateUtc.Add(deltaFromBase).Humanize(utcDate: true, dateToCompareAgainst: baseDateUtc, culture: culture, dateTimeExpressionProvider));
+ Assert.Equal(expectedString, baseDate.Add(deltaFromBase).Humanize(false, baseDate, culture: culture, dateTimeExpressionProvider));
}
- public static void Verify(string expectedString, int unit, TimeUnit timeUnit, Tense tense, double? precision = null, CultureInfo culture = null, DateTime? baseDate = null, DateTime? baseDateUtc = null)
+ public static void Verify(string expectedString, int unit, TimeUnit timeUnit, Tense tense, double? precision = null, CultureInfo culture = null, DateTime? baseDate = null, DateTime? baseDateUtc = null, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
// We lock this as these tests can be multi-threaded and we're setting a static
lock (LockObject)
@@ -83,14 +83,14 @@ public static void Verify(string expectedString, int unit, TimeUnit timeUnit, Te
if (baseDate == null)
{
- VerifyWithCurrentDate(expectedString, deltaFromNow, culture);
- VerifyWithDateInjection(expectedString, deltaFromNow, culture);
+ VerifyWithCurrentDate(expectedString, deltaFromNow, culture, dateTimeExpressionProvider);
+ VerifyWithDateInjection(expectedString, deltaFromNow, culture, dateTimeExpressionProvider);
}
else
{
- VerifyWithDate(expectedString, deltaFromNow, culture, baseDate.Value, baseDateUtc.Value);
+ VerifyWithDate(expectedString, deltaFromNow, culture, baseDate.Value, baseDateUtc.Value, dateTimeExpressionProvider);
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer.Tests/DateTimeHumanizePrecisionTimeExpressionsTests.cs b/src/Humanizer.Tests/DateTimeHumanizePrecisionTimeExpressionsTests.cs
new file mode 100644
index 000000000..1a666a9bb
--- /dev/null
+++ b/src/Humanizer.Tests/DateTimeHumanizePrecisionTimeExpressionsTests.cs
@@ -0,0 +1,192 @@
+using Humanizer.Localisation;
+using Xunit;
+
+namespace Humanizer.Tests
+{
+ [UseCulture("en-US")]
+ public class DateTimeHumanizePrecisionTimeExpressionsTests
+ {
+
+ private const double DefaultPrecision = .75;
+ private static readonly TimeExpressionProviderToTest _timeExpressionProvider = new TimeExpressionProviderToTest();
+
+ [Theory]
+ [InlineData(1, "now")]
+ [InlineData(749, "now")]
+ [InlineData(750, "for one second")]
+ [InlineData(1000, "for one second")]
+ [InlineData(1749, "for one second")]
+ [InlineData(1750, "for 2 seconds")]
+ public void MillisecondsAgo(int milliseconds, string expected)
+ {
+ DateHumanize.Verify(expected, milliseconds, TimeUnit.Millisecond, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "now")]
+ [InlineData(749, "now")]
+ [InlineData(750, "in one second")]
+ [InlineData(1000, "in one second")]
+ [InlineData(1749, "in one second")]
+ [InlineData(1750, "in 2 seconds")]
+ public void MillisecondsFromNow(int milliseconds, string expected)
+ {
+ DateHumanize.Verify(expected, milliseconds, TimeUnit.Millisecond, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one second")]
+ [InlineData(10, "for 10 seconds")]
+ [InlineData(44, "for 44 seconds")]
+ [InlineData(45, "for a minute")]
+ [InlineData(60, "for a minute")]
+ [InlineData(104, "for a minute")]
+ [InlineData(105, "for 2 minutes")]
+ [InlineData(120, "for 2 minutes")]
+ public void SecondsAgo(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one second")]
+ [InlineData(10, "in 10 seconds")]
+ [InlineData(44, "in 44 seconds")]
+ [InlineData(45, "in a minute")]
+ [InlineData(60, "in a minute")]
+ [InlineData(104, "in a minute")]
+ [InlineData(105, "in 2 minutes")]
+ [InlineData(120, "in 2 minutes")]
+ public void SecondsFromNow(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for a minute")]
+ [InlineData(10, "for 10 minutes")]
+ [InlineData(44, "for 44 minutes")]
+ [InlineData(45, "for an hour")]
+ [InlineData(60, "for an hour")]
+ [InlineData(104, "for an hour")]
+ [InlineData(105, "for 2 hours")]
+ [InlineData(120, "for 2 hours")]
+ public void MinutesAgo(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in a minute")]
+ [InlineData(10, "in 10 minutes")]
+ [InlineData(44, "in 44 minutes")]
+ [InlineData(45, "in an hour")]
+ [InlineData(60, "in an hour")]
+ [InlineData(104, "in an hour")]
+ [InlineData(105, "in 2 hours")]
+ [InlineData(120, "in 2 hours")]
+ public void MinutesFromNow(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for an hour")]
+ [InlineData(10, "for 10 hours")]
+ [InlineData(17, "for 17 hours")]
+ [InlineData(18, "for one day")]
+ [InlineData(24, "for one day")]
+ [InlineData(41, "for one day")]
+ [InlineData(42, "for 2 days")]
+ [InlineData(48, "for 2 days")]
+ [InlineData(60, "for 2 days")]
+ public void HoursAgo(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in an hour")]
+ [InlineData(10, "in 10 hours")]
+ [InlineData(18, "tomorrow")]
+ [InlineData(24, "tomorrow")]
+ [InlineData(41, "tomorrow")]
+ [InlineData(42, "in 2 days")]
+ [InlineData(48, "in 2 days")]
+ [InlineData(60, "in 2 days")]
+ public void HoursFromNow(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one day")]
+ [InlineData(10, "for 10 days")]
+ [InlineData(20, "for 20 days")]
+ [InlineData(22, "for 22 days")]
+ [InlineData(23, "for one month")]
+ [InlineData(31, "for one month")]
+ [InlineData(43, "for one month")]
+ [InlineData(53, "for 2 months")]
+ public void DaysAgo(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "tomorrow")]
+ [InlineData(10, "in 10 days")]
+ [InlineData(20, "in 20 days")]
+ [InlineData(22, "in 22 days")]
+ [InlineData(23, "in one month")]
+ [InlineData(31, "in one month")]
+ [InlineData(43, "in one month")]
+ [InlineData(53, "in 2 months")]
+ public void DaysFromNow(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one month")]
+ [InlineData(8, "for 8 months")]
+ [InlineData(9, "for one year")]
+ [InlineData(12, "for one year")]
+ [InlineData(19, "for one year")]
+ [InlineData(21, "for 2 years")]
+ [InlineData(24, "for 2 years")]
+ public void MonthsAgo(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one month")]
+ [InlineData(8, "in 8 months")]
+ [InlineData(9, "in one year")]
+ [InlineData(12, "in one year")]
+ [InlineData(19, "in one year")]
+ [InlineData(21, "in 2 years")]
+ [InlineData(24, "in 2 years")]
+ public void MonthsFromNow(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one year")]
+ [InlineData(2, "for 2 years")]
+ public void YearsAgo(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one year")]
+ [InlineData(2, "in 2 years")]
+ public void YearsFromNow(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future, DefaultPrecision, dateTimeExpressionProvider: _timeExpressionProvider);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests/DateTimeHumanizeSupportTimeExpressionsTests.cs b/src/Humanizer.Tests/DateTimeHumanizeSupportTimeExpressionsTests.cs
new file mode 100644
index 000000000..d74f3bcde
--- /dev/null
+++ b/src/Humanizer.Tests/DateTimeHumanizeSupportTimeExpressionsTests.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Globalization;
+using Humanizer.Localisation;
+using Xunit;
+
+namespace Humanizer.Tests
+{
+ [UseCulture("en-US")]
+ public class DateTimeHumanizeSupportTimeExpressionsTests
+ {
+
+ private static readonly TimeExpressionProviderToTest TimeExpressionProvider = new TimeExpressionProviderToTest();
+
+ [Theory]
+ [InlineData(1, "for one second")]
+ [InlineData(10, "for 10 seconds")]
+ [InlineData(59, "for 59 seconds")]
+ [InlineData(60, "for a minute")]
+ public void SecondsFor(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one second")]
+ [InlineData(10, "in 10 seconds")]
+ [InlineData(59, "in 59 seconds")]
+ [InlineData(60, "in a minute")]
+ public void SecondsIn(int seconds, string expected)
+ {
+ DateHumanize.Verify(expected, seconds, TimeUnit.Second, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for a minute")]
+ [InlineData(10, "for 10 minutes")]
+ [InlineData(44, "for 44 minutes")]
+ [InlineData(45, "for 45 minutes")]
+ [InlineData(59, "for 59 minutes")]
+ [InlineData(60, "for an hour")]
+ [InlineData(119, "for an hour")]
+ [InlineData(120, "for 2 hours")]
+ public void MinutesFor(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in a minute")]
+ [InlineData(10, "in 10 minutes")]
+ [InlineData(44, "in 44 minutes")]
+ [InlineData(45, "in 45 minutes")]
+ [InlineData(59, "in 59 minutes")]
+ [InlineData(60, "in an hour")]
+ [InlineData(119, "in an hour")]
+ [InlineData(120, "in 2 hours")]
+ public void MinutesIn(int minutes, string expected)
+ {
+ DateHumanize.Verify(expected, minutes, TimeUnit.Minute, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for an hour")]
+ [InlineData(10, "for 10 hours")]
+ [InlineData(23, "for 23 hours")]
+ [InlineData(24, "for one day")]
+ public void HoursFor(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in an hour")]
+ [InlineData(10, "in 10 hours")]
+ [InlineData(23, "in 23 hours")]
+ [InlineData(24, "tomorrow")]
+ public void HoursIn(int hours, string expected)
+ {
+ DateHumanize.Verify(expected, hours, TimeUnit.Hour, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one day")]
+ [InlineData(10, "for 10 days")]
+ [InlineData(27, "for 27 days")]
+ [InlineData(32, "for one month")]
+ public void DaysFor(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "tomorrow")]
+ [InlineData(10, "in 10 days")]
+ [InlineData(27, "in 27 days")]
+ [InlineData(32, "in one month")]
+ public void DaysIn(int days, string expected)
+ {
+ DateHumanize.Verify(expected, days, TimeUnit.Day, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one month")]
+ [InlineData(10, "for 10 months")]
+ [InlineData(11, "for 11 months")]
+ [InlineData(12, "for one year")]
+ public void MonthsFor(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one month")]
+ [InlineData(10, "in 10 months")]
+ [InlineData(11, "in 11 months")]
+ [InlineData(12, "in one year")]
+ public void MonthsIn(int months, string expected)
+ {
+ DateHumanize.Verify(expected, months, TimeUnit.Month, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "for one year")]
+ [InlineData(2, "for 2 years")]
+ public void YearsFor(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Past, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+
+ [Theory]
+ [InlineData(1, "in one year")]
+ [InlineData(2, "in 2 years")]
+ public void YearsIn(int years, string expected)
+ {
+ DateHumanize.Verify(expected, years, TimeUnit.Year, Tense.Future, dateTimeExpressionProvider: TimeExpressionProvider);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests/TimeExpressionProviderToTest.cs b/src/Humanizer.Tests/TimeExpressionProviderToTest.cs
new file mode 100644
index 000000000..23d91b499
--- /dev/null
+++ b/src/Humanizer.Tests/TimeExpressionProviderToTest.cs
@@ -0,0 +1,17 @@
+using Humanizer.Localisation;
+
+namespace Humanizer.Tests
+{
+ public class TimeExpressionProviderToTest : DateTimeExpressionProvider
+ {
+ public override TimeExpressionPast GetPastTimeExpression()
+ {
+ return TimeExpressionPast.For;
+ }
+
+ public override TimeExpressionFuture GetFutureTimeExpression()
+ {
+ return TimeExpressionFuture.In;
+ }
+ }
+}
diff --git a/src/Humanizer/DateHumanizeExtensions.cs b/src/Humanizer/DateHumanizeExtensions.cs
index 7047b2f69..62f8eeec3 100644
--- a/src/Humanizer/DateHumanizeExtensions.cs
+++ b/src/Humanizer/DateHumanizeExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using Humanizer.Configuration;
+using Humanizer.Localisation;
namespace Humanizer
{
@@ -17,7 +18,7 @@ public static class DateHumanizeExtensions
/// 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 DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null)
+ public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
var comparisonBase = dateToCompareAgainst ?? DateTime.UtcNow;
@@ -26,7 +27,7 @@ public static string Humanize(this DateTime input, bool utcDate = true, DateTime
comparisonBase = comparisonBase.ToLocalTime();
}
- return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture);
+ return Configurator.DateTimeHumanizeStrategy.Humanize(input, comparisonBase, culture, dateTimeExpressionProvider);
}
///
@@ -82,4 +83,4 @@ public static string Humanize(this DateTimeOffset? input, DateTimeOffset? dateTo
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs b/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs
index 1b25eea6e..d2076f1a8 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/DateTimeHumanizeAlgorithms.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Globalization;
using Humanizer.Configuration;
using Humanizer.Localisation;
@@ -13,7 +13,7 @@ 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)
+ public static string PrecisionHumanize(DateTime input, DateTime comparisonBase, double precision, CultureInfo culture, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks));
var tense = input > comparisonBase ? Tense.Future : Tense.Past;
@@ -72,42 +72,42 @@ public static string PrecisionHumanize(DateTime input, DateTime comparisonBase,
var formatter = Configurator.GetFormatter(culture);
if (years > 0)
{
- return formatter.DateHumanize(TimeUnit.Year, tense, years);
+ return formatter.DateHumanize(TimeUnit.Year, tense, years, dateTimeExpressionProvider);
}
if (months > 0)
{
- return formatter.DateHumanize(TimeUnit.Month, tense, months);
+ return formatter.DateHumanize(TimeUnit.Month, tense, months, dateTimeExpressionProvider);
}
if (days > 0)
{
- return formatter.DateHumanize(TimeUnit.Day, tense, days);
+ return formatter.DateHumanize(TimeUnit.Day, tense, days, dateTimeExpressionProvider);
}
if (hours > 0)
{
- return formatter.DateHumanize(TimeUnit.Hour, tense, hours);
+ return formatter.DateHumanize(TimeUnit.Hour, tense, hours, dateTimeExpressionProvider);
}
if (minutes > 0)
{
- return formatter.DateHumanize(TimeUnit.Minute, tense, minutes);
+ return formatter.DateHumanize(TimeUnit.Minute, tense, minutes, dateTimeExpressionProvider);
}
if (seconds > 0)
{
- return formatter.DateHumanize(TimeUnit.Second, tense, seconds);
+ return formatter.DateHumanize(TimeUnit.Second, tense, seconds, dateTimeExpressionProvider);
}
- return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0);
+ return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0, dateTimeExpressionProvider);
}
// 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)
+ public static string DefaultHumanize(DateTime input, DateTime comparisonBase, CultureInfo culture, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
var tense = input > comparisonBase ? Tense.Future : Tense.Past;
var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks));
@@ -116,59 +116,59 @@ public static string DefaultHumanize(DateTime input, DateTime comparisonBase, Cu
if (ts.TotalMilliseconds < 500)
{
- return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0);
+ return formatter.DateHumanize(TimeUnit.Millisecond, tense, 0, dateTimeExpressionProvider);
}
if (ts.TotalSeconds < 60)
{
- return formatter.DateHumanize(TimeUnit.Second, tense, ts.Seconds);
+ return formatter.DateHumanize(TimeUnit.Second, tense, ts.Seconds, dateTimeExpressionProvider);
}
if (ts.TotalSeconds < 120)
{
- return formatter.DateHumanize(TimeUnit.Minute, tense, 1);
+ return formatter.DateHumanize(TimeUnit.Minute, tense, 1, dateTimeExpressionProvider);
}
if (ts.TotalMinutes < 60)
{
- return formatter.DateHumanize(TimeUnit.Minute, tense, ts.Minutes);
+ return formatter.DateHumanize(TimeUnit.Minute, tense, ts.Minutes, dateTimeExpressionProvider);
}
if (ts.TotalMinutes < 90)
{
- return formatter.DateHumanize(TimeUnit.Hour, tense, 1);
+ return formatter.DateHumanize(TimeUnit.Hour, tense, 1, dateTimeExpressionProvider);
}
if (ts.TotalHours < 24)
{
- return formatter.DateHumanize(TimeUnit.Hour, tense, ts.Hours);
+ return formatter.DateHumanize(TimeUnit.Hour, tense, ts.Hours, dateTimeExpressionProvider);
}
if (ts.TotalHours < 48)
{
var days = Math.Abs((input.Date - comparisonBase.Date).Days);
- return formatter.DateHumanize(TimeUnit.Day, tense, days);
+ return formatter.DateHumanize(TimeUnit.Day, tense, days, dateTimeExpressionProvider);
}
if (ts.TotalDays < 28)
{
- return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days);
+ return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days, dateTimeExpressionProvider);
}
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.Month, tense, 1, dateTimeExpressionProvider);
}
- return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days);
+ return formatter.DateHumanize(TimeUnit.Day, tense, ts.Days, dateTimeExpressionProvider);
}
if (ts.TotalDays < 345)
{
var months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5));
- return formatter.DateHumanize(TimeUnit.Month, tense, months);
+ return formatter.DateHumanize(TimeUnit.Month, tense, months, dateTimeExpressionProvider);
}
var years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365));
@@ -177,7 +177,7 @@ public static string DefaultHumanize(DateTime input, DateTime comparisonBase, Cu
years = 1;
}
- return formatter.DateHumanize(TimeUnit.Year, tense, years);
+ return formatter.DateHumanize(TimeUnit.Year, tense, years, dateTimeExpressionProvider);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
index e8c97fdb0..7ee4fd3eb 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/DefaultDateTimeHumanizeStrategy.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using System.Globalization;
+using Humanizer.Localisation;
namespace Humanizer.DateTimeHumanizeStrategy
{
@@ -11,9 +12,9 @@ public class DefaultDateTimeHumanizeStrategy : IDateTimeHumanizeStrategy
///
/// Calculates the distance of time in words between two provided dates
///
- public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture)
+ public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture, DateTimeExpressionProvider dateTimeTextProvider)
{
- return DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture);
+ return DateTimeHumanizeAlgorithms.DefaultHumanize(input, comparisonBase, culture, dateTimeTextProvider);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
index 7d663a794..5974d8dba 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/IDateTimeHumanizeStrategy.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using Humanizer.Localisation;
namespace Humanizer.DateTimeHumanizeStrategy
{
@@ -11,6 +12,6 @@ public interface IDateTimeHumanizeStrategy
///
/// Calculates the distance of time in words between two provided dates used for DateTime.Humanize
///
- string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture);
+ string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture, DateTimeExpressionProvider dateTimeTextProvider);
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs
index 37bef4b9e..bd5283c79 100644
--- a/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs
+++ b/src/Humanizer/DateTimeHumanizeStrategy/PrecisionDateTimeHumanizeStrategy.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using System.Globalization;
+using Humanizer.Localisation;
namespace Humanizer.DateTimeHumanizeStrategy
{
@@ -22,9 +23,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)
+ public string Humanize(DateTime input, DateTime comparisonBase, CultureInfo culture, DateTimeExpressionProvider dateTimeExpressionProvider)
{
- return DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, _precision, culture);
+ return DateTimeHumanizeAlgorithms.PrecisionHumanize(input, comparisonBase, _precision, culture, dateTimeExpressionProvider);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Humanizer/Localisation/DateTimeExpressionProvider.cs b/src/Humanizer/Localisation/DateTimeExpressionProvider.cs
new file mode 100644
index 000000000..705202d05
--- /dev/null
+++ b/src/Humanizer/Localisation/DateTimeExpressionProvider.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Humanizer.Localisation
+{
+ public class DateTimeExpressionProvider
+ {
+ private static readonly DateTimeExpressionProvider _dateTimeExpressionProvider = new DateTimeExpressionProvider();
+
+ public static DateTimeExpressionProvider Default
+ {
+ get { return _dateTimeExpressionProvider; }
+ }
+
+ public virtual TimeExpressionFuture GetFutureTimeExpression()
+ {
+ return TimeExpressionFuture.FromNow;
+ }
+
+ public virtual TimeExpressionPast GetPastTimeExpression()
+ {
+ return TimeExpressionPast.Ago;
+ }
+ }
+}
diff --git a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
index 341437042..660c8391a 100644
--- a/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
+++ b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs
@@ -44,9 +44,9 @@ public virtual string DateHumanize_Never()
///
///
///
- public virtual string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit)
+ public virtual string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit, DateTimeExpressionProvider dateTimeTextProvider = null)
{
- return GetResourceForDate(timeUnit, timeUnitTense, unit);
+ return GetResourceForDate(timeUnit, timeUnitTense, unit, dateTimeTextProvider);
}
///
@@ -71,9 +71,9 @@ public virtual string TimeSpanHumanize(TimeUnit timeUnit, int unit, bool toWords
return GetResourceForTimeSpan(timeUnit, unit, toWords);
}
- private string GetResourceForDate(TimeUnit unit, Tense timeUnitTense, int count)
+ private string GetResourceForDate(TimeUnit unit, Tense timeUnitTense, int count, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
- var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count);
+ var resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, timeUnitTense: timeUnitTense, count: count, dateTimeExpressionProvider: dateTimeExpressionProvider);
return count == 1 ? Format(resourceKey) : Format(resourceKey, count);
}
diff --git a/src/Humanizer/Localisation/Formatters/IFormatter.cs b/src/Humanizer/Localisation/Formatters/IFormatter.cs
index 398fbd4fd..e3f641323 100644
--- a/src/Humanizer/Localisation/Formatters/IFormatter.cs
+++ b/src/Humanizer/Localisation/Formatters/IFormatter.cs
@@ -26,7 +26,7 @@ public interface IFormatter
///
///
///
- string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit);
+ string DateHumanize(TimeUnit timeUnit, Tense timeUnitTense, int unit, DateTimeExpressionProvider dateTimeExpressionProvider = null);
///
/// 0 seconds
diff --git a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
index 89a3a50ff..a03c1c251 100644
--- a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
+++ b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs
@@ -23,9 +23,6 @@ public static class DateHumanize
///
private const string DateTimeFormat = "DateHumanize_{0}{1}{2}";
- private const string Ago = "Ago";
- private const string FromNow = "FromNow";
-
///
/// Generates Resource Keys accordning to convention.
///
@@ -33,7 +30,7 @@ public static class DateHumanize
/// Is time unit in future or past
/// Number of units, default is One.
/// Resource key, like DateHumanize_SingleMinuteAgo
- public static string GetResourceKey(TimeUnit timeUnit, Tense timeUnitTense, int count = 1)
+ public static string GetResourceKey(TimeUnit timeUnit, Tense timeUnitTense, int count = 1, DateTimeExpressionProvider dateTimeExpressionProvider = null)
{
ValidateRange(count);
@@ -43,7 +40,10 @@ public static string GetResourceKey(TimeUnit timeUnit, Tense timeUnitTense, int
}
var singularity = count == 1 ? Single : Multiple;
- var tense = timeUnitTense == Tense.Future ? FromNow : Ago;
+
+ dateTimeExpressionProvider ??= DateTimeExpressionProvider.Default;
+
+ var tense = timeUnitTense == Tense.Future ? dateTimeExpressionProvider.GetFutureTimeExpression().ToString() : dateTimeExpressionProvider.GetPastTimeExpression().ToString();
var unit = timeUnit.ToString().ToQuantity(count, ShowQuantityAs.None);
return DateTimeFormat.FormatWith(singularity, unit, tense);
}
diff --git a/src/Humanizer/Localisation/TimeExpressionFuture.cs b/src/Humanizer/Localisation/TimeExpressionFuture.cs
new file mode 100644
index 000000000..4495520d9
--- /dev/null
+++ b/src/Humanizer/Localisation/TimeExpressionFuture.cs
@@ -0,0 +1,12 @@
+namespace Humanizer.Localisation
+{
+ ///
+ /// Enumerates the possible time expressions
+ ///
+ public enum TimeExpressionFuture
+ {
+ FromNow,
+ For,
+ In
+ }
+}
diff --git a/src/Humanizer/Localisation/TimeExpressionPast.cs b/src/Humanizer/Localisation/TimeExpressionPast.cs
new file mode 100644
index 000000000..eab23f47a
--- /dev/null
+++ b/src/Humanizer/Localisation/TimeExpressionPast.cs
@@ -0,0 +1,11 @@
+namespace Humanizer.Localisation
+{
+ ///
+ /// Enumerates the possible time expressions
+ ///
+ public enum TimeExpressionPast
+ {
+ Ago,
+ For
+ }
+}
diff --git a/src/Humanizer/Properties/Resources.resx b/src/Humanizer/Properties/Resources.resx
index 678f0d5cf..d11b8a0a8 100644
--- a/src/Humanizer/Properties/Resources.resx
+++ b/src/Humanizer/Properties/Resources.resx
@@ -675,4 +675,283 @@
NNW
+
+ for {0} days
+
+
+ for {0} days
+
+
+ for {0} days
+
+
+ for {0} days
+
+
+ for {0} day
+
+
+ for {0} days
+
+
+ for {0} hours
+
+
+ for {0} hours
+
+
+ for {0} hours
+
+
+ for {0} hours
+
+
+ for {0} hours
+
+
+ for {0} hour
+
+
+ for {0} hours
+
+
+ for {0} minutes
+
+
+ for {0} minutes
+
+
+ for {0} minutes
+
+
+ for {0} minutes
+
+
+ for {0} minutes
+
+
+ for {0} minute
+
+
+ for {0} minutes
+
+
+ for {0} months
+
+
+ for {0} months
+
+
+ for {0} months
+
+
+ for {0} months
+
+
+ for {0} month
+
+
+ for {0} months
+
+
+ for {0} seconds
+
+
+ for {0} seconds
+
+
+ for {0} seconds
+
+
+ for {0} seconds
+
+
+ for {0} seconds
+
+
+ for {0} second
+
+
+ for {0} seconds
+
+
+ for {0} years
+
+
+ for {0} years
+
+
+ for {0} years
+
+
+ for {0} years
+
+
+ for {0} years
+
+
+ for {0} year
+
+
+ for {0} years
+
+
+
+
+
+ in {0} days
+
+
+ in {0} days
+
+
+ in {0} days
+
+
+ in {0} day
+
+
+ in {0} days
+
+
+ in {0} days
+
+
+ in {0} hours
+
+
+ in {0} hours
+
+
+ in {0} hours
+
+
+ in {0} hours
+
+
+ in {0} hours
+
+
+ in {0} hour
+
+
+ in {0} hours
+
+
+ in {0} minutes
+
+
+ in {0} minutes
+
+
+ in {0} minutes
+
+
+ in {0} minutes
+
+
+ in {0} minutes
+
+
+ in {0} minute
+
+
+ in {0} minutes
+
+
+ in {0} months
+
+
+ in {0} months
+
+
+ in {0} months
+
+
+ in {0} months
+
+
+ in {0} month
+
+
+ in {0} months
+
+
+ in {0} seconds
+
+
+ in {0} seconds
+
+
+ in {0} seconds
+
+
+ in {0} seconds
+
+
+ in {0} seconds
+
+
+ in {0} second
+
+
+ in {0} seconds
+
+
+ in {0} years
+
+
+ in {0} years
+
+
+ in {0} years
+
+
+ in {0} years
+
+
+ in {0} years
+
+
+ in {0} year
+
+
+ in {0} years
+
+
+ for one day
+
+
+ tomorrow
+
+
+ for an hour
+
+
+ in an hour
+
+
+ for a minute
+
+
+ in a minute
+
+
+ for one month
+
+
+ in one month
+
+
+ for one second
+
+
+ in one second
+
+
+ for one year
+
+
+ in one year
+
\ No newline at end of file