【问题标题】:How do I parse and convert DateTime’s to the RFC 822 date-time format?如何解析 DateTime 并将其转换为 RFC 822 日期时间格式?
【发布时间】:2010-09-22 00:52:40
【问题描述】:

如何将 DateTime 结构转换为其等效的 RFC 822 date-time 格式化字符串表示将此字符串表示解析回 .NET 中的 DateTime 结构? RFC-822 日期时间格式用于许多规范,例如 RSS Syndication Format

【问题讨论】:

  • 我在寻找 .NET 实现。
  • 我想更新一下以使用 DateTimeOffset。
  • .NET 有一个开箱即用的 RSS 2.0 格式化程序,它可以正确地将项目发布日期序列化为 RFC 822。有关详细信息,请参阅 System.ServiceModel 程序集中的 Rss20FeedFormatter 类。
  • 另见 Kirk 对用于 RSS 日期序列化的内部 .NET 代码的回答。

标签: .net datetime rss rfc822


【解决方案1】:

根据 Kirk Liemohn 的回答,我成功地使用了这种方法:

private DateTimeOffset? ParseDate(string date)
    {
        const string FORMAT = "ddd, d MMM yyyy HH:mm:ss zzz";
        const string FORMAT2 = "ddd, dd MMM yyyy HH:mm:ss zzz";
        const string FORMAT3 = "dd MMM yyyy HH:mm:ss zzz";
        const string FORMAT4 = "d MMM yyyy HH:mm:ss zzz";
        DateTimeOffset d;
        if (DateTimeOffset.TryParseExact(date, new string[] { FORMAT, FORMAT2, FORMAT3, FORMAT4 }, CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite, out d))
            return d;
        return null;
    }

例子:

DateTimeOffset? date = ParseDate("Thu, 5 Apr 2012 23:47:37 +0200");
Console.WriteLine(date.ToString());
// => 05/04/2012 23:47:37 +02:00

它不尊重 RFC 的完整规范,但它适用于我的用例。

具体来说,它不适用于时区快递,例如:“GMT”、“CST”等(请参阅"zone" in RFC822 Section 5.1)。请参阅better answer of Oleksandr Pshenychnyy

