在C#中是否可以检查给定的日期格式字符串是否仅包含日期格式或时间格式?

时间:2019-09-25 10:18:58

标签: c# datetime

例如。我有一些混合的日期和时间格式字符串。

"date1": "dd/MM/yyyy",
"date2": "yyyy MM yyyy",
"date3": "h:mmtt",
"date4": "h:mmtt"

我需要检查每种格式都是时间格式还是日期格式。我知道我可以对字符串进行一些向导检查,如果它包含'yyyy'等,但是这感觉很错误并且容易出错。有什么方法可以检查给定的DateTime格式是否仅导致显示时间或仅导致日期?

请明确说明,我不愿意根据格式验证给定日期,也不是给定日期实际上是日期,我只想确定字符串DateTime格式是否仅导致时间部分显示或仅显示日期部分(如果已将其应用于任何DateTime值)。

非常感谢

Stewart

3 个答案:

答案 0 :(得分:4)

我会遵循以下原则:

[Flags]
public enum DateFormatStringKind
{
    HasNone = 0,
    HasDate = 1 << 0,
    HasTime = 1 << 1,
    HasBoth = HasDate | HasTime
}

public static DateFormatStringKind DescribeFormatString(string s, IFormatProvider provider)
{
    DateTime d = new DateTime(2, 2, 2, 1, 1, 1, 1); // DateTime will all non-default values
    DateTime d2 = DateTime.ParseExact(d.ToString(s, provider), s, provider, System.Globalization.DateTimeStyles.NoCurrentDateDefault);

    DateFormatStringKind result = DateFormatStringKind.HasNone;

    if (d2.Date.Ticks != 0)
        result |= DateFormatStringKind.HasDate;

    if (d2.TimeOfDay != TimeSpan.Zero)
        result |= DateFormatStringKind.HasTime;

    return result;
}
var culture = System.Globalization.CultureInfo.InvariantCulture;

Console.WriteLine(DescribeFormatString("dd/MM/yyyy", culture));
Console.WriteLine(DescribeFormatString("yyyy MM yyyy", culture));
Console.WriteLine(DescribeFormatString("h:mmtt", culture));
Console.WriteLine(DescribeFormatString("dd h:mmtt", culture));
Console.WriteLine(DescribeFormatString("'literal'", culture));
HasDate
HasDate
HasTime
HasBoth
HasNone

它将具有所有非默认字段的日期转换为使用格式字符串的字符串,然后使用相同的格式字符串返回,然后检查哪些字段在转换后仍然存在。

如果该模式中没有日期组成部分,则“日期”部分将为0001-01-01,即零日期(从点0开始的零滴答声)。 NoCurrentDateDefault标志可确保不使用当前日期。

如果模式中没有时间成分,则时间将重置为午夜(从午夜TimeSpan.Zero开始)。

如果日期模式中至少有一个组成部分(年,月或日),则相应的字段将变为2,大于日期字段的默认1,因此无论它是什么组件,都将被检测到。

如果时间模式中至少有一个组成部分(小时,分钟,秒,毫秒),它将变为1,大于时间字段的默认0,因此无论它是什么组件,都将再次检测到它。

答案 1 :(得分:0)

我对此没有了解。

您可以使用两种方法,您已经提到了这两种方法。

第一个方法是针对任意测试日期时间进行解析。 GSerg的答案已经涵盖了这一点,但简单来说,您实际上是创建一个虚拟日期,然后将其解析为字符串,然后使用格式字符串将其返回。显然,您的考试时间应该不是00:00的时间,否则您仍然无法分辨;

,并且该日期还应为“今天”或“ 0001年1月1日”以外的日期(请参见Documentation)。

第二个选项是检查完整的日期时间格式字符串变量集(请参阅Documentation)-因此,类似这样(尽管在.NET Framework的将来实现中可能会发生变化):

与日期相关的项目如下:

  

“ d”“ dd”“ ddd”“ dddd”“ g”“ gg”“ M”“ MM”“ MMM”“ MMMM”“ y”“ yy”“ yyy”   “ yyyy”“ yyyyy”“ /”

