diff --git a/src/Enums/RelativityDirection.cs b/src/Enums/RelativityDirection.cs new file mode 100644 index 0000000..fac877c --- /dev/null +++ b/src/Enums/RelativityDirection.cs @@ -0,0 +1,8 @@ +namespace moment.net.Enums +{ + internal enum RelativityDirection + { + From, + To + } +} \ No newline at end of file diff --git a/src/RelativeTime.cs b/src/RelativeTime.cs index 8ac3248..3e731a0 100644 --- a/src/RelativeTime.cs +++ b/src/RelativeTime.cs @@ -1,24 +1,28 @@ using System; +using moment.net.Enums; namespace moment.net { public static class RelativeTime { - private const int _daysInAWeek = 7; - private const double _daysInAYear = 365.2425; // see https://en.wikipedia.org/wiki/Gregorian_calendar - private const double _daysInAMonth = _daysInAYear / 12; + private const double DaysInAYear = 365.2425; // see https://en.wikipedia.org/wiki/Gregorian_calendar + private const double DaysInAMonth = DaysInAYear / 12; public static string FromNow(this DateTime This) { - if (This.Kind == DateTimeKind.Utc) - { - return TimeFromTimeSpan(DateTime.UtcNow - This); - } + return This.Kind == DateTimeKind.Utc + ? ParseFromPastTimeSpan(DateTime.UtcNow - This) + : ParseFromPastTimeSpan(DateTime.Now - This); + } - return TimeFromTimeSpan(DateTime.Now - This); + public static string ToNow(this DateTime This) + { + return This.Kind == DateTimeKind.Utc + ? ParseFromFutureTimeSpan(This - DateTime.UtcNow) + : ParseFromFutureTimeSpan(This - DateTime.Now); } - private static string TimeFromTimeSpan(TimeSpan timeSpan) + private static string ParseFromPastTimeSpan(TimeSpan timeSpan) { var totalTimeInSeconds = timeSpan.TotalSeconds; @@ -70,7 +74,7 @@ private static string TimeFromTimeSpan(TimeSpan timeSpan) if (totalTimeInDays > 45 && totalTimeInDays <= 319) { - return $"{Math.Ceiling(totalTimeInDays / _daysInAMonth)} months ago"; + return $"{Math.Ceiling(totalTimeInDays / DaysInAMonth)} months ago"; } if (totalTimeInDays > 319 && totalTimeInDays <= 547) @@ -80,10 +84,80 @@ private static string TimeFromTimeSpan(TimeSpan timeSpan) if (totalTimeInDays > 547) { - return $"{Math.Ceiling(totalTimeInDays / _daysInAYear)} years ago"; + return $"{Math.Ceiling(totalTimeInDays / DaysInAYear)} years ago"; + } + + throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan, + "The time span sent could not be parsed."); + } + + private static string ParseFromFutureTimeSpan(TimeSpan timeSpan) + { + var totalTimeInSeconds = timeSpan.TotalSeconds; + + if (totalTimeInSeconds <= 44.0) + { + return "in a few seconds"; + } + + if (totalTimeInSeconds > 44.0 && totalTimeInSeconds <= 89.0) + { + return "in a minute"; + } + + var totalTimeInMinutes = timeSpan.TotalMinutes; + + if (totalTimeInSeconds > 89 && totalTimeInMinutes <= 44) + { + return $"in {Math.Ceiling(totalTimeInMinutes)} minutes"; + } + + if (totalTimeInMinutes > 44 && totalTimeInMinutes <= 89) + { + return "in an hour"; + } + + var totalTimeInHours = timeSpan.TotalHours; + + if (totalTimeInMinutes > 89 && totalTimeInHours <= 21) + { + return $"in {Math.Ceiling(totalTimeInHours)} hours"; + } + + if (totalTimeInHours > 21 && totalTimeInHours <= 35) + { + return "in a day"; + } + + var totalTimeInDays = timeSpan.TotalDays; + + if (totalTimeInHours > 35 && totalTimeInDays <= 25) + { + return $"in {Math.Ceiling(totalTimeInDays)} days"; + } + + if (totalTimeInDays > 25 && totalTimeInDays <= 45) + { + return "in a month"; + } + + if (totalTimeInDays > 45 && totalTimeInDays <= 319) + { + return $"in {Math.Ceiling(totalTimeInDays / DaysInAMonth)} months"; + } + + if (totalTimeInDays > 319 && totalTimeInDays <= 547) + { + return "in a year"; + } + + if (totalTimeInDays > 547) + { + return $"in {Math.Ceiling(totalTimeInDays / DaysInAYear)} years"; } - - throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan, "The time span sent could not be parsed."); + + throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan, + "in The time span sent could not be parsed."); } } } \ No newline at end of file diff --git a/tests/RelativeTime.Tests.cs b/tests/RelativeTime.Tests.cs index 400bf9d..d365cec 100644 --- a/tests/RelativeTime.Tests.cs +++ b/tests/RelativeTime.Tests.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using NUnit.Framework; using Shouldly; namespace moment.net.Tests { + [ExcludeFromCodeCoverage] public class RelativeTimeTests { [Test] @@ -96,5 +98,96 @@ public void MultipleYearsTest() var dateTime = DateTime.UtcNow.AddDays(-3650); dateTime.FromNow().ShouldBe("10 years ago"); } + + [Test] + public void AFewSecondsInTheFutureTest() + { + var aFewSecondsAgo = DateTime.UtcNow.AddSeconds(20); + aFewSecondsAgo.ToNow().ShouldBe("in a few seconds"); + } + + [Test] + public void MoreSecondsInTheFutureTest() + { + var largeSecondsAgo = DateTime.UtcNow.AddSeconds(50); + largeSecondsAgo.ToNow().ShouldBe("in a minute"); + } + + [Test] + public void AFewMinutesInTheFutureTest() + { + var afewMinutesAgo = DateTime.Now.AddMinutes(1); + afewMinutesAgo.ToNow().ShouldBe("in a minute"); + } + + [Test] + public void MoreMinutesInTheFutureTest() + { + var minutesAgo = DateTime.Now.AddMinutes(15); + minutesAgo.ToNow().ShouldBe("in 15 minutes"); + } + + [Test] + public void ToHourTest() + { + var dateTime = DateTime.UtcNow.AddMinutes(65); + dateTime.ToNow().ShouldBe("in an hour"); + } + + [Test] + public void ToMultipleHoursTest() + { + var dateTime = DateTime.UtcNow.AddHours(20); + dateTime.ToNow().ShouldBe("in 20 hours"); + } + + [Test] + public void ToDayTest() + { + var dateTime = DateTime.UtcNow.AddHours(25); + dateTime.ToNow().ShouldBe("in a day"); + } + + [Test] + public void ToMultipleDaysTest() + { + var dateTime = DateTime.UtcNow.AddDays(4); + dateTime.ToNow().ShouldBe("in 4 days"); + } + + [Test] + public void ToMonthTest() + { + var dateTime = DateTime.UtcNow.AddDays(27); + dateTime.ToNow().ShouldBe("in a month"); + } + + [Test] + public void ToMultipleMonthsTest() + { + var dateTime = DateTime.UtcNow.AddDays(60); + dateTime.ToNow().ShouldBe("in 2 months"); + } + + [Test] + public void ToYearTest() + { + var dateTime = DateTime.UtcNow.AddDays(360); + dateTime.ToNow().ShouldBe("in a year"); + } + + [Test] + public void ToTwoYearsTest() + { + var dateTime = DateTime.UtcNow.AddDays(570); + dateTime.ToNow().ShouldBe("in 2 years"); + } + + [Test] + public void ToMultipleYearsTest() + { + var dateTime = DateTime.UtcNow.AddDays(3650); + dateTime.ToNow().ShouldBe("in 10 years"); + } } } \ No newline at end of file