[enhancement] Date parser handle dates without a year. resolves #11219 (#11656)

This commit is contained in:
Alessio Gogna
2021-05-03 21:26:43 +02:00
committed by GitHub
parent 4de2124b98
commit 7789a72ffb
2 changed files with 58 additions and 31 deletions

View File

@@ -42,11 +42,13 @@ namespace Jackett.Common.Utils
} }
// ex: "2 hours 1 day" // ex: "2 hours 1 day"
public static DateTime FromTimeAgo(string str) public static DateTime FromTimeAgo(string str, DateTime? relativeFrom = null)
{ {
str = str.ToLowerInvariant(); str = str.ToLowerInvariant();
var now = relativeFrom ?? DateTime.Now;
if (str.Contains("now")) if (str.Contains("now"))
return DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); return DateTime.SpecifyKind(now, DateTimeKind.Local);
str = str.Replace(",", ""); str = str.Replace(",", "");
str = str.Replace("ago", ""); str = str.Replace("ago", "");
@@ -80,7 +82,7 @@ namespace Jackett.Common.Utils
throw new Exception("TimeAgo parsing failed, unknown unit: " + unit); throw new Exception("TimeAgo parsing failed, unknown unit: " + unit);
} }
return DateTime.SpecifyKind(DateTime.Now - timeAgo, DateTimeKind.Local); return DateTime.SpecifyKind(now - timeAgo, DateTimeKind.Local);
} }
// Uses the DateTimeRoutines library to parse the date // Uses the DateTimeRoutines library to parse the date
@@ -97,14 +99,23 @@ namespace Jackett.Common.Utils
throw new Exception("FromFuzzyTime parsing failed"); throw new Exception("FromFuzzyTime parsing failed");
} }
private static DateTime FromFuzzyPastTime(string str, string format, DateTime now)
{
var result = FromFuzzyTime(str, format);
if (result > now)
result = result.AddYears(-1);
return result;
}
public static DateTime FromUnknown(string str, string format = null) public static DateTime FromUnknown(string str, string format = null, DateTime? relativeFrom = null)
{ {
try try
{ {
str = ParseUtil.NormalizeSpace(str); str = ParseUtil.NormalizeSpace(str);
var now = relativeFrom ?? DateTime.Now;
if (str.ToLower().Contains("now")) if (str.ToLower().Contains("now"))
return DateTime.Now; return now;
// ... ago // ... ago
var match = _TimeAgoRegexp.Match(str); var match = _TimeAgoRegexp.Match(str);
@@ -119,7 +130,7 @@ namespace Jackett.Common.Utils
if (match.Success) if (match.Success)
{ {
var time = str.Replace(match.Groups[0].Value, ""); var time = str.Replace(match.Groups[0].Value, "");
var dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); var dt = DateTime.SpecifyKind(now.Date, DateTimeKind.Unspecified);
dt += ParseTimeSpan(time); dt += ParseTimeSpan(time);
return dt; return dt;
} }
@@ -129,7 +140,7 @@ namespace Jackett.Common.Utils
if (match.Success) if (match.Success)
{ {
var time = str.Replace(match.Groups[0].Value, ""); var time = str.Replace(match.Groups[0].Value, "");
var dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); var dt = DateTime.SpecifyKind(now.Date, DateTimeKind.Unspecified);
dt += ParseTimeSpan(time); dt += ParseTimeSpan(time);
dt -= TimeSpan.FromDays(1); dt -= TimeSpan.FromDays(1);
return dt; return dt;
@@ -140,7 +151,7 @@ namespace Jackett.Common.Utils
if (match.Success) if (match.Success)
{ {
var time = str.Replace(match.Groups[0].Value, ""); var time = str.Replace(match.Groups[0].Value, "");
var dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); var dt = DateTime.SpecifyKind(now.Date, DateTimeKind.Unspecified);
dt += ParseTimeSpan(time); dt += ParseTimeSpan(time);
dt += TimeSpan.FromDays(1); dt += TimeSpan.FromDays(1);
return dt; return dt;
@@ -151,7 +162,7 @@ namespace Jackett.Common.Utils
if (match.Success) if (match.Success)
{ {
var time = str.Replace(match.Groups[0].Value, ""); var time = str.Replace(match.Groups[0].Value, "");
var dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); var dt = DateTime.SpecifyKind(now.Date, DateTimeKind.Unspecified);
dt += ParseTimeSpan(time); dt += ParseTimeSpan(time);
DayOfWeek dow; DayOfWeek dow;
@@ -188,8 +199,9 @@ namespace Jackett.Common.Utils
if (match.Success) if (match.Success)
{ {
var date = match.Groups[1].Value; var date = match.Groups[1].Value;
var newDate = DateTime.Now.Year + "-" + date; var newDate = now.Year + "-" + date;
str = str.Replace(date, newDate); str = str.Replace(date, newDate);
return FromFuzzyPastTime(str, format, now);
} }
// add missing year 2 // add missing year 2
@@ -198,7 +210,8 @@ namespace Jackett.Common.Utils
{ {
var date = match.Groups[1].Value; var date = match.Groups[1].Value;
var time = match.Groups[2].Value; var time = match.Groups[2].Value;
str = date + " " + DateTime.Now.Year + " " + time; str = date + " " + now.Year + " " + time;
return FromFuzzyPastTime(str, format, now);
} }
return FromFuzzyTime(str, format); return FromFuzzyTime(str, format);
@@ -210,8 +223,10 @@ namespace Jackett.Common.Utils
} }
// converts a date/time string to a DateTime object using a GoLang layout // converts a date/time string to a DateTime object using a GoLang layout
public static DateTime ParseDateTimeGoLang(string date, string layout) public static DateTime ParseDateTimeGoLang(string date, string layout, DateTime? relativeFrom = null)
{ {
var now = relativeFrom ?? DateTime.Now;
date = ParseUtil.NormalizeSpace(date); date = ParseUtil.NormalizeSpace(date);
var pattern = layout; var pattern = layout;
@@ -278,7 +293,10 @@ namespace Jackett.Common.Utils
try try
{ {
return DateTime.ParseExact(date, pattern, CultureInfo.InvariantCulture); var dateTime = DateTime.ParseExact(date, pattern, CultureInfo.InvariantCulture);
if (!pattern.Contains("yy") && dateTime > now)
dateTime = dateTime.AddYears(-1);
return dateTime;
} }
catch (FormatException ex) catch (FormatException ex)
{ {

View File

@@ -88,7 +88,7 @@ namespace Jackett.Test.Common.Utils
public void FromUnknownTest() public void FromUnknownTest()
{ {
var now = DateTime.Now; var now = DateTime.Now;
var today = DateTime.UtcNow.Date; var today = now.ToUniversalTime().Date;
var yesterday = today.AddDays(-1); var yesterday = today.AddDays(-1);
var tomorrow = today.AddDays(1); var tomorrow = today.AddDays(1);
var testCases = new Dictionary<string, DateTime> var testCases = new Dictionary<string, DateTime>
@@ -105,27 +105,28 @@ namespace Jackett.Test.Common.Utils
}; };
foreach (var testCase in testCases) foreach (var testCase in testCases)
Assert.AreEqual(testCase.Value, DateTimeUtil.FromUnknown(testCase.Key)); Assert.AreEqual(testCase.Value, DateTimeUtil.FromUnknown(testCase.Key, relativeFrom: now));
AssertSimilarDates(now, DateTimeUtil.FromUnknown("now")); Assert.AreEqual(now, DateTimeUtil.FromUnknown("now", relativeFrom: now));
AssertSimilarDates(now.AddHours(-3), DateTimeUtil.FromUnknown("3 hours ago")); AssertSimilarDates(now.AddHours(-3), DateTimeUtil.FromUnknown("3 hours ago", relativeFrom: now));
Assert.True((now - DateTimeUtil.FromUnknown("monday at 10:20 am")).TotalSeconds <= 3600 * 24 * 7); // 7 days Assert.True((now - DateTimeUtil.FromUnknown("monday at 10:20 am", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7); // 7 days
Assert.True((now - DateTimeUtil.FromUnknown("Tuesday at 22:20")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("Tuesday at 22:20", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.True((now - DateTimeUtil.FromUnknown("wednesday at \n 22:20")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("wednesday at \n 22:20", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.True((now - DateTimeUtil.FromUnknown("\n thursday \n at 22:20")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("\n thursday \n at 22:20", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.True((now - DateTimeUtil.FromUnknown("friday at 22:20")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("friday at 22:20", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.True((now - DateTimeUtil.FromUnknown("Saturday at 00:20")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("Saturday at 00:20", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.True((now - DateTimeUtil.FromUnknown("sunday at 22:00")).TotalSeconds <= 3600 * 24 * 7); Assert.True((now - DateTimeUtil.FromUnknown("sunday at 22:00", relativeFrom: now)).TotalSeconds <= 3600 * 24 * 7);
Assert.AreEqual(new DateTime(2020, 10, 31, 3, 8, 27, DateTimeKind.Utc).ToLocalTime(), Assert.AreEqual(new DateTime(2020, 10, 31, 3, 8, 27, DateTimeKind.Utc).ToLocalTime(),
DateTimeUtil.FromUnknown("1604113707")); DateTimeUtil.FromUnknown("1604113707", relativeFrom: now));
Assert.AreEqual(new DateTime(now.Year, 2, 1), DateTimeUtil.FromUnknown("02-01")); var refDate = new DateTime(2021, 03, 12, 12, 00, 00, DateTimeKind.Local);
Assert.AreEqual(new DateTime(now.Year, 2, 1), DateTimeUtil.FromUnknown("2-1")); Assert.AreEqual(new DateTime(refDate.Year, 2, 1), DateTimeUtil.FromUnknown("02-01", relativeFrom: refDate));
Assert.AreEqual(new DateTime(now.Year, 1, 2, 10, 30, 0), DateTimeUtil.FromUnknown("2 Jan 10:30")); Assert.AreEqual(new DateTime(refDate.Year, 2, 1), DateTimeUtil.FromUnknown("2-1", relativeFrom: refDate));
Assert.AreEqual(new DateTime(refDate.Year, 1, 2, 10, 30, 0), DateTimeUtil.FromUnknown("2 Jan 10:30", relativeFrom: refDate));
Assert.AreEqual(new DateTime(2005, 6, 10, 10, 30, 0), Assert.AreEqual(new DateTime(2005, 6, 10, 10, 30, 0),
DateTimeUtil.FromUnknown("June 10, 2005 10:30AM")); DateTimeUtil.FromUnknown("June 10, 2005 10:30AM"));
// bad cases // bad cases
@@ -138,6 +139,13 @@ namespace Jackett.Test.Common.Utils
{ {
// ignored // ignored
} }
Assert.AreEqual(new DateTime(refDate.Year - 1, 5, 2), DateTimeUtil.FromUnknown("05-02", relativeFrom: refDate));
Assert.AreEqual(new DateTime(refDate.Year - 1, 5, 2), DateTimeUtil.FromUnknown("5-2", relativeFrom: refDate));
Assert.AreEqual(new DateTime(refDate.Year - 1, 5, 2, 10, 30, 0), DateTimeUtil.FromUnknown("2 May 10:30", relativeFrom: refDate));
Assert.AreEqual(new DateTime(2020, 12, 31, 23, 59, 0), DateTimeUtil.FromUnknown("12-31 23:59", relativeFrom: new DateTime(2021, 12, 31, 23, 58, 59, DateTimeKind.Local)));
Assert.AreEqual(new DateTime(2020, 1, 1, 0, 1, 0), DateTimeUtil.FromUnknown("1-1 00:01", relativeFrom: new DateTime(2021, 1, 1, 0, 0, 0, DateTimeKind.Local)));
} }
[Test] [Test]
@@ -149,8 +157,9 @@ namespace Jackett.Test.Common.Utils
DateTimeUtil.ParseDateTimeGoLang("21-06-2010 04:20:19 -04:00", "02-01-2006 15:04:05 -07:00")); 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, 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")); DateTimeUtil.ParseDateTimeGoLang("2010-06-21 -05:30", "2006-01-02 -07:00"));
Assert.AreEqual(new DateTime(now.Year, 9, 14, 7, 0, 0), var refDate = new DateTime(2021, 03, 12, 12, 00, 00, DateTimeKind.Local);
DateTimeUtil.ParseDateTimeGoLang("7am Sep. 14", "3pm Jan. 2")); Assert.AreEqual(new DateTime(refDate.Year - 1, 9, 14, 7, 0, 0),
DateTimeUtil.ParseDateTimeGoLang("7am Sep. 14", "3pm Jan. 2", relativeFrom:refDate));
// bad cases // bad cases
try try