我正在尝试解析RFC1123格式的日期(例如:Thu, 21 Jan 2010 17:47:00 EST)。
以下是我尝试的方法,但都没有成功:
DateTime Date = DateTime.Parse(dt);
DateTime Date = DateTime.ParseExact(dt, "r", null);
你尝试过类似这样的代码吗:
string dateString, format;
DateTime result;
CultureInfo provider = CultureInfo.InvariantCulture;
dateString = "Thu, 21 Jan 2010 17:47:00 EST";
format = "ddd, dd MMM yyyy hh:mm:ss EST";
result = DateTime.ParseExact(dateString, format, provider);
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString());
我还没有测试过(稍后会测试)...但我认为这会解决你的问题。
编辑:看起来问题在于RFC1123规定时区应该始终为GMT...这就是为什么r或R无法按照你的格式工作的原因。问题就在于EST。上面的模式考虑到了EST,但它是静态的,如果你有其他时区可能会遇到麻烦。最好的解决方案是遵循RFC1123标准并转换为GMT,这应该可以解决你的问题。如果你不能,请告诉我,我可能有一个解决方案。
编辑2:这不是一个完整的解决方案,但它可以将时区隔离出来,并允许你解析它。代码不知道呈现给它的时区,但你可以将任何时区缩写投入其中,它都能解析时间。如果你想转换为GMT然后使用r或R,你可以将正则表达式匹配的结果放入查找表中(以查看该时区缩写的时间偏移量),然后将时间转换为GMT并从那里解析。这将是一个好的解决方案,但需要更多的工作。这是代码:
string dateString, format, pattern, tz;
DateTime result;
CultureInfo provider = CultureInfo.InvariantCulture;
pattern = @"[a-zA-Z]+, [0-9]+ [a-zA-Z]+ [0-9]+ [0-9]+:[0-9]+:[0-9]+ (?<timezone>[a-zA-Z]+)";
dateString = "Thu, 21 Jan 2010 17:47:00 EST";
Regex findTz = new Regex(pattern, RegexOptions.Compiled);
tz = findTz.Match(dateString).Result("${timezone}");
format = "ddd, dd MMM yyyy HH:mm:ss " + tz;
try
{
result = DateTime.ParseExact(dateString, format, provider);
Console.WriteLine("Timezone format is: {0}", format);
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString());
}
catch (FormatException)
{
Console.WriteLine("{0} is not in the correct format.", dateString);
}
Console.ReadLine();
如果您想将此转换为时区转换器,请参考以下UTC偏移量列表:
我看到这个问题时正在寻找同样的解决方案。令人难以置信的是,在12年中没有运行时的解决方案。
这是我的解决方案:
/// <summary>
/// Regex expression matching date as "Thu, 15 Feb 2018 00:36:36.405 +0000 (UTC)"
/// </summary>
private static readonly Regex reMimeDateTzshift = new Regex(@"(?<dow>[A-Za-z]{3}),?\s+(?<day>\d{1,2})\s(?<month3>[A-Za-z]{3})\s(?<year>\d{4})\s(?<hour>\d+):(?<minutes>\d+):(?<seconds>\d+)(?<milliseconds>\.\d+)?\s(?<tzshift>[+\-]\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// Regex expression matching date as "Wed, 24 Oct 2012 16:37:27 GMT"
/// </summary>
private static readonly Regex reMimeDateTimezone = new Regex(@"(?<dow>[A-Za-z]{3}),?\s+(?<day>\d{1,2})\s(?<month3>[A-Za-z]{3})\s(?<year>\d{4})\s(?<hour>\d+):(?<minutes>\d+):(?<seconds>\d+)(?<milliseconds>\.\d+)?\s(?<timezone>[A-Z]{3,4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// Regex expression matching date as "Fri Aug 18 00:42 PDT 2006"
/// </summary>
private static readonly Regex reMimeDateAmerican = new Regex(@"(?<dow>[A-Za-z]{3}),?\s+(?<month3>[A-Za-z]{3})\s(?<day>\d{1,2})\s(?<hour>\d+):(?<minutes>\d+)\s(?<timezone>[A-Z]{3,4})\s(?<year>\d{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Dictionary<string, string> timezones = new Dictionary<string, string>(StringComparer.Ordinal) {
// https://www.rfc-editor.org/rfc/rfc822
// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
{ "NZDT", "+1300" },
{ "NZST", "+1200" },
{ "AEDT", "+1100" },
{ "ACDT", "+1030" },
{ "AEST", "+1000" }, { "ChST", "+1000" },
{ "ACST", "+0930" },
{ "WIT", "+0900" }, { "KST", "+0900" }, { "JST", "+0900" },
{ "HKT", "+0800" }, { "WITA", "+0800" }, { "AWST", "+0800" },
{ "WIB", "+0700" },
{ "PKT", "+0500" },
{ "EAT", "+0300" }, { "IDT", "+0300" }, { "MSK", "+0300" }, { "EEST", "+0300" },
{ "CAT", "+0200" }, { "EET", "+0200" }, { "IST", "+0200" }, { "CEST", "+0200" }, { "MEST", "+0200" }, { "SAST", "+0200"},
{ "WAT", "+0100" }, { "CET", "+0100" }, { "MET", "+0100" }, { "WEST", "+0100" },
{ "UT" , "+0000" }, { "UTC", "+0000" }, { "GMT", "+0000" }, { "WET", "+0000" },
{ "EDT", "-0400" }, { "AST", "-0400" },
{ "EST", "-0500" }, { "CDT", "-0500" },
{ "CST", "-0600" }, { "MDT", "-0600" },
{ "MST", "-0700" }, { "PDT", "-0700" },
{ "PST", "-0800" }, { "AKDT", "-0800" },
{ "HDT", "-0900" }, { "AKST", "-0900" },
{ "HST", "-1000" },
{ "SST", "-1100" },
// Note: rfc822 got the signs backwards for the military
// timezones so some sending clients may mistakenly use the
// wrong values.
{ "A", "+0100" }, { "B", "+0200" }, { "C", "+0300" },
{ "D", "+0400" }, { "E", "+0500" }, { "F", "+0600" },
{ "G", "+0700" }, { "H", "+0800" }, { "I", "+0900" },
{ "K", "+1000" }, { "L", "+1100" }, { "M", "+1200" },
{ "N", "-0100" }, { "O", "-0200" }, { "P", "-0300" },
{ "Q", "-0400" }, { "R", "-0500" }, { "S", "-0600" },
{ "T", "-0700" }, { "U", "-0800" }, { "V", "-0900" },
{ "W", "-1000" }, { "X", "-1100" }, { "Y", "-1200" },
{ "Z", "+0000" }
};
/// <summary>
/// Tries to convert String to date
/// If there is a run time error, the smallest possible date is returned<br/>
/// Examples: <br/>
/// <example>Wed, 04 Jan 2006 07:58:08 -0800</example><br/>
/// <example>Wed, 04 Jan 2006 07:58:08 -0800 (PST)</example><br/>
/// <example>"Wed, 24 Oct 2012 16:37:27 GMT (envelope-from dboutet@businessv.com)"</example><br/>
/// <example>"Thu, 15 Feb 2018 00:36:36.405 +0000 (UTC)"</example><br/>
/// <example>"Fri Aug 18 00:42 PDT 2006"</example>
/// </summary>
static public DateTime ConvertToDateTime(string date) {
DateTime ReturnDateTime;
String cleanDateTime;
Match match;
String tzShift;
// Optimistic: Try directly
// Valid for "dd MMM yyyy hh:mm:ss zzzz" and "ddd, dd MMM yyyy hh:mm:ss zzzz formats"
if (DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces, out ReturnDateTime)) {
return ReturnDateTime;
}
// Try: Wed, 04 Jan 2006 07:58:08 -0800
match = reMimeDateTzshift.Match(date);
if (match != Match.Empty) {
cleanDateTime = $"{match.Groups["dow"].Value}, {match.Groups["day"].Value} {match.Groups["month3"].Value} {match.Groups["year"].Value} {match.Groups["hour"].Value}:{match.Groups["minutes"].Value}:{match.Groups["seconds"].Value} {match.Groups["tzshift"].Value}";
if (DateTime.TryParse(cleanDateTime, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces, out ReturnDateTime)) {
return ReturnDateTime;
}
}
// Try: "Wed, 04 Jan 2006 07:58:08 GMT".
match = reMimeDateTimezone.Match(date);
if (match != Match.Empty) {
tzShift = timezones.GetValueOrDefault(match.Groups["timezone"].Value, "+0000");
cleanDateTime = $"{match.Groups["dow"].Value}, {match.Groups["day"].Value} {match.Groups["month3"].Value} {match.Groups["year"].Value} {match.Groups["hour"].Value}:{match.Groups["minutes"].Value}:{match.Groups["seconds"].Value} {tzShift}";
if (DateTime.TryParse(cleanDateTime, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces, out ReturnDateTime)) {
return ReturnDateTime;
}
}
// Try: "Fri Aug 18 00:42 PDT 2006".
match = reMimeDateAmerican.Match(date);
if (match != Match.Empty) {
tzShift = timezones.GetValueOrDefault(match.Groups["timezone"].Value, "+0000");
cleanDateTime = $"{match.Groups["dow"].Value}, {match.Groups["day"].Value} {match.Groups["month3"].Value} {match.Groups["year"].Value} {match.Groups["hour"].Value}:{match.Groups["minutes"].Value}:00 {tzShift}";
if (DateTime.TryParse(cleanDateTime, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces, out ReturnDateTime)) {
return ReturnDateTime;
}
}
_loggerError(_logger, $"Date format not recognised: '{date}'", null);
return DateTime.MinValue;
}