字符串到UTC时间转换

我收到的邮件档案中包含这样的日期。

Wed, 17 Dec 1997 13:36:23 +2 Mon, 16 Jun 1997 15:41:52 EST Tue, 15 Jul 1997 14:37:00 EDT Tue, 5 Aug 1997 08:37:56 PST Tue, 5 Aug 1997 15:46:16 PDT Thu, 5 Mar 1998 08:44:19 MET Mon, 8 Nov 1999 17:49:25 GMT Thu, 24 Feb 94 20:06:06 MST Mon, 19 Dec 2005 14:17:06 CST Thu, 14 Sep 95 19:15 CDT Sat, 22 Feb 1997 05:16:55 UT Mon, 8 Jul 1996 15:48:54 GMT-5 Mon, 25 Nov 1996 17:10:28 WET Mon, 6 Jan 1997 23:43:48 UT Fri, 13 Jun 1997 16:44:03 -0400 

问是将此时间转换为UTC。 这就是我试图这样做的方式。

 static void Main(string[] args) { var possibleValues = new string[] { "Mon, 29 Sep 2014 08:33:35 +0200" , "Fri, 29 Jun 2001 07:53:01 -0700" ,"Fri, 26 Sep 2014 15:57:04 +0000" ,"Wed, 17 Dec 1997 13:36:23 +2" , "Fri, 13 Jun 1997 16:44:03 -0400" , "Mon, 16 Jun 1997 15:41:52 EST" , "Tue, 15 Jul 1997 14:37:00 EDT" , "Tue, 5 Aug 1997 08:37:56 PST" , "Tue, 5 Aug 1997 15:46:16 PDT" , "Thu, 5 Mar 1998 08:44:19 MET" , "Mon, 8 Nov 1999 17:49:25 GMT" , "Thu, 24 Feb 94 20:06:06 MST" , "Mon, 19 Dec 2005 14:17:06 CST" , "Thu, 14 Sep 95 19:15:00 CDT" , "Sat, 22 Feb 1997 05:16:55 UT" , "Mon, 8 Jul 1996 15:48:54 GMT-5" , "Mon, 25 Nov 1996 17:10:28 WET" , "Mon, 6 Jan 1997 23:43:48 UT" }; foreach (var item in possibleValues) { var dateParts = item.Split(' '); var lastItem = dateParts[dateParts.Length - 1]; if (lastItem.StartsWith("+") || lastItem.StartsWith("-")) { try { DateTimeOffset offset = DateTimeOffset.Parse(item, CultureInfo.InvariantCulture); Debug.WriteLine("Input: {0}, UTC Time: {1}", item, offset.UtcDateTime); } catch (Exception exc) { Debug.WriteLine("Failed - {0}, Error Message: {1}", item, exc.Message); } } else { //Sometimes year is a two digit number and sometimes it is 4 digit number. string dateFormat = string.Format("ddd, {0} MMM {1} {2}:mm:ss {3}", new string('d', dateParts[1].Length), new string('y', dateParts[3].Length), int.Parse(dateParts[4].Substring(0, 2)) > 12 ? "HH" : "hh", lastItem); try { DateTimeOffset offset = DateTimeOffset.ParseExact(item, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None); Debug.WriteLine("Input: {0}, UTC Time: {1}", item, offset.UtcDateTime); } catch (Exception exc) { Debug.WriteLine("Failed - {0}, DateFormat Tried: {1}, Error Message: {2}", item, dateFormat, exc.Message); } } } } 

我无法弄清楚如何处理所有情况。 我也愿意使用野田时间。

我已经通过SO和谷歌的许多链接找到了这个答案,但无法从这些链接中实现任何答案。 如果您知道类似的问题,请告诉我。

我已经通过以下链接了。

Convert.ToDateTime方法
在类型之间转换
日光节约时间和时间区域-最佳实践
所以标签时区
编码在.NET Framework中使用DateTime的最佳实践
转换对的一-UTC-日期-时间-串在-C-尖锐

这些日期似乎主要符合RFC822§5.1,并经RFC1123§5.2.14修订。

但是,指定的几个时区不符合要求。

  • “WET”通常为+0000
  • “MET”很少见,但此处显示为+0100。
  • “GMT-5”应写成“-0500”
  • “+2”应写为“+0200”

该格式仅提供以下定义:

  • “UT”/“GMT”= +0100
  • “EDT”= – 0400
  • “EST”/“CDT”= – 0500
  • “CST”/“MDT”= -0600
  • “MST”/“PDT”= -0700
  • “PST”= -0800

请注意,在正常情况下, 任何时区缩写都可能不明确。 例如,“CST”有5种不同的含义,您可以在此列表中看到。 只有在这种特定的格式中,缩写才具有特定的上下文。 换句话说,虽然“CST”是中国标准时间的有效缩写,但您永远不会在RFC822 / 1123格式化值中使用CST。 相反,你会使用“+0800”。

现在在.NET中,RFC822 / 1123格式由"R"标准格式说明符覆盖。 通常,您可以使用"R"说明符调用DateTimeOffset.ParseExactDateTime.ParseExact 。 但是,您将无法在此处使用它,因为它不识别除“GMT”之外的任何时区缩写,也不适用于偏移或两位数年份。

但是,非精确解析器( DateTimeOffset.ParseDateTime.Parse )似乎确实识别了大部分重要位,我们可以利用这一点。 您必须进行一些预处理以分配可识别的时区偏移。

 private static readonly Dictionary TZMap = new Dictionary { // Defined by RFC822, but not known to .NET {"UT", "+0000"}, {"EST", "-0500"}, {"EDT", "-0400"}, {"CST", "-0600"}, {"CDT", "-0500"}, {"MST", "-0700"}, {"MDT", "-0600"}, {"PST", "-0800"}, {"PDT", "-0700"}, // Extraneous, as found in your data {"WET", "+0000"}, {"MET", "+0100"} }; public static DateTimeOffset Parse(string s) { // Get the time zone part of the string var tz = s.Substring(s.LastIndexOf(' ') + 1); // Replace time zones defined in the map if (TZMap.ContainsKey(tz)) { s = s.Substring(0, s.Length - tz.Length) + TZMap[tz]; } // Replace time zone offsets with leading characters if (tz.StartsWith("GMT+") || tz.StartsWith("GMT-") || tz.StartsWith("UTC+") || tz.StartsWith("UTC-")) { s = s.Substring(0, s.Length - tz.Length) + tz.Substring(3); } DateTimeOffset dto; if (DateTimeOffset.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, out dto)) { return dto; } throw new ArgumentException("Could not parse value: " + s); } 

这会传递您提供的所有示例值,但是您可能会发现需要添加到地图中的更多无关值。 在识别所有边缘情况之前,可能需要多次浏览数据。

当然,既然你在这里找回了DateTimeOffset ,如果你想要UTC值,你可以使用.UtcDateTime.ToUniversalTime()