使用DateTime.TryParseExact解析非标准日期格式

时间:2011-08-29 08:22:59

标签: c# .net parsing datetime-format

您好我正在尝试解析日期字符串,如“1012012”,“2012年1月1日”。

  1. 阅读Api它说使用d,%d,其中日期没有前导0.不能让它在“1012012”等日期工作

  2. 尝试使用“d MMM YYYY”作为“2012年1月1日”,我使用什么'st','th'有效?

    using System;
    using System.IO;
    using System.Globalization;
    
    namespace test
    {
      class Script
      {
        static public void Main(string [] args)
        {
    
            //String dateString = "9022011";  // q1
            String dateString = "9th February 2011";  //q2
            System.DateTime date = DateTime.MinValue;
            string[] format = { "ddMMyyyy", "d MMM yyyy" }; // what would be the correct format strings?
    
            if (DateTime.TryParseExact(dateString,format,new CultureInfo("en-AU"),DateTimeStyles.None,out date))
                            {
                Console.Out.WriteLine(date.ToString());
            } 
                            else
                            {
                Console.Out.WriteLine("cant convert");
            }
         }
      }
    
    }
    

3 个答案:

答案 0 :(得分:4)

  1. 我认为不能这样做。解析器从左到右处理您的输入,因此如果它看到“1012012”,它会认为该日是10,然后解析失败,因为没有足够的字符,即使格式字符串是“dMMyyyy”。需要某种回溯来考虑当天是1的可能性,但不幸的是它似乎没有这样做。

    然而,使用自定义正则表达式来解析此格式相当简单。正则表达式解析器确实使用回溯,因此它将正确地考虑两个选项:

    string input = "1012012";
    Match m = Regex.Match(input, @"^(?<day>\d{1,2})(?<month>\d{2})(?<year>\d{4})$");
    if( m.Success )
    {
        DateTime d = new DateTime(Convert.ToInt32(m.Groups["year"].Value),
                                  Convert.ToInt32(m.Groups["month"].Value),
                                  Convert.ToInt32(m.Groups["day"].Value));
    }
    

    如果字符串的长度为7,则另一个选项是简单地添加前导零:

    string input = "1012012";
    if( input.Length == 7 )
        input = "0" + input;
    DateTime d = DateTime.ParseExact(input, "ddMMyyyy", CultureInfo.CurrentCulture);
    
  2. 您可以使用已知字符串的确切格式这一事实,而不是像在其他答案中那样尝试进行多次查找和替换。它以一位或两位数字开头,后跟两个字母,后跟月份和年份。所以你可以像这样提取日期:

    string input = "1st January 2012";
    int index = char.IsNumber(input, 1) ? 2 : 1;
    input = input.Substring(0, index) + input.Substring(index + 2);
    DateTime d = DateTime.ParseExact(input, "d MMMM yyyy", CultureInfo.InvariantCulture);
    

    当然,这将接受在这些职位上纯粹胡说八道的日期,例如“1xx 2012年1月”,但我不确定你的情况是否有问题。

    如果输入可以包含非英文月份名称,也务必传递适当的CultureInfo

  3. 如果您可以在不事先知道要获得的格式的情况下获得任何一种格式,则需要进行简单的检查以确定事先使用哪种方法。第一种格式的字符串总是7或8个字符,第二种格式的字符串总是更长,所以这应该很容易测试。另一种方法是检查字符串是否包含任何非数字字符(在这种情况下,它是长格式)。

答案 1 :(得分:3)

var dateString = "1st February 2011";
DateTime date;
var replaced = dateString.Substring(0,4)
                         .Replace("nd","")
                         .Replace("th","")
                         .Replace("rd","")
                         .Replace("st","")
                         + dateString.Substring(4);

DateTime.TryParseExact(replaced, "d MMMM yyyy",
                       new CultureInfo("en-us"), DateTimeStyles.AssumeLocal, 
                       out date);

应该做的伎俩(对不起,'th'是讨厌的) - 你必须小心一点st(八月) - 只是从前几次出场中删除它:

答案 2 :(得分:2)

如果要解析特定于文化的日期字符串,则应使用匹配的文化。 CultureInfo.InvariantCulture不是一个好主意,因为它只适用于英文字符串 但是,您尝试做的事情不仅仅是格式说明符,因为当天没有可以解析“th”,“st”等字符串。您必须事先手动删除它们。