【讨论】:

    【解决方案2】:

    按照 Kirk 的想法,我反编译了 System.ServiceModel.Syndication.Rss20FeedFormatter 类 (System.ServiceModel.dll) 的源代码,这里是 Microsoft RFC 822 日期格式的内部解析器(我稍微简化了他们的异常处理逻辑以减少依赖):

    public static class DateTimeParser
    {
        public static DateTimeOffset ParseDateTimeRFC822(string dateTimeString)
        {
            StringBuilder dateTimeStringBuilder = new StringBuilder(dateTimeString.Trim());
            if (dateTimeStringBuilder.Length < 18)
            {
                throw new FormatException("Invalid date format. Expected date in RFC 822 format");
            }
            if (dateTimeStringBuilder[3] == ',')
            {
                // There is a leading (e.g.) "Tue, ", strip it off
                dateTimeStringBuilder.Remove(0, 4);
                // There's supposed to be a space here but some implementations dont have one
                RemoveExtraWhiteSpaceAtStart(dateTimeStringBuilder);
            }
            ReplaceMultipleWhiteSpaceWithSingleWhiteSpace(dateTimeStringBuilder);
            if (char.IsDigit(dateTimeStringBuilder[1]))
            {
                // two-digit day, we are good
            }
            else
            {
                dateTimeStringBuilder.Insert(0, '0');
            }
            if (dateTimeStringBuilder.Length < 19)
            {
                throw new FormatException("Invalid date format. Expected date in RFC 822 format");
            }
            bool thereAreSeconds = (dateTimeStringBuilder[17] == ':');
            int timeZoneStartIndex;
            if (thereAreSeconds)
            {
                timeZoneStartIndex = 21;
            }
            else
            {
                timeZoneStartIndex = 18;
            }
            string timeZoneSuffix = dateTimeStringBuilder.ToString().Substring(timeZoneStartIndex);
            dateTimeStringBuilder.Remove(timeZoneStartIndex, dateTimeStringBuilder.Length - timeZoneStartIndex);
            bool isUtc;
            dateTimeStringBuilder.Append(NormalizeTimeZone(timeZoneSuffix, out isUtc));
            string wellFormattedString = dateTimeStringBuilder.ToString();
    
            DateTimeOffset theTime;
            string parseFormat;
            if (thereAreSeconds)
            {
                parseFormat = "dd MMM yyyy HH:mm:ss zzz";
            }
            else
            {
                parseFormat = "dd MMM yyyy HH:mm zzz";
            }
            if (DateTimeOffset.TryParseExact(wellFormattedString, parseFormat,
                CultureInfo.InvariantCulture.DateTimeFormat,
                (isUtc ? DateTimeStyles.AdjustToUniversal : DateTimeStyles.None), out theTime))
            {
                return theTime;
            }
            throw new FormatException("Invalid date format. Expected date in RFC 822 format");
        }
    
        static string NormalizeTimeZone(string rfc822TimeZone, out bool isUtc)
        {
            isUtc = false;
            // return a string in "-08:00" format
            if (rfc822TimeZone[0] == '+' || rfc822TimeZone[0] == '-')
            {
                // the time zone is supposed to be 4 digits but some feeds omit the initial 0
                StringBuilder result = new StringBuilder(rfc822TimeZone);
                if (result.Length == 4)
                {
                    // the timezone is +/-HMM. Convert to +/-HHMM
                    result.Insert(1, '0');
                }
                result.Insert(3, ':');
                return result.ToString();
            }
            switch (rfc822TimeZone)
            {
                case "UT":
                case "Z":
                    isUtc = true;
                    return "-00:00";
                case "GMT":
                    return "-00:00";
                case "A":
                    return "-01:00";
                case "B":
                    return "-02:00";
                case "C":
                    return "-03:00";
                case "D":
                case "EDT":
                    return "-04:00";
                case "E":
                case "EST":
                case "CDT":
                    return "-05:00";
                case "F":
                case "CST":
                case "MDT":
                    return "-06:00";
                case "G":
                case "MST":
                case "PDT":
                    return "-07:00";
                case "H":
                case "PST":
                    return "-08:00";
                case "I":
                    return "-09:00";
                case "K":
                    return "-10:00";
                case "L":
                    return "-11:00";
                case "M":
                    return "-12:00";
                case "N":
                    return "+01:00";
                case "O":
                    return "+02:00";
                case "P":
                    return "+03:00";
                case "Q":
                    return "+04:00";
                case "R":
                    return "+05:00";
                case "S":
                    return "+06:00";
                case "T":
                    return "+07:00";
                case "U":
                    return "+08:00";
                case "V":
                    return "+09:00";
                case "W":
                    return "+10:00";
                case "X":
                    return "+11:00";
                case "Y":
                    return "+12:00";
                default:
                    return "";
            }
        }
    
        static void RemoveExtraWhiteSpaceAtStart(StringBuilder stringBuilder)
        {
            int i = 0;
            while (i < stringBuilder.Length)
            {
                if (!char.IsWhiteSpace(stringBuilder[i]))
                {
                    break;
                }
                ++i;
            }
            if (i > 0)
            {
                stringBuilder.Remove(0, i);
            }
        }
    
        static void ReplaceMultipleWhiteSpaceWithSingleWhiteSpace(StringBuilder builder)
        {
            int index = 0;
            int whiteSpaceStart = -1;
            while (index < builder.Length)
            {
                if (char.IsWhiteSpace(builder[index]))
                {
                    if (whiteSpaceStart < 0)
                    {
                        whiteSpaceStart = index;
                        // normalize all white spaces to be ' ' so that the date time parsing works
                        builder[index] = ' ';
                    }
                }
                else if (whiteSpaceStart >= 0)
                {
                    if (index > whiteSpaceStart + 1)
                    {
                        // there are at least 2 spaces... replace by 1
                        builder.Remove(whiteSpaceStart, index - whiteSpaceStart - 1);
                        index = whiteSpaceStart + 1;
                    }
                    whiteSpaceStart = -1;
                }
                ++index;
            }
            // we have already trimmed the start and end so there cannot be a trail of white spaces in the end
            Debug.Assert(builder.Length == 0 || builder[builder.Length - 1] != ' ', "The string builder doesnt end in a white space");
        }
    }
    

    可能看起来不寻常的第一件事是它们返回[DateTimeOffset][1] 类而不是DateTime。但是当我们阅读更多关于它的信息时,它似乎完全合乎逻辑 - DateTimeOffset 存储 日期、时间和时区 信息(完全是 RFC 822 格式的字符串)。 如果您只返回 DateTime 对象,它将位于哪个时区:UTC、本地或在解析字符串中指定的时区 - 在某些情况下,任何答案都是错误的。所以DateTimeOffset 解决了一个重要的不确定性问题。您可以使用 DateTimeOffset.ToUniversalTime()DateTimeOffset.ToLocalTime() 方法将其转换为您以后需要的时区。

    我在少数情况下对其进行了测试,它似乎完美地完成了这项工作。

    但我不确定,为什么 Microsoft 决定将此实现设为私有 - 它似乎不需要太多支持。

    【讨论】:

      【解决方案3】:

      这是 C# 中的一个实现,说明如何解析 DateTime 并将其转换为 RFC-822 表示和从它的 RFC-822 表示转换。它的唯一限制是 DateTime 采用协调世界时 (UTC)。我同意这不是非常优雅的代码,但它可以完成工作。

      /// <summary>
      /// Provides methods for converting <see cref="DateTime"/> structures 
      /// to and from the equivalent <a href="http://www.w3.org/Protocols/rfc822/#z28">RFC 822</a> 
      /// string representation.
      /// </summary>
      public class Rfc822DateTime
      {
          //============================================================
          //  Private members
          //============================================================
          #region Private Members
          /// <summary>
          /// Private member to hold array of formats that RFC 822 date-time representations conform to.
          /// </summary>
          private static string[] formats = new string[0];
          /// <summary>
          /// Private member to hold the DateTime format string for representing a DateTime in the RFC 822 format.
          /// </summary>
          private const string format     = "ddd, dd MMM yyyy HH:mm:ss K";
          #endregion
      
          //============================================================
          //  Public Properties
          //============================================================
          #region Rfc822DateTimeFormat
          /// <summary>
          /// Gets the custom format specifier that may be used to represent a <see cref="DateTime"/> in the RFC 822 format.
          /// </summary>
          /// <value>A <i>DateTime format string</i> that may be used to represent a <see cref="DateTime"/> in the RFC 822 format.</value>
          /// <remarks>
          /// <para>
          /// This method returns a string representation of a <see cref="DateTime"/> that utilizes the time zone 
          /// offset (local differential) to represent the offset from Greenwich mean time in hours and minutes. 
          /// The <see cref="Rfc822DateTimeFormat"/> is a valid date-time format string for use 
          /// in the <see cref="DateTime.ToString(String, IFormatProvider)"/> method.
          /// </para>
          /// <para>
          /// The <a href="http://www.w3.org/Protocols/rfc822/#z28">RFC 822</a> Date and Time specification 
          /// specifies that the year will be represented as a two-digit value, but the 
          /// <a href="http://www.rssboard.org/rss-profile#data-types-datetime">RSS Profile</a> recommends that 
          /// all date-time values should use a four-digit year. The <see cref="Rfc822DateTime"/> class 
          /// follows the RSS Profile recommendation when converting a <see cref="DateTime"/> to the equivalent 
          /// RFC 822 string representation.
          /// </para>
          /// </remarks>
          public static string Rfc822DateTimeFormat
          {
              get
              {
                  return format;
              }
          }
          #endregion
      
          #region Rfc822DateTimePatterns
          /// <summary>
          /// Gets an array of the expected formats for RFC 822 date-time string representations.
          /// </summary>
          /// <value>
          /// An array of the expected formats for RFC 822 date-time string representations 
          /// that may used in the <see cref="DateTime.TryParseExact(String, string[], IFormatProvider, DateTimeStyles, out DateTime)"/> method.
          /// </value>
          /// <remarks>
          /// The array of the expected formats that is returned assumes that the RFC 822 time zone 
          /// is represented as or converted to a local differential representation.
          /// </remarks>
          /// <seealso cref="ConvertZoneToLocalDifferential(String)"/>
          public static string[] Rfc822DateTimePatterns
          {
              get
              {
                  if (formats.Length > 0)
                  {
                      return formats;
                  }
                  else
                  {
                      formats = new string[35];
      
                      // two-digit day, four-digit year patterns
                      formats[0]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'fffffff zzzz";
                      formats[1]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'ffffff zzzz";
                      formats[2]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'fffff zzzz";
                      formats[3]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'ffff zzzz";
                      formats[4]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'fff zzzz";
                      formats[5]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'ff zzzz";
                      formats[6]  = "ddd',' dd MMM yyyy HH':'mm':'ss'.'f zzzz";
                      formats[7]  = "ddd',' dd MMM yyyy HH':'mm':'ss zzzz";
      
                      // two-digit day, two-digit year patterns
                      formats[8]  = "ddd',' dd MMM yy HH':'mm':'ss'.'fffffff zzzz";
                      formats[9]  = "ddd',' dd MMM yy HH':'mm':'ss'.'ffffff zzzz";
                      formats[10] = "ddd',' dd MMM yy HH':'mm':'ss'.'fffff zzzz";
                      formats[11] = "ddd',' dd MMM yy HH':'mm':'ss'.'ffff zzzz";
                      formats[12] = "ddd',' dd MMM yy HH':'mm':'ss'.'fff zzzz";
                      formats[13] = "ddd',' dd MMM yy HH':'mm':'ss'.'ff zzzz";
                      formats[14] = "ddd',' dd MMM yy HH':'mm':'ss'.'f zzzz";
                      formats[15] = "ddd',' dd MMM yy HH':'mm':'ss zzzz";
      
                      // one-digit day, four-digit year patterns
                      formats[16] = "ddd',' d MMM yyyy HH':'mm':'ss'.'fffffff zzzz";
                      formats[17] = "ddd',' d MMM yyyy HH':'mm':'ss'.'ffffff zzzz";
                      formats[18] = "ddd',' d MMM yyyy HH':'mm':'ss'.'fffff zzzz";
                      formats[19] = "ddd',' d MMM yyyy HH':'mm':'ss'.'ffff zzzz";
                      formats[20] = "ddd',' d MMM yyyy HH':'mm':'ss'.'fff zzzz";
                      formats[21] = "ddd',' d MMM yyyy HH':'mm':'ss'.'ff zzzz";
                      formats[22] = "ddd',' d MMM yyyy HH':'mm':'ss'.'f zzzz";
                      formats[23] = "ddd',' d MMM yyyy HH':'mm':'ss zzzz";
      
                      // two-digit day, two-digit year patterns
                      formats[24] = "ddd',' d MMM yy HH':'mm':'ss'.'fffffff zzzz";
                      formats[25] = "ddd',' d MMM yy HH':'mm':'ss'.'ffffff zzzz";
                      formats[26] = "ddd',' d MMM yy HH':'mm':'ss'.'fffff zzzz";
                      formats[27] = "ddd',' d MMM yy HH':'mm':'ss'.'ffff zzzz";
                      formats[28] = "ddd',' d MMM yy HH':'mm':'ss'.'fff zzzz";
                      formats[29] = "ddd',' d MMM yy HH':'mm':'ss'.'ff zzzz";
                      formats[30] = "ddd',' d MMM yy HH':'mm':'ss'.'f zzzz";
                      formats[31] = "ddd',' d MMM yy HH':'mm':'ss zzzz";
      
                      // Fall back patterns
                      formats[32] = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK"; // RoundtripDateTimePattern
                      formats[33] = DateTimeFormatInfo.InvariantInfo.UniversalSortableDateTimePattern;
                      formats[34] = DateTimeFormatInfo.InvariantInfo.SortableDateTimePattern;
      
                      return formats;
                  }
              }
          }
          #endregion
      
          //============================================================
          //  Public Methods
          //============================================================
          #region Parse(string s)
          /// <summary>
          /// Converts the specified string representation of a date and time to its <see cref="DateTime"/> equivalent.
          /// </summary>
          /// <param name="s">A string containing a date and time to convert.</param>
          /// <returns>
          /// A <see cref="DateTime"/> equivalent to the date and time contained in <paramref name="s"/>, 
          /// expressed as <i>Coordinated Universal Time (UTC)</i>.
          /// </returns>
          /// <remarks>
          /// The string <paramref name="s"/> is parsed using formatting information in the <see cref="DateTimeFormatInfo.InvariantInfo"/> object.
          /// </remarks>
          /// <exception cref="ArgumentNullException"><paramref name="s"/> is a <b>null</b> reference (Nothing in Visual Basic).</exception>
          /// <exception cref="ArgumentNullException"><paramref name="s"/> is an empty string.</exception>
          /// <exception cref="FormatException"><paramref name="s"/> does not contain a valid RFC 822 string representation of a date and time.</exception>
          public static DateTime Parse(string s)
          {
              //------------------------------------------------------------
              //  Validate parameter
              //------------------------------------------------------------
              if (String.IsNullOrEmpty(s))
              {
                throw new ArgumentNullException("s");
              }
      
              DateTime result;
              if (Rfc822DateTime.TryParse(s, out result))
              {
                  return result;
              }
              else
              {
                  throw new FormatException(String.Format(null, "{0} is not a valid RFC 822 string representation of a date and time.", s));
              }
          }
          #endregion
      
          #region ConvertZoneToLocalDifferential(string s)
          /// <summary>
          /// Converts the time zone component of an RFC 822 date and time string representation to its local differential (time zone offset).
          /// </summary>
          /// <param name="s">A string containing an RFC 822 date and time to convert.</param>
          /// <returns>A date and time string that uses local differential to describe the time zone equivalent to the date and time contained in <paramref name="s"/>.</returns>
          /// <exception cref="ArgumentNullException"><paramref name="s"/> is a <b>null</b> reference (Nothing in Visual Basic).</exception>
          /// <exception cref="ArgumentNullException"><paramref name="s"/> is an empty string.</exception>
          public static string ConvertZoneToLocalDifferential(string s)
          {
              string zoneRepresentedAsLocalDifferential   = String.Empty;
      
              //------------------------------------------------------------
              //  Validate parameter
              //------------------------------------------------------------
              if (String.IsNullOrEmpty(s))
              {
                throw new ArgumentNullException("s");
              }
      
              if(s.EndsWith(" UT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" UT") + 1) ), "+00:00");
              }
              else if (s.EndsWith(" GMT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" GMT") + 1 ) ), "+00:00");
              }
              else if (s.EndsWith(" EST", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" EST") + 1)), "-05:00");
              }
              else if (s.EndsWith(" EDT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" EDT") + 1)), "-04:00");
              }
              else if (s.EndsWith(" CST", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" CST") + 1)), "-06:00");
              }
              else if (s.EndsWith(" CDT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" CDT") + 1)), "-05:00");
              }
              else if (s.EndsWith(" MST", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" MST") + 1)), "-07:00");
              }
              else if (s.EndsWith(" MDT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" MDT") + 1)), "-06:00");
              }
              else if (s.EndsWith(" PST", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" PST") + 1)), "-08:00");
              }
              else if (s.EndsWith(" PDT", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" PDT") + 1)), "-07:00");
              }
              else if (s.EndsWith(" Z", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" Z") + 1)), "+00:00");
              }
              else if (s.EndsWith(" A", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" A") + 1)), "-01:00");
              }
              else if (s.EndsWith(" M", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" M") + 1)), "-12:00");
              }
              else if (s.EndsWith(" N", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" N") + 1)), "+01:00");
              }
              else if (s.EndsWith(" Y", StringComparison.OrdinalIgnoreCase))
              {
                  zoneRepresentedAsLocalDifferential  = String.Concat(s.Substring(0, (s.LastIndexOf(" Y") + 1)), "+12:00");
              }
              else
              {
                  zoneRepresentedAsLocalDifferential  = s;
              }
      
              return zoneRepresentedAsLocalDifferential;
          }
          #endregion
      
          #region ToString(DateTime utcDateTime)
          /// <summary>
          /// Converts the value of the specified <see cref="DateTime"/> object to its equivalent string representation.
          /// </summary>
          /// <param name="utcDateTime">The Coordinated Universal Time (UTC) <see cref="DateTime"/> to convert.</param>
          /// <returns>A RFC 822 string representation of the value of the <paramref name="utcDateTime"/>.</returns>
          /// <exception cref="ArgumentException">The specified <paramref name="utcDateTime"/> object does not represent a <see cref="DateTimeKind.Utc">Coordinated Universal Time (UTC)</see> value.</exception>
          public static string ToString(DateTime utcDateTime)
          {
              if (utcDateTime.Kind != DateTimeKind.Utc)
              {
                  throw new ArgumentException("utcDateTime");
              }
      
              return utcDateTime.ToString(Rfc822DateTime.Rfc822DateTimeFormat, DateTimeFormatInfo.InvariantInfo);
          }
          #endregion
      
          #region TryParse(string s, out DateTime result)
          /// <summary>
          /// Converts the specified string representation of a date and time to its <see cref="DateTime"/> equivalent.
          /// </summary>
          /// <param name="s">A string containing a date and time to convert.</param>
          /// <param name="result">
          /// When this method returns, contains the <see cref="DateTime"/> value equivalent to the date and time 
          /// contained in <paramref name="s"/>, expressed as <i>Coordinated Universal Time (UTC)</i>, 
          /// if the conversion succeeded, or <see cref="DateTime.MinValue">MinValue</see> if the conversion failed. 
          /// The conversion fails if the s parameter is a <b>null</b> reference (Nothing in Visual Basic), 
          /// or does not contain a valid string representation of a date and time. 
          /// This parameter is passed uninitialized.
          /// </param>
          /// <returns><b>true</b> if the <paramref name="s"/> parameter was converted successfully; otherwise, <b>false</b>.</returns>
          /// <remarks>
          /// The string <paramref name="s"/> is parsed using formatting information in the <see cref="DateTimeFormatInfo.InvariantInfo"/> object. 
          /// </remarks>
          public static bool TryParse(string s, out DateTime result)
          {
              //------------------------------------------------------------
              //  Attempt to convert string representation
              //------------------------------------------------------------
              bool wasConverted   = false;
              result              = DateTime.MinValue;
      
              if (!String.IsNullOrEmpty(s))
              {
                  DateTime parseResult;
                  if (DateTime.TryParseExact(Rfc822DateTime.ConvertZoneToLocalDifferential(s), Rfc822DateTime.Rfc822DateTimePatterns, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal, out parseResult))
                  {
                      result          = DateTime.SpecifyKind(parseResult, DateTimeKind.Utc);
                      wasConverted    = true;
                  }
              }
      
              return wasConverted;
          }
          #endregion
      }
      

      【讨论】:

      • 这段代码中Guard类型的使用让我想起了Argotic Syndication Framework中的解决方案。这是来自 Argotic 的 beta 代码吗?他们在最新版本的 Argotic 中对这个问题的解决方案是我见过的最好的。
      • 这不是 Argotic 的 beta 代码,我相信最新的 Argotic 可能比这里列出的有更好的实现。
      • Error 4 The name 'Guard' does not exist in current -1 for not submit working code
      • 您似乎只处理单个字母后缀 A、M、N、Y 和 Z。规范说除了 J 之外的所有字母都是允许的,AM(不包括 J)代表范围 -1 到 -12 小时,范围 N 到 Y 表示 +1 到 +12 小时。
      • RFC 822 dates 中,日期的名称和时间的秒数是可选的。此代码示例未处理此问题。
      【解决方案4】:

      这是我使用扩展方法的实现:

      namespace MyNamespace
      {
          public static partial class ExtensionMethods
          {
              public static string ToRFC822String(this DateTime timestamp)
              {
                  return timestamp.ToString("ddd',' d MMM yyyy HH':'mm':'ss")
                      + " "
                      + timestamp.ToString("zzzz").Replace(":", "");
              }
          }
       }
      

      使用方法:

       using MyNamespace;
      
       ....
      
       string MyRFC822String = DateTime.Now.ToRFC822String();
      

      【讨论】:

        【解决方案5】:

        这是微软在 Rss20FeedFormatter 中的做法。反对派的代码没有去掉 GMT 偏移部分中的“:”。杰夫伍德曼似乎做到了这一点。下面的代码也是这样做的(如果不使用 Atom10FeedFormatter.zeroOffset)。

        private string AsString(DateTimeOffset dateTime)
        {
            if (dateTime.Offset == Atom10FeedFormatter.zeroOffset)
            {
                return dateTime.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss Z", CultureInfo.InvariantCulture);
            }
            StringBuilder builder = new StringBuilder(dateTime.T)oString("ddd, dd MMM yyyy HH:mm:ss zzz", CultureInfo.InvariantCulture));
            builder.Remove(builder.Length - 3, 1);
            return builder.ToString();
        }
        

        【讨论】:

        • 无法解析Atom10FeedFormatter。在 VS2015 下如何解决这个问题?
        • 已经 7 年了,所以也许这行不通,但是如果您还没有尝试以下操作。包括 System.ServiceModel.dll 作为程序集引用,并为 System.ServiceModel.Syndication 添加 using 语句。另见:msdn.microsoft.com/en-us/library/…
        【解决方案6】:

        试试这个:

          DateTime today = DateTime.Now;
          String rfc822 = today.ToString("r");
          Console.WriteLine("RFC-822 date: {0}", rfc822);
        
          DateTime parsedRFC822 = DateTime.Parse(rfc822);
          Console.WriteLine("Date: {0}", parsedRFC822);
        

        传递给 DateTime 的 ToString() 方法的“r”格式说明符实际上产生了一个 RFC-1123 格式的日期时间字符串,但也作为 RFC-822 日期传递,基于阅读在 http://www.w3.org/Protocols/rfc822/#z28 找到的规范。我在创建 RSS 提要时使用了这种方法,它们通过了基于 http://validator.w3.org/feed/check.cgi 上可用的验证器的验证。

        缺点是,在转换中,它将日期时间转换为 GMT。要转换回本地时间,您需要应用本地时区偏移量。为此,您可以使用 TimeZone 类来获取您当前的时区偏移量,并将“GMT”替换为时区偏移量字符串:

        TimeZone tz = TimeZone.CurrentTimeZone;
        
        String offset = tz.GetUtcOffset().ToString();
        // My locale is Mountain time; offset is set to "-07:00:00"
        // if local time is behind utc time, offset should start with "-".
        // otherwise, add a plus sign to the beginning of the string.
        if (!offset.StartsWith("-"))
          offset = "+" + offset; // Add a (+) if it's a UTC+ timezone
        offset = offset.Substring(0,6); // only want the first 6 chars.
        offset = offset.Replace(":", ""); // remove colons.
        // offset now looks something like "-0700".
        rfc822 = rfc822.Replace("GMT", offset);
        // The rfc822 string can now be parsed back to a DateTime object,
        // with the local time accounted for.
        DateTime new = DateTime.Parse(rfc822);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-23
          • 1970-01-01
          • 2013-06-15
          • 2011-04-22
          • 2010-10-27
          • 2013-06-13
          相关资源
          最近更新 更多