.net - parse - ¿Cómo analizo y convierto DateTime al formato de fecha y hora RFC 822?
datetime.parse format dd/mm/yyyy (6)
¿Cómo convierto una estructura de DateTime a su representación de cadena formateada de fecha RFC 822 equivalente y analizo esta representación de cadena de nuevo a una estructura DateTime en .NET? El formato de fecha y hora RFC-822 se utiliza en varias especificaciones, como el formato de distribución de RSS .
Prueba esto:
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);
El especificador de formato "r" pasado al método ToString () de DateTime realmente produce una cadena de fecha y hora formateada en RFC-1123, pero también pasa como una fecha RFC-822, basada en la lectura de la especificación encontrada en http: //www.w3. org / Protocols / rfc822 / # z28 . Utilicé este método para crear feeds RSS y aprobaron la validación basada en el validador disponible en http://validator.w3.org/feed/check.cgi .
La desventaja es que, en la conversión, convierte la fecha y hora a GMT. Para convertir de nuevo a la hora local, necesitaría aplicar su desplazamiento de zona horaria local. Para eso, puede usar la clase TimeZone para obtener su compensación de zona horaria actual, y reemplazar "GMT" con una cadena de compensación de zona horaria:
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);
Así es como Microsoft lo hace en Rss20FeedFormatter. El código de oposición no elimina el ":" en la porción de compensación GMT. Jeff Woodman parece hacer esto. El código siguiente también lo hace (si no usa 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();
}
Aquí está mi implementación usando un método de extensión:
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(":", "");
}
}
}
Usar:
using MyNamespace;
....
string MyRFC822String = DateTime.Now.ToRFC822String();
Esta es una implementación en C # de cómo analizar y convertir un DateTime desde y hacia su representación RFC-822. La única restricción que tiene es que DateTime está en hora universal coordinada (UTC). Estoy de acuerdo en que este código no es muy elegante, pero cumple su función.
/// <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
}
Siguiendo la idea de Kirk, descompilé fuentes para la clase System.ServiceModel.Syndication.Rss20FeedFormatter
( System.ServiceModel.dll ) y aquí está el analizador interno de Microsoft para el formato de fechas RFC 822 (simplifiqué un poco su lógica de manejo de excepciones para reducir las dependencias):
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");
}
}
Lo primero que puede parecer inusual es que devuelven la clase [DateTimeOffset][1]
lugar de DateTime
. Pero cuando leemos más sobre esto, parece ser completamente lógico: DateTimeOffset
almacena información de fecha, hora y zona horaria (exactamente como la cadena en formato RFC 822). Si devolviera el objeto DateTime, en qué zona horaria estaría : UTC, local o el especificado en la cadena analizada, cualquier respuesta sería incorrecta en algunos casos. Entonces DateTimeOffset
resuelve un importante problema de incertidumbre. Y puede convertirlo a la zona horaria que necesite más adelante utilizando los métodos DateTimeOffset.ToUniversalTime()
, DateTimeOffset.ToLocalTime()
.
Lo probé en algunos casos y parece que hace el trabajo a la perfección.
Sin embargo, no estoy seguro de por qué Microsoft decidió hacer esta implementación privada; no parece necesitar mucho apoyo.
Basado en la respuesta de Kirk Liemohn, utilicé este método con éxito:
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;
}
Ejemplo:
DateTimeOffset? date = ParseDate("Thu, 5 Apr 2012 23:47:37 +0200");
Console.WriteLine(date.ToString());
// => 05/04/2012 23:47:37 +02:00
No respeta la especificación completa de RFC, pero funciona para mis casos de uso.
Específicamente, no funciona con timezone express como: "GMT", "CST", etc. (ver "zona" en RFC822 Sección 5.1 ). Vea la mejor respuesta de Oleksandr Pshenychnyy .