2014-09-29 7 views
4

Я получаю почтовые архивы с такими датами в нем.String to 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 и Google, чтобы найти этот ответ, но не смог реализовать какой-либо ответ из этих ссылок. Если вы знаете подобный вопрос, пожалуйста, дайте мне знать.

Я уже прошел через ссылки.

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/), где консенсус« нет, они не должны ». –

+0

@JohnSaunders, спасибо, я буду помнить об этом. – ndd

+0

Строки, по-видимому, в основном соответствуют требованиям RFC 822/1123, за исключением сокращений часового пояса «WET» и «MET». Кроме того, смещения в форме «GMT-5» и «+2» не соответствуют спецификации, так как этот формат требует значений, таких как +0100 ». –

ответ

3

Эти даты появляются в основном быть совместимы с RFC 822 §5.1 с внесенными RFC 1123 §5.2.14.

Однако некоторые из указанных часовых поясов не соответствуют требованиям.

  • "WET" обычно +0000
  • "МЕТ" редко, но показано here как +0100.
  • "GMT-5" должно быть записано как "-0500"
  • "+2" должен быть записан как "+0200"

Этот формат обеспечивает только для определения:

  • "УТ"/"GMT" = +0100
  • "EDT" = -0400
  • "EST"/"CDT" = -0500
  • "ДКБ"/"МДТ" = -0600
  • "МСТ"/"ФДТ" = -0700
  • "ПСТ" = -0800

Обратите внимание, что при нормальных условиях, любого часового пояса аббревиатура может быть неоднозначной. Например, существует 5 различных значений «CST», как вы можете видеть in this list. Только в этом конкретном формате аббревиатура имеет конкретный контекст. Другими словами, хотя «КНТ» является допустимым сокращением для стандартного времени в Китае, вы никогда не будете использовать CST в формате RFC822/1123. Вместо этого вы будете использовать «+0800».

Теперь в .NET формат RFC822/1123 покрывается "R" standard format specifier. Обычно вы можете позвонить DateTimeOffset.ParseExact или DateTime.ParseExact с помощью спецификатора "R". Однако вы не сможете использовать это здесь, потому что он не распознает аббревиатуру какого-либо времени, кроме «GMT», и не работает с смещениями или двузначными годами.

Однако неточный парсер (DateTimeOffset.Parse или DateTime.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

+0

Эти два входных значения выглядят идентично мне. Они должны производить одинаковый вывод. Метод, который я дал здесь, должен давать 'DateTimeOffset' с смещением 8:33:35 и +02: 00. Вызов '.UtcDateTime' даст 6:33:35. Я не уверен, как вы получили 12:33:35. –

+0

О, теперь я вижу, вы сравниваете свой исходный код с моим ответом. Ваш исходный код является ошибочным, потому что вы вызываете '.ToUniversalTime()' на экземпляр 'DateTime'. Это будет предполагать, что это значение находится в локальном часовом поясе компьютера, на котором вы работаете. Вы не хотите этого делать. Вы можете вызвать его на экземпляре 'DateTimeOffset', а не на' DateTime'. Ошибка связана с 'offset.DateTime.ToUniversalTime()'. Это должно быть просто 'offset.ToUniversalTime()' –

Смежные вопросы