如何在c#中手动解析带有可选字段的自定义日期时间格式?

本文关键字:字段 自定义 日期 格式 时间 | 更新日期: 2023-09-27 18:13:55

假设我有以下日期/时间,格式近似于内部iso:

  • "2011-11-07T11:17"
  • "--T11:17" (11:17 am, no date, only time)
  • "-11-07"(11月7日,无年无时)

分隔符是强制性的,使我能够知道数据是否存在。数据将被设置为如下结构:

struct MyDate
{
    int? Year ;
    int? Month ;
    int? Day ;
    int? Hour ;
    int? Minute ;
}

"最简单"的方法是一个字符一个字符地循环,如果存在则提取数据。

但是我有一个唠叨的印象,必须有某种API来提取,例如,一个整数,并返回第一个非整数字符的索引(类似于C的strtol)。

在c#中是否有strtol之类的函数,或者更高级的函数来提取类型数据,而不是逐个字符解析字符串?

如何在c#中手动解析带有可选字段的自定义日期时间格式?

您可以使用DateTime.ParseExact。查看这里的文档

我会这样做:

EDIT 2

现在包括:

  • MyDate结构中静态ParseTryParse方法:)
  • 一个镜像ToString(),便于测试
  • 最小单元测试用例
  • 附加演示:从字符串到MyDate的隐式转换操作符(因此您可以在需要MyDate的地方传递字符串)

http://ideone.com/rukw4

using System;
using System.Text;
using System.Text.RegularExpressions;
struct MyDate 
{ 
    public int? Year, Month, Day, Hour, Minute; 
    private static readonly Regex dtRegex = new Regex(
        @"^(?<year>'d{4})?-(?<month>'d'd)?-(?<day>'d'd)?"
    +   @"(?:T(?<hour>'d'd)?:(?<minute>'d'd)?)?$",
        RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
    public static bool TryParse(string input, out MyDate result)
    {
        Match match = dtRegex.Match(input);
        result = default(MyDate);
        if (match.Success)
        {
            if (match.Groups["year"].Success)
                result.Year = Int32.Parse(match.Groups["year"].Value);
            if (match.Groups["month"].Success)
                result.Month = Int32.Parse(match.Groups["month"].Value);
            if (match.Groups["day"].Success)
                result.Day = Int32.Parse(match.Groups["day"].Value);
            if (match.Groups["hour"].Success)
                result.Hour = Int32.Parse(match.Groups["hour"].Value);
            if (match.Groups["minute"].Success)
                result.Minute = Int32.Parse(match.Groups["minute"].Value);
        }
        return match.Success;
    }
    public static MyDate Parse(string input)
    {
        MyDate result;
        if (!TryParse(input, out result))
            throw new ArgumentException(string.Format("Unable to parse MyDate: '{0}'", input));
        return result;
    }
    public override string ToString()
    {
        return string.Format("{0:0000}-{1:00}-{2:00}T{3:00}:{4:00}", Year, Month, Day, Hour, Minute);
    }
    public static implicit operator MyDate(string input)
    {
        return Parse(input);
    }
}
class Program
{
    static void Main(string[] args)
    {
        foreach (var testcase in new [] { 
                "2011-11-07T11:17",
                "-11-07T11:17",
                "2011--07T11:17",
                "2011-11-T11:17",
                "2011-11-07T:17",
                "2011-11-07T11:",
                // extra:
                "--T11:17", // (11:17 am, no date, only time)
                "-11-07", // (november the 7th, no year, no time)
                // failures:
                "2011/11/07 T 11:17",
                "no match" })
        {
            MyDate parsed;
            if (MyDate.TryParse(testcase, out parsed))
                Console.WriteLine("'{0}' -> Parsed into '{1}'", testcase, parsed);
            else
                Console.WriteLine("'{0}' -> Parse failure", testcase);
        }
    }
}
输出:

'2011-11-07T11:17' -> Parsed into '2011-11-07T11:17'
'-11-07T11:17' -> Parsed into '-11-07T11:17'
'2011--07T11:17' -> Parsed into '2011--07T11:17'
'2011-11-T11:17' -> Parsed into '2011-11-T11:17'
'2011-11-07T:17' -> Parsed into '2011-11-07T:17'
'2011-11-07T11:' -> Parsed into '2011-11-07T11:'
'--T11:17' -> Parsed into '--T11:17'
'-11-07' -> Parsed into '-11-07T:'
'2011/11/07 T 11:17' -> Parse failure
'no match' -> Parse failure

如果性能不是一个问题,我会为你的任务使用正则表达式。

使用('d*)-('d*)-('d*)T('d*):('d*)作为表达式,然后将每个捕获组解析为结构的相应字段,将空字符串转换为null值:

var match = Regex.Match(str, @"('d*)-('d*)-('d*)T('d*):('d*)");
var date = new MyDate();
if (match.Groups[1].Value != "") date.Year = int.Parse(match.Groups[1].Value);
if (match.Groups[2].Value != "") date.Month = int.Parse(match.Groups[2].Value);
if (match.Groups[3].Value != "") date.Day = int.Parse(match.Groups[3].Value);
if (match.Groups[4].Value != "") date.Hour = int.Parse(match.Groups[4].Value);
if (match.Groups[5].Value != "") date.Minute = int.Parse(match.Groups[5].Value);

EDIT: 'T'和':'分隔符在此代码中是强制性的。如果你想要其他答案,请参考@sehe的答案

如果你知道日期格式,你可以使用DateTime.ParseExact为例…如果你需要类似于strtol,你可以使用Convert.ToInt32