解析非标准的日期格式与DateTime.TryParseExact非标准、日期、格式、TryParseExact

2023-09-04 11:41:39 作者:沾满血的手

林喜试图解析日期字符串,如1012012,第一届2012年1月。

读了API它说,用D,%d其中的日期不具有领先的0不能让它工作的日期,如1012012

试图用D MMM YYYY2012 1月1日,我该怎么用这么'圣','日'的作品?

 使用系统;
使用System.IO;
使用System.Globalization;

命名空间测试
{
  类脚本
  {
    静态公共无效的主要(字串[] args)
    {

        //字符串dateString =9022011; // Q1
        字符串dateString =2011年2月9日; // Q2
        System.DateTime的日期= DateTime.MinValue;
        字符串[]格式= {DDMMYYYY,D MMM YYYY}; //什么是正确的格式字符串?

        如果(DateTime.TryParseExact(dateString,格式,新的CultureInfo(EN-AU),DateTimeStyles.None,过时))
                        {
            Console.Out.WriteLine(与Date.toString());
        }
                        其他
                        {
            Console.Out.WriteLine(倾斜转换);
        }
     }
  }

}
 

解决方案

我不认为这是可以做到。解析器处理左到右您的输入,因此,如果看到1012012,它会认为这一天是10,然后失败解析因为没有留下足够的字符,即使格式化字符串为dMMyyyy。这将需要某种形式回溯到认为这一天是1的可能性,但它似乎并没有做到这一点很遗憾。

然而相当简单使用自定义的正则表达式来解析这种格式。正则表达式解析器不使用回溯,以便正常考虑两个选项:

 字符串输入=1012012;
匹配米= Regex.Match(输入,@^(小于?天> \ D {1,2})(小于?月> \ D {2})(小于?年> \ D {4}) $);
如果(m.Success)
{
    日期时间D =新的日期时间(Convert.ToInt32(m.Groups [年。值),
                              Convert.ToInt32(m.Groups [月。值),
                              Convert.ToInt32(m.Groups [日]值。));
}
 

另一种选择是简单的增加一个前导零如果字符串的长度为七:

 字符串输入=1012012;
如果(input.Length == 7)
    输入=0+输入;
日期时间D = DateTime.ParseExact(输入,DDMMYYYY,CultureInfo.CurrentCulture);
 
EXLE怎么把非标准时间格式改成标准时间格式

而不是试图做多的查找和替换在其他的答案,你可以使用一个事实,即该字符串的准确格式是已知的。它开始与一个或两个数字,随后通过两个字母,接着月份和年份。所以,你可以提取日期是这样的:

 字符串输入=2012 1月1日;
INT指数= char.IsNumber(输入,1)? 2:1;
输入= input.Substring(0,指数)+ input.Substring(指数+ 2);
日期时间D = DateTime.ParseExact(输入D MMMM YYYY,CultureInfo.InvariantCulture);
 

当然,这将接受的日期有纯属扯淡这些职位,如2012 1XX月,但我不知道这是你的情况的问题。

另外,一定要通过适当的的CultureInfo 如果输入可以容纳非英语月份名称。

如果你能得到这两种格式不知道提前其中你要,你需要一个简单的检查,看看事先使用的方法。在第一格式的字符串将始终7或8个字符,并且在第二格式字符串总是会更长,所以这应该是容易测试。另一种方法是,检查如果字符串包含任何非数字字符(在这种情况下,它的长格式)。

Hi Im trying to parse date strings like "1012012", "1st January 2012".

read the Api It says to use d,%d where the date does not have a leading 0. Cant get it working for dates like "1012012"

trying to use "d MMM YYYY" for "1st January 2012", what do I use so 'st', 'th' works?

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");
        }
     }
  }

}

解决方案

I don't think this can be done. The parser processes your input left-to-right, so if it sees "1012012" it will think the day is 10, and then fail the parse because there's not enough characters left, even if the format string is "dMMyyyy". It would need some kind of backtracking to consider the possibility that the day is 1, but it doesn't seem to do that unfortunately.

It is however fairly simple to use a custom regex to parse this format. The regex parser does use backtracking so it will correctly consider both options:

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));
}

Another option would be to simple add a leading zero if the length of the string is seven:

string input = "1012012";
if( input.Length == 7 )
    input = "0" + input;
DateTime d = DateTime.ParseExact(input, "ddMMyyyy", CultureInfo.CurrentCulture);

Rather than attempting to do multiple find and replaces as in the other answers, you can use the fact that the exact format of the string is known. It starts with one or two digits, followed by two letters, followed by the month and the year. So you could extract the date like this:

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);

Of course, this will accept dates that have pure nonsense in those positions, like "1xx January 2012", but I'm not sure if that's a problem in your case.

Also be sure to pass the appropriate CultureInfo if the input can hold non-English month names.

If you can get either format without knowing in advance which you're getting, you'll need a simple check to see which method to use beforehand. Strings in the first format will always be 7 or 8 characters, and strings in the second format will always be longer, so this should be easy to test. Another method would be to check if the string contains any non-numeric characters (in which case it's the long format).