diff --git a/src/Jackett.Common/Indexers/Shazbat.cs b/src/Jackett.Common/Indexers/Shazbat.cs index 7b31681aa..eb1b3da07 100644 --- a/src/Jackett.Common/Indexers/Shazbat.cs +++ b/src/Jackett.Common/Indexers/Shazbat.cs @@ -149,8 +149,7 @@ namespace Jackett.Common.Indexers release.Comments = new Uri(SiteLink + qLinkComm.GetAttribute("href")); var dateString = row.QuerySelector(".datetime")?.GetAttribute("data-timestamp"); if (dateString != null) - release.PublishDate = DateTimeUtil - .UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)).ToLocalTime(); + release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)); var infoString = row.QuerySelector("td:nth-of-type(4)").TextContent; release.Size = ParseUtil.CoerceLong( Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(", "").Replace(")", "")); diff --git a/src/Jackett.Common/Indexers/TorrentNetwork.cs b/src/Jackett.Common/Indexers/TorrentNetwork.cs index bdd0fede9..68896e783 100644 --- a/src/Jackett.Common/Indexers/TorrentNetwork.cs +++ b/src/Jackett.Common/Indexers/TorrentNetwork.cs @@ -233,7 +233,7 @@ namespace Jackett.Common.Indexers //var row13 = (string)torrent[13]; //var row14 = (long)torrent[14]; var link = new Uri(SiteLink + "sdownload/" + torrentID + "/" + passkey); - var publishDate = DateTimeUtil.UnixTimestampToDateTime((double)torrent[3]).ToLocalTime(); + var publishDate = DateTimeUtil.UnixTimestampToDateTime((double)torrent[3]); var downloadVolumeFactor = (long)torrent[10] switch { // Only Up diff --git a/src/Jackett.Common/Utils/DateTimeUtil.cs b/src/Jackett.Common/Utils/DateTimeUtil.cs index d00871553..dccff18f6 100644 --- a/src/Jackett.Common/Utils/DateTimeUtil.cs +++ b/src/Jackett.Common/Utils/DateTimeUtil.cs @@ -4,6 +4,9 @@ using System.Text.RegularExpressions; namespace Jackett.Common.Utils { + /// + /// All functions MUST return local time (local time zone) + /// public static class DateTimeUtil { public const string Rfc1123ZPattern = "ddd, dd MMM yyyy HH':'mm':'ss z"; @@ -27,7 +30,7 @@ namespace Jackett.Common.Utils { var unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); var unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond); - return new DateTime(unixStart.Ticks + unixTimeStampInTicks); + return new DateTime(unixStart.Ticks + unixTimeStampInTicks).ToLocalTime(); } public static double DateTimeToUnixTimestamp(DateTime dt) @@ -50,14 +53,14 @@ namespace Jackett.Common.Utils str = str.Replace("and", ""); var timeAgo = TimeSpan.Zero; - var timeagoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?"); - var timeagoMatches = timeagoRegex.Match(str); + var timeAgoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?"); + var timeAgoMatches = timeAgoRegex.Match(str); - while (timeagoMatches.Success) + while (timeAgoMatches.Success) { - var val = ParseUtil.CoerceFloat(timeagoMatches.Groups[1].Value); - var unit = timeagoMatches.Groups[2].Value; - timeagoMatches = timeagoMatches.NextMatch(); + var val = ParseUtil.CoerceFloat(timeAgoMatches.Groups[1].Value); + var unit = timeAgoMatches.Groups[2].Value; + timeAgoMatches = timeAgoMatches.NextMatch(); if (unit.Contains("sec") || unit == "s") timeAgo += TimeSpan.FromSeconds(val); @@ -101,14 +104,14 @@ namespace Jackett.Common.Utils { str = ParseUtil.NormalizeSpace(str); if (str.ToLower().Contains("now")) - return DateTime.UtcNow; + return DateTime.Now; // ... ago var match = _TimeAgoRegexp.Match(str); if (match.Success) { - var timeago = str; - return FromTimeAgo(timeago); + var timeAgo = str; + return FromTimeAgo(timeAgo); } // Today ... diff --git a/src/Jackett.Test/TestHelpers/WebUtilityHelpersTests.cs b/src/Jackett.Test/Common/Helpers/WebUtilityHelpersTests.cs similarity index 88% rename from src/Jackett.Test/TestHelpers/WebUtilityHelpersTests.cs rename to src/Jackett.Test/Common/Helpers/WebUtilityHelpersTests.cs index d4939746b..69305b995 100644 --- a/src/Jackett.Test/TestHelpers/WebUtilityHelpersTests.cs +++ b/src/Jackett.Test/Common/Helpers/WebUtilityHelpersTests.cs @@ -4,7 +4,7 @@ using Jackett.Common.Helpers; using NUnit.Framework; using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; -namespace Jackett.Test.TestHelpers +namespace Jackett.Test.Common.Helpers { [TestFixture] public class WebUtilityHelpersTests @@ -53,6 +53,13 @@ namespace Jackett.Test.TestHelpers } } + [Test] + public void WebUtilityHelpers_UrlEncode_BadEncodes() + { + var encoded = WebUtilityHelpers.UrlEncode(null, Encoding.UTF8); + Assert.AreEqual("", encoded); + } + [Test] public void WebUtilityHelpers_UrlDecode_CorrectlyDecodes() { @@ -68,5 +75,12 @@ namespace Jackett.Test.TestHelpers } } } + + [Test] + public void WebUtilityHelpers_UrlDecode_BadDecodes() + { + var decoded = WebUtilityHelpers.UrlDecode(null, Encoding.UTF8); + Assert.AreEqual("", decoded); + } } } diff --git a/src/Jackett.Test/Common/Utils/DateTimeUtilTests.cs b/src/Jackett.Test/Common/Utils/DateTimeUtilTests.cs index 00e9038d1..c3fc6075a 100644 --- a/src/Jackett.Test/Common/Utils/DateTimeUtilTests.cs +++ b/src/Jackett.Test/Common/Utils/DateTimeUtilTests.cs @@ -8,9 +8,86 @@ namespace Jackett.Test.Common.Utils [TestFixture] public class DateTimeUtilTests { + [Test] + public void UnixTimestampToDateTimeTest() + { + const long timestampLong = 1604113707; + const double timestampDouble = 1604113707.0; + var expected = new DateTime(2020, 10, 31, 3, 8, 27, DateTimeKind.Utc).ToLocalTime(); + + Assert.AreEqual(expected, DateTimeUtil.UnixTimestampToDateTime(timestampLong)); + Assert.AreEqual(expected, DateTimeUtil.UnixTimestampToDateTime(timestampDouble)); + } + + [Test] + public void DateTimeToUnixTimestampTest() + { + var dateTime = new DateTime(2020, 10, 31, 3, 8, 27, DateTimeKind.Utc); + const double expected = 1604113707.0; + + Assert.AreEqual(expected, DateTimeUtil.DateTimeToUnixTimestamp(dateTime)); + } + + [Test] + public void FromTimeAgoTest() + { + var now = DateTime.Now; + + AssertSimilarDates(now, DateTimeUtil.FromTimeAgo("NOW")); // case insensitive + AssertSimilarDates(now, DateTimeUtil.FromTimeAgo("now")); + AssertSimilarDates(now.AddSeconds(-1), DateTimeUtil.FromTimeAgo("1 sec")); + AssertSimilarDates(now.AddMinutes(-12), DateTimeUtil.FromTimeAgo("12 min ago")); + AssertSimilarDates(now.AddHours(-20), DateTimeUtil.FromTimeAgo("20 h")); + AssertSimilarDates(now.AddDays(-3), DateTimeUtil.FromTimeAgo("3 days")); + AssertSimilarDates(now.AddDays(-7), DateTimeUtil.FromTimeAgo("1 week")); + AssertSimilarDates(now.AddDays(-60), DateTimeUtil.FromTimeAgo("2 month ago")); + AssertSimilarDates(now.AddDays(-365), DateTimeUtil.FromTimeAgo("1 year")); + AssertSimilarDates(now.AddHours(-20).AddMinutes(-15), DateTimeUtil.FromTimeAgo("20 hours and 15 minutes ago")); + AssertSimilarDates(now, DateTimeUtil.FromTimeAgo("")); + + // bad cases + try + { + DateTimeUtil.FromTimeAgo("1 bad"); // unknown unit + Assert.Fail(); + } + catch + { + // ignored + } + } + + [Test] + public void FromFuzzyTimeTest() + { + // there are few tests because we are using a well known library + var now = DateTime.Now; + + Assert.AreEqual(new DateTimeOffset(2010, 6, 21, 4, 20, 19, new TimeSpan(-4, -30, 0)).DateTime, + DateTimeUtil.FromFuzzyTime("21 Jun 2010 04:20:19 -0430 blah")); + Assert.AreEqual(new DateTime(2005, 6, 10, 10, 30, 0), + DateTimeUtil.FromFuzzyTime("June 10, 2005 10:30AM", "UK")); + Assert.AreEqual(new DateTime(now.Year, now.Month, now.Day, 19, 54, 0), + DateTimeUtil.FromFuzzyTime("today 19:54")); + Assert.True((now - DateTimeUtil.FromFuzzyTime("Yesterday at 10:20 pm")).TotalSeconds <= 3600 * 24); // 1 day + Assert.True((now - DateTimeUtil.FromFuzzyTime("Sunday at 14:30")).TotalSeconds <= 3600 * 24 * 7); // 1 week + + // bad cases + try + { + DateTimeUtil.FromFuzzyTime("1 bad"); + Assert.Fail(); + } + catch + { + // ignored + } + } + [Test] public void FromUnknownTest() { + var now = DateTime.Now; var today = DateTime.UtcNow.Date; var yesterday = today.AddDays(-1); var tomorrow = today.AddDays(1); @@ -22,11 +99,75 @@ namespace Jackett.Test.Common.Utils {"Today at 20:19:54", today.AddHours(20).AddMinutes(19).AddSeconds(54)}, {"Today 22:29", today.AddHours(22).AddMinutes(29)}, {"Yesterday\n 19:54:54", yesterday.AddHours(19).AddMinutes(54).AddSeconds(54)}, - {"Yesterday\n 11:55 PM", yesterday.AddHours(23).AddMinutes(55)} + {"yesterday\n 11:55 PM", yesterday.AddHours(23).AddMinutes(55)}, + {"Tomorrow\n 19:54:54", tomorrow.AddHours(19).AddMinutes(54).AddSeconds(54)}, + {"tomorrow 22:29", tomorrow.AddHours(22).AddMinutes(29)}, }; foreach (var testCase in testCases) Assert.AreEqual(testCase.Value, DateTimeUtil.FromUnknown(testCase.Key)); + + AssertSimilarDates(now, DateTimeUtil.FromUnknown("now")); + AssertSimilarDates(now.AddHours(-3), DateTimeUtil.FromUnknown("3 hours ago")); + + Assert.True((now - DateTimeUtil.FromUnknown("monday at 10:20 am")).TotalSeconds <= 3600 * 24 * 7); // 7 days + Assert.True((now - DateTimeUtil.FromUnknown("Tuesday at 22:20")).TotalSeconds <= 3600 * 24 * 7); + Assert.True((now - DateTimeUtil.FromUnknown("wednesday at \n 22:20")).TotalSeconds <= 3600 * 24 * 7); + Assert.True((now - DateTimeUtil.FromUnknown("\n thursday \n at 22:20")).TotalSeconds <= 3600 * 24 * 7); + Assert.True((now - DateTimeUtil.FromUnknown("friday at 22:20")).TotalSeconds <= 3600 * 24 * 7); + Assert.True((now - DateTimeUtil.FromUnknown("Saturday at 00:20")).TotalSeconds <= 3600 * 24 * 7); + Assert.True((now - DateTimeUtil.FromUnknown("sunday at 22:00")).TotalSeconds <= 3600 * 24 * 7); + + Assert.AreEqual(new DateTime(2020, 10, 31, 3, 8, 27, DateTimeKind.Utc).ToLocalTime(), + DateTimeUtil.FromUnknown("1604113707")); + + Assert.AreEqual(new DateTime(now.Year, 2, 1), DateTimeUtil.FromUnknown("02-01")); + Assert.AreEqual(new DateTime(now.Year, 2, 1), DateTimeUtil.FromUnknown("2-1")); + Assert.AreEqual(new DateTime(now.Year, 1, 2, 10, 30, 0), DateTimeUtil.FromUnknown("2 Jan 10:30")); + + Assert.AreEqual(new DateTime(2005, 6, 10, 10, 30, 0), + DateTimeUtil.FromUnknown("June 10, 2005 10:30AM")); + + // bad cases + try + { + DateTimeUtil.FromUnknown("1 bad"); + Assert.Fail(); + } + catch + { + // ignored + } + } + + [Test] + public void ParseDateTimeGoLangTest() + { + var now = DateTime.Now; + + Assert.AreEqual(new DateTimeOffset(2010, 6, 21, 4, 20, 19, new TimeSpan(-4, 0, 0)).ToLocalTime().DateTime, + DateTimeUtil.ParseDateTimeGoLang("21-06-2010 04:20:19 -04:00", "02-01-2006 15:04:05 -07:00")); + Assert.AreEqual(new DateTimeOffset(2010, 6, 21, 0, 0, 0, new TimeSpan(-5, -30, 0)).ToLocalTime().DateTime, + DateTimeUtil.ParseDateTimeGoLang("2010-06-21 -05:30", "2006-01-02 -07:00")); + Assert.AreEqual(new DateTime(now.Year, 9, 14, 7, 0, 0), + DateTimeUtil.ParseDateTimeGoLang("7am Sep. 14", "3pm Jan. 2")); + + // bad cases + try + { + DateTimeUtil.ParseDateTimeGoLang("21-06-2010 04:20:19", "02-01-2006 15:04:05 -07:00"); + Assert.Fail(); + } + catch + { + // ignored + } + } + + private static void AssertSimilarDates(DateTime dt1, DateTime dt2, int delta = 5) + { + var diff = Math.Abs((dt1 - dt2).TotalSeconds); + Assert.True(diff < delta, $"Dates are not similar. Expected: {dt1} But was: {dt2}"); } } } diff --git a/src/Jackett.Test/Jackett.Test.csproj b/src/Jackett.Test/Jackett.Test.csproj index 2e2aa3b4e..ea8fa1bdb 100644 --- a/src/Jackett.Test/Jackett.Test.csproj +++ b/src/Jackett.Test/Jackett.Test.csproj @@ -36,7 +36,6 @@ -