2014-09-29 157 views
4

我收到郵件存檔與這樣的日期在其中。字符串到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 Method
Converting between types
daylight-saving-time-and-time-zone-best-practices
SO Tags timezone
Coding Best Practices Using DateTime in the .NET Framework
conversion-of-a-utc-date-time-string-in-c-sharp

+0

我編輯了你的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 – 2014-09-29 17:36:20

+0

@JohnSaunders,謝謝我會牢記這一點。 – ndd 2014-09-29 17:38:55

+0

除了時區縮寫「WET」和「MET」之外,這些字符串似乎大部分都符合RFC 822/1123標準。此外,格式「GMT-5」和「+2」的偏移量沒有規定,因爲該格式要求值爲+0100「。 – 2014-09-29 17:41:19

回答

3

這些日期似乎大多是符合RFC 822 §5.1RFC 1123 §5.2.14修正。

但是,指定的幾個時區不符合規定。

  • 「WET」 通常是0000
  • 「MET」 是罕見的,但被示出爲here 0100。
  • 「GMT-5」 應寫爲 「-0500」
  • 「+2」 應寫爲 「+0200」

該格式只提供定義爲:

  • 「UT」/ 「GMT」= 0100
  • 「EDT」= -0400
  • 「EST」/ 「CDT」= -0500
  • 「CST」/ 「MDT」= -0600
  • 「MST」/ 「PDT」= -0700
  • 「PST」= -0800

注意,在正常情況下,任何時區縮寫可能是不明確的。例如,「CST」有5種不同的含義,您可以看到in this list。只有在這種特定的格式中,縮寫才具有特定的上下文。換句話說,雖然「CST」是中國標準時間的有效縮寫,但絕不會使用RFC822/1123格式值中的CST。相反,你會使用「+0800」。

現在在.NET中,RFC822/1123格式由"R" standard format specifier覆蓋。通常,您可以撥打DateTimeOffset.ParseExactDateTime.ParseExact"R"說明符。但是,您將無法在此處使用該功能,因爲它不識別「GMT」以外的任何時區縮寫,也不適用於偏移量或兩位數年份。

但是,非精確的解析器(DateTimeOffset.ParseDateTime.Parse)似乎確認了大多數重要的位,我們可以利用這一點。您必須執行一些預處理才能分配可識別的時區偏移量。

private static readonly Dictionary<string,string> TZMap = new Dictionary<string, string> 
{ 
    // 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()

+0

@mattjohson運行上面的代碼後,我注意到我得到不同的結果,這可能是我可能有錯誤,但我在發佈問題之前仔細檢查了我的答案,所以你可以幫助驗證答案嗎? http://i.stack.imgur.com/2o6E1.png – ndd 2014-09-29 19:10:43

+0

這兩個輸入值與我看起來完全相同。他們應該產生相同的輸出。我在這裏給出的方法應該給出一個帶有8:33:35和+02:00偏移量的「DateTimeOffset」。調用'.UtcDateTime'會給6:33:35。我不確定你如何得到12:33:35。 – 2014-09-29 19:17:16

+0

哦,我現在看到,你正在比較你的原始代碼和我的答案。您的原始代碼有缺陷,因爲您正在'DateTime'實例上調用'.ToUniversalTime()'。這將假定該值位於正在運行的計算機的本地時區中。你不想這樣做。你可以在'DateTimeOffset'實例上調用它,而不是'DateTime'。錯誤與'offset.DateTime.ToUniversalTime()'有關。它應該只是'offset.ToUniversalTime()' – 2014-09-29 19:20:22