与时间有关的项目如下:

  

“ f”“ ff”“ fff”“ ffff”“ fffff”“ ffffff”“ fffffff”“ F”“ FF”“ FFF”“ FFFF”   “ FFFFF”“ FFFFFF”“ FFFFFFF”“ h”“ hh”“ H”“ HH”“ s”“ ss”“ t”“ tt”“ m”   “ mm”“:”

以下内容含糊不清,可能是其中之一-因此我们将忽略这些内容:

  

“ K”“ z”“ zz”“ zzz”

这为我们提供了以下伪代码:

If date1 contains any of (d,g,M,y,/) then date = true
If date1 contains any of (f,F,h,H,s,t,m,:) then time = true
If date && time then date-time

请注意,这没有考虑转义(\)字符或包含上述字符之一的字符串文字('...')的可能性。要解决此问题,您可以先从格式字符串中删除反斜杠之后或单引号之间的所有字符-但此时最好使用regex。

答案 2 :(得分:0)

有864,000,000,000 ticks in a day。您可以检查DateTime.Ticks属性以查看是否可以被该数字整除。如果Ticksticks in a day为0,则没有时间部分。同样,如果Ticks / ticks in a day为0,则没有日部分。使用Math.DivRem一次执行除法和模运算。

这是一个帮助班。

    public class DateInfo
    {
        private const long ticksPerDay = 864000000000;
        public bool HasDate { get; private set; }
        public bool HasTime { get; private set; }
        public DateInfo(DateTime date)
        {
            long timeTicks = 0;
            var dayticks = Math.DivRem(date.Ticks, ticksPerDay, out timeTicks);
            HasDate = dayticks > 0;
            HasTime = timeTicks > 0;
        }
        public override string ToString()
        {
            return $"{{{nameof(HasDate)}:{HasDate}, {nameof(HasTime)}:{HasTime}}}";
        }
        private static readonly DateTime testDate = DateTime.Parse("2/2/2 1:11");
        public static DateInfo GetDateInfo(string format)
        {
            var formatted = testDate.ToString(format);
            var dt = DateTime.ParseExact(formatted, format, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
            return new DateInfo(dt);
        }
    }

测试:

        var MinDate = DateTime.MinValue;
        var OneHour = MinDate.AddHours(1);
        var OneDay = MinDate.AddDays(1);

        var tests = new Dictionary<string, DateTime>
        {
            { nameof(MinDate), DateTime.MinValue },
            { nameof(OneDay), OneDay },
            { nameof(OneHour), OneHour },
            { nameof(DateTime.Now), DateTime.Now },
            { nameof(DateTime.Today), DateTime.Today },
        };

        var infos = tests.Select(x =>
        {
            var dateInfo = new DateInfo(x.Value);
            return new { x.Key, dateInfo.HasDate, dateInfo.HasTime };
        });

        tests.ToList().ForEach(test =>
        {
            var dateInfo = new DateInfo(test.Value);
            System.Diagnostics.Debug.WriteLine($"{test.Key}: {dateInfo}");
        });
        var formatTests = new Dictionary<string, string>
        {
            { "date1", "dd/MM/yyyy" },
            { "date2", "yyyy MM dd" },
            { "date3", "h:mmtt" },
            { "date4", "hh:mmtt" }
        };
        formatTests.ToList().ForEach(test =>
        {
            var dateInfo = DateInfo.GetDateInfo(test.Value);
            System.Diagnostics.Debug.WriteLine($"{test.Key}: {dateInfo}");
        });

结果:

MinDate: {HasDate:False, HasTime:False}
OneDay: {HasDate:True, HasTime:False}
OneHour: {HasDate:False, HasTime:True}
Now: {HasDate:True, HasTime:True}
Today: {HasDate:True, HasTime:False}
date1: {HasDate:True, HasTime:False}
date2: {HasDate:True, HasTime:False}
date3: {HasDate:False, HasTime:True}
date4: {HasDate:False, HasTime:True}