在C#,.Net 4.0中解析RFC1123格式的日期

12

我正在尝试解析RFC1123格式的日期(例如:Thu, 21 Jan 2010 17:47:00 EST)。

以下是我尝试的方法,但都没有成功:

DateTime Date = DateTime.Parse(dt);
DateTime Date = DateTime.ParseExact(dt, "r", null);
2个回答

12

你尝试过类似这样的代码吗:

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偏移量列表:

带有UTC偏移量的时区缩写


这很有道理。但问题在于,我无法控制日期格式,因为它来自外部来源。有没有办法将非GMT时区转换为基于GMT的时区,然后应用“r”或“R”? - Moon
我希望我能给你一个更好的答案,但是……缩写无法识别。我有一个解决方案,但它并不好玩或优雅。我会发布它,并祈祷有人比我更能帮助你!非常抱歉。 - Tim C
它不是完美的,但好多了! :) 我感激你的帮助,真的! :) - Moon
你可以使用TryParseExact()代替带有ParseExact()的try-catch。 - IgorK

0

我看到这个问题时正在寻找同样的解决方案。令人难以置信的是,在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;

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接