diff --git a/src/Parsers/TimeSpanParser.cs b/src/Parsers/TimeSpanParser.cs
index ef5dd1c..a8d2aa5 100644
--- a/src/Parsers/TimeSpanParser.cs
+++ b/src/Parsers/TimeSpanParser.cs
@@ -1,15 +1,25 @@
-using JetBrains.Annotations;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using JetBrains.Annotations;
using Remora.Commands.Parsers;
using Remora.Results;
namespace Octobot.Parsers;
///
-/// Parses .
+/// Parses from .
///
+///
+/// Parsed .
+///
+///
+/// If parse wasn't successful, will return .
+///
[PublicAPI]
-public class TimeSpanParser : AbstractTypeParser
+public partial class TimeSpanParser : AbstractTypeParser
{
+ private static readonly Regex Pattern = ParseRegex();
+
public static Result TryParse(string timeSpanString, CancellationToken ct = default)
{
if (timeSpanString.StartsWith('-'))
@@ -17,8 +27,83 @@ public class TimeSpanParser : AbstractTypeParser
return TimeSpan.Zero;
}
- var parser = new Remora.Commands.Parsers.TimeSpanParser();
- var parseResult = parser.TryParseAsync(timeSpanString, ct).AsTask().GetAwaiter().GetResult();
- return !parseResult.IsDefined(out var @in) ? TimeSpan.Zero : @in;
+ timeSpanString = timeSpanString.Trim();
+
+ if (TimeSpan.TryParse(timeSpanString, DateTimeFormatInfo.InvariantInfo, out var parsedTimeSpan))
+ {
+ return parsedTimeSpan;
+ }
+
+ var matches = ParseRegex().Matches(timeSpanString);
+ if (matches.Count is 0)
+ {
+ return TimeSpan.Zero;
+ }
+
+ var timeSpan = TimeSpan.Zero;
+ foreach (var groups in matches.Select(match => match.Groups
+ .Cast()
+ .Where(g => g.Success)
+ .Skip(1)
+ .Select(g => (g.Name, g.Value))))
+ {
+ foreach ((var key, var groupValue) in groups)
+ {
+ return !double.TryParse(groupValue, out var parsedGroupValue)
+ ? TimeSpan.Zero
+ : ParseFromRegex(timeSpan, key, groupValue, parsedGroupValue);
+ }
+ }
+
+ return timeSpan;
}
+
+ private static Result ParseFromRegex(TimeSpan timeSpan,
+ string key, string groupValue, double parsedGroupValue)
+ {
+ if (key is "Years" or "Months")
+ {
+ if (!int.TryParse(groupValue, out var parsedIntegerValue))
+ {
+ return TimeSpan.Zero;
+ }
+
+ switch (key)
+ {
+ case "Years":
+ {
+ var now = DateTimeOffset.UtcNow;
+ var then = now.AddYears(parsedIntegerValue);
+
+ timeSpan += then - now;
+ break;
+ }
+ case "Months":
+ {
+ var now = DateTimeOffset.UtcNow;
+ var then = now.AddMonths(parsedIntegerValue);
+
+ timeSpan += then - now;
+ break;
+ }
+ }
+
+ return timeSpan;
+ }
+
+ timeSpan += key switch
+ {
+ "Weeks" => TimeSpan.FromDays(parsedGroupValue * 7),
+ "Days" => TimeSpan.FromDays(parsedGroupValue),
+ "Hours" => TimeSpan.FromHours(parsedGroupValue),
+ "Minutes" => TimeSpan.FromMinutes(parsedGroupValue),
+ "Seconds" => TimeSpan.FromSeconds(parsedGroupValue),
+ _ => throw new ArgumentOutOfRangeException(key)
+ };
+
+ return timeSpan;
+ }
+
+ [GeneratedRegex("(?\\d+(?=y|л|г))|(?\\d+(?=mo|мес))|(?\\d+(?=w|н|нед))|(?\\d+(?=d|дн))|(?\\d+(?=h|ч))|(?\\d+(?=m|min|мин|м))|(?\\d+(?=s|sec|с|сек))")]
+ private static partial Regex ParseRegex();
}