diff --git a/src/NzbDrone.Core.Test/ParserTests/DateTimeUtilFixture.cs b/src/NzbDrone.Core.Test/ParserTests/DateTimeUtilFixture.cs new file mode 100644 index 000000000..7dbea8b3e --- /dev/null +++ b/src/NzbDrone.Core.Test/ParserTests/DateTimeUtilFixture.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; +using System.Threading; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ParserTests +{ + [TestFixture] + public class DateTimeUtilFixture : CoreTest + { + [TestCase("pt-BR")] + [TestCase("en-US")] + public void should_format_date_invariant(string culture) + { + Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); + + var dateNow = DateTime.Now; + + DateTimeUtil.FromUnknown(dateNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)) + .ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture) + .Should().Be(dateNow.ToString("ddd, dd MMM yyyy HH':'mm':'ss z", CultureInfo.InvariantCulture)); + } + + [TestCase("2022-08-08 02:07:39 -02:00", "2006-01-02 15:04:05 -07:00", "yyyy-MM-dd HH:mm:ss zzz", "2022-08-08 04:07:39 +00:00")] + [TestCase("2022-08-08 02:07:39 -02:00", "yyyy-MM-dd HH:mm:ss zzz", "yyyy-MM-dd HH:mm:ss zzz", "2022-08-08 04:07:39 +00:00")] + [TestCase("2022-08-08 -02:00", "2006-01-02 -07:00", "yyyy-MM-dd zzz", "2022-08-08 +00:00")] + [TestCase("2022-08-08 -02:00", "yyyy-MM-dd zzz", "yyyy-MM-dd zzz", "2022-08-08 +00:00")] + [TestCase("02:07:39 -02:00", "15:04:05 -07:00", "HH:mm:ss zzz", "04:07:39 +00:00")] + [TestCase("02:07:39 -02:00", "HH:mm:ss zzz", "HH:mm:ss zzz", "04:07:39 +00:00")] + [TestCase("-02:00", "zzz", "zzz", "+00:00")] + [TestCase("-02:00", "-07:00", "zzz", "+00:00")] + public void parse_datetime_golang(string dateInput, string format, string standardFormat, string expectedDate) + { + DateTimeUtil.ParseDateTimeGoLang(dateInput, format) + .ToUniversalTime() + .ToString(standardFormat, CultureInfo.InvariantCulture) + .Should().Be(expectedDate); + } + } +} diff --git a/src/NzbDrone.Core.Test/ParserTests/DateUtilFixture.cs b/src/NzbDrone.Core.Test/ParserTests/DateUtilFixture.cs deleted file mode 100644 index df2d4350c..000000000 --- a/src/NzbDrone.Core.Test/ParserTests/DateUtilFixture.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Globalization; -using System.Threading; -using FluentAssertions; -using NUnit.Framework; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.ParserTests -{ - [TestFixture] - public class DateUtilFixture : CoreTest - { - [TestCase("pt-BR")] - [TestCase("en-US")] - public void should_format_date_invariant(string culture) - { - Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); - - var dateNow = DateTime.Now; - - DateTimeUtil.FromUnknown(dateNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)) - .ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture) - .Should().Be(dateNow.ToString("ddd, dd MMM yyyy HH':'mm':'ss z", CultureInfo.InvariantCulture)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 8c940bc2d..dcfeb4024 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -615,21 +615,14 @@ namespace NzbDrone.Core.Indexers.Cardigann case "dateparse": var layout = (string)filter.Args; - if (layout.Contains("yy") && DateTime.TryParseExact(data, layout, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate)) + try { - data = parsedDate.ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture); + var date = DateTimeUtil.ParseDateTimeGoLang(data, layout); + data = date.ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture); } - else + catch (InvalidDateException ex) { - try - { - var date = DateTimeUtil.ParseDateTimeGoLang(data, layout); - data = date.ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture); - } - catch (InvalidDateException ex) - { - _logger.Debug(ex.Message); - } + _logger.Debug(ex.Message); } break; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 91374487f..9be1f9485 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -509,7 +509,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.Seeders.ToString(); break; case "date": - release.PublishDate = DateTimeUtil.FromUnknown(value); + release.PublishDate = DateTime.TryParseExact(value, DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate) ? parsedDate : DateTimeUtil.FromUnknown(value); value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern, CultureInfo.InvariantCulture); break; case "files": diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index ca98c2af0..f2bcfd312 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -251,69 +251,73 @@ namespace NzbDrone.Core.Parser public static DateTime ParseDateTimeGoLang(string date, string layout) { date = date.Trim(); - var pattern = layout; - // year - pattern = pattern.Replace("2006", "yyyy"); - pattern = pattern.Replace("06", "yy"); + var commonStandardFormats = new[] { "y", "h", "d" }; - // month - pattern = pattern.Replace("January", "MMMM"); - pattern = pattern.Replace("Jan", "MMM"); - pattern = pattern.Replace("01", "MM"); + if (commonStandardFormats.Any(layout.ContainsIgnoreCase) && DateTime.TryParseExact(date, layout, CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate)) + { + return parsedDate; + } - // day - pattern = pattern.Replace("Monday", "dddd"); - pattern = pattern.Replace("Mon", "ddd"); - pattern = pattern.Replace("02", "dd"); - pattern = pattern.Replace("2", "d"); + var format = layout - // hours/minutes/seconds - pattern = pattern.Replace("05", "ss"); + // year + .Replace("2006", "yyyy") + .Replace("06", "yy") - pattern = pattern.Replace("15", "HH"); - pattern = pattern.Replace("03", "hh"); - pattern = pattern.Replace("3", "h"); + // month + .Replace("January", "MMMM") + .Replace("Jan", "MMM") + .Replace("01", "MM") - pattern = pattern.Replace("04", "mm"); - pattern = pattern.Replace("4", "m"); + // day + .Replace("Monday", "dddd") + .Replace("Mon", "ddd") + .Replace("02", "dd") + .Replace("2", "d") - pattern = pattern.Replace("5", "s"); + // hours/minutes/seconds + .Replace("05", "ss") + .Replace("15", "HH") + .Replace("03", "hh") + .Replace("3", "h") + .Replace("04", "mm") + .Replace("4", "m") + .Replace("5", "s") - // month again - pattern = pattern.Replace("1", "M"); + // month again + .Replace("1", "M") - // fractional seconds - pattern = pattern.Replace(".0000", "ffff"); - pattern = pattern.Replace(".000", "fff"); - pattern = pattern.Replace(".00", "ff"); - pattern = pattern.Replace(".0", "f"); + // fractional seconds + .Replace(".0000", "ffff") + .Replace(".000", "fff") + .Replace(".00", "ff") + .Replace(".0", "f") + .Replace(".9999", "FFFF") + .Replace(".999", "FFF") + .Replace(".99", "FF") + .Replace(".9", "F") - pattern = pattern.Replace(".9999", "FFFF"); - pattern = pattern.Replace(".999", "FFF"); - pattern = pattern.Replace(".99", "FF"); - pattern = pattern.Replace(".9", "F"); + // AM/PM + .Replace("PM", "tt") + .Replace("pm", "tt") // not sure if this works - // AM/PM - pattern = pattern.Replace("PM", "tt"); - pattern = pattern.Replace("pm", "tt"); // not sure if this works - - // timezones - // these might need further tuning - pattern = pattern.Replace("Z07:00", "'Z'zzz"); - pattern = pattern.Replace("Z07", "'Z'zz"); - pattern = pattern.Replace("Z07:00", "'Z'zzz"); - pattern = pattern.Replace("Z07", "'Z'zz"); - pattern = pattern.Replace("-07:00", "zzz"); - pattern = pattern.Replace("-07", "zz"); + // timezones + // these might need further tuning + .Replace("Z07:00", "'Z'zzz") + .Replace("Z07", "'Z'zz") + .Replace("Z07:00", "'Z'zzz") + .Replace("Z07", "'Z'zz") + .Replace("-07:00", "zzz") + .Replace("-07", "zz"); try { - return DateTime.ParseExact(date, pattern, CultureInfo.InvariantCulture); + return DateTime.ParseExact(date, format, CultureInfo.InvariantCulture); } catch (FormatException ex) { - throw new InvalidDateException($"Error while parsing DateTime \"{date}\", using layout \"{layout}\" ({pattern}): {ex.Message}", ex); + throw new InvalidDateException($"Error while parsing DateTime \"{date}\", using layout \"{layout}\" ({format}): {ex.Message}", ex); } }