implement proper time zone converter

This commit is contained in:
13xforever
2019-08-19 21:25:58 +05:00
parent 1b508e34f2
commit 1f2b0f0428
3 changed files with 108 additions and 23 deletions

View File

@@ -304,15 +304,13 @@ namespace CompatBot.Commands
}
else if (txt != null)
{
var newStartTime = FixTimeString(txt.Content);
if (!DateTime.TryParse(newStartTime, out var newTime))
if (!TimeParser.TryParse(txt.Content, out var newTime))
{
errorMsg = $"Couldn't parse `{newStartTime}` as a start date and time";
errorMsg = $"Couldn't parse `{txt.Content}` as a start date and time";
goto step1;
}
var duration = evt.End - evt.Start;
newTime = Normalize(newTime);
evt.Start = newTime.Ticks;
evt.End = evt.Start + duration;
evt.Year = newTime.Year;
@@ -487,25 +485,6 @@ namespace CompatBot.Commands
return score > 0.5 ? name : eventName;
}
private static string FixTimeString(string dateTime)
{
return dateTime.ToUpperInvariant()
.Replace("PST", "-08:00")
.Replace("EST", "-05:00")
.Replace("BST", "-03:00")
.Replace("JST", "+09:00")
.Replace("AEST", "+10:00");
}
private static DateTime Normalize(DateTime date)
{
if (date.Kind == DateTimeKind.Utc)
return date;
if (date.Kind == DateTimeKind.Local)
return date.ToUniversalTime();
return date.AsUtc();
}
private static async Task<TimeSpan?> TryParseTimeSpanAsync(CommandContext ctx, string duration, bool react = true)
{
var d = Duration.Match(duration);

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Remotion.Linq.Clauses;
namespace CompatBot.Utils
{
public static class TimeParser
{
private static readonly Dictionary<string, TimeZoneInfo> TimeZoneMap;
static TimeParser()
{
var tzAcronyms = new Dictionary<string, string[]>
{
["PT"] = new[] { "Pacific Standard Time" },
["PST"] = new[] { "Pacific Standard Time" },
["PDT"] = new[] { "Pacific Standard Time" },
["EST"] = new[] { "Eastern Standard Time" },
["EDT"] = new[] { "Eastern Standard Time" },
["CEST"] = new[] { "Central European Standard Time" },
["BST"] = new[] { "British Summer Time", "GMT Standard Time" },
["JST"] = new[] { "Japan Standard Time", "Tokyo Standard Time" },
};
var uniqueNames = new HashSet<string>(
from tznl in tzAcronyms.Values
from tzn in tznl
select tzn
);
var tzList = TimeZoneInfo.GetSystemTimeZones();
var result = new Dictionary<string, TimeZoneInfo>();
foreach (var tzi in tzList)
{
if (uniqueNames.Contains(tzi.StandardName) || uniqueNames.Contains(tzi.StandardName))
{
var acronyms = from tza in tzAcronyms
where tza.Value.Contains(tzi.StandardName) || tza.Value.Contains(tzi.DaylightName)
select tza.Key;
foreach (var tza in acronyms)
result[tza] = tzi;
}
}
TimeZoneMap = result;
}
public static bool TryParse(string dateTime, out DateTime result)
{
result = default;
if (string.IsNullOrEmpty(dateTime))
return false;
dateTime = dateTime.ToUpperInvariant();
if (char.IsDigit(dateTime[dateTime.Length - 1]))
{
return DateTime.TryParse(dateTime, out result);
}
var cutIdx = dateTime.LastIndexOf(' ');
if (cutIdx < 0)
return false;
var tza = dateTime.Substring(cutIdx + 1);
dateTime = dateTime.Substring(0, cutIdx);
if (TimeZoneMap.TryGetValue(tza, out var tzi))
{
if (!DateTime.TryParse(dateTime, out result))
return false;
result = TimeZoneInfo.ConvertTimeToUtc(result, tzi);
return true;
}
return false;
}
public static DateTime Normalize(this DateTime date)
{
if (date.Kind == DateTimeKind.Utc)
return date;
if (date.Kind == DateTimeKind.Local)
return date.ToUniversalTime();
return date.AsUtc();
}
}
}

20
Tests/TimeParserTests.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using CompatBot.Utils;
using NUnit.Framework;
namespace Tests
{
[TestFixture]
public class TimeParserTests
{
[TestCase("2019-8-19 6:00 PT", "2019-08-19 13:00")]
[TestCase("2019-8-19 17:00 bst", "2019-08-19 16:00")]
public void TimeZoneConverterTest(string input, string utcInput)
{
var utc = DateTime.Parse(utcInput).Normalize();
Assert.That(TimeParser.TryParse(input, out var result), Is.True);
Assert.That(result, Is.EqualTo(utc));
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
}
}
}