不允许模棱两可的日期

本文关键字:日期 模棱两可 不允许 | 更新日期: 2023-09-27 18:10:52

DateTime.Parse(myString, CultureInfo.InvariantCulture)很高兴解析以下明确的日期(假设有固定的本地时区):

2015-12-31T12:15:00
2015-12-31T12:15:00Z
2015-12-31T12:15:00+01:00
2015-12-31T12:15
2015-12-31
2015-12-31 12:15:00
2015-12-31 12:15:00Z
2015-12-31 12:15:00+01:00
2015-12-31 12:15

这太好了。我喜欢这种灵活性。不幸的是,它还解析以下歧义的日期:

4.3.2015   // The user intent could be March or April.

我知道我可以使用ParseExact,但这样我就必须提交一个大列表,其中包含所有可能提交给我的应用程序的明确日期格式。

我能以某种方式不允许模棱两可的日期格式,而不必指定每个明确的格式ParseExact?比如DateTime.Parse(myString, IsoCulture) ?

不允许模棱两可的日期

我不认为你可以通过提供一个单一的格式选项。

这是我的起始日期,至少可以确保日期部分的格式是正确的:

Public Function ParseUnAmbiguousDate(s As String, ByRef aDateTime As DateTime) As Boolean
    'keep a track of how long the date portion is
    Dim dateLength As Integer = 0
    'there are only two valid date formats in ISO terms yyyy-MM-dd or yyyyMMdd so try these first
    'is it too short?
    If s.Length < 8 Then Return False
    'try the yyyyMMdd format
    If DateTime.TryParseExact(s.Substring(0, 8), "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, aDateTime) Then
        dateLength = 8
    End If
    'try the yyyy-MM-dd format if the first option failed
    If dateLength = 0 Then
        'is it too short for this format?
        If s.Length < 12 Then Return False
        If DateTime.TryParseExact(s.Substring(0, 10), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, aDateTime) Then
            dateLength = 10
        End If
    End If
    'if we get here then check we have found a format
    If dateLength = 0 Then Return False
    'now substitue our date for a known one to try and parse the time
    Dim timePortion As Date
    If DateTime.TryParse("2000-01-01" & s.Substring(dateLength), timePortion) Then
        aDateTime = New DateTime(aDateTime.Year, aDateTime.Month, aDateTime.Day, timePortion.Hour, timePortion.Minute, timePortion.Second, timePortion.Kind)
        Return True
    Else
        Return False
    End If
End Function

可以使用这个扩展:

using System;
using NUnit.Framework;
namespace UnitTestProject1
{
    [TestFixture]
    public class UnitTest1
    {
        [TestCase("2015-12-31", true)]
        [TestCase("2015-01-01", true)]
        [TestCase("2015-12-31 12:15:00+01:00", true)]
        [TestCase("4.3.2015", false)]
        [TestCase("4.13.2015", true)]
        [TestCase("13.13.2015", false, ExpectedException = typeof(FormatException))]
        public void TestMethod1(string input, bool expected)
        {
            Assert.AreEqual(expected, input.IsDateNotAmbigous());
        }
    }
    public static class Extensions
    {
        public static bool IsDateNotAmbigous(this string stringDateTime)
        {
            DateTime parsed = DateTime.Parse(stringDateTime);
            return parsed.Day == parsed.Month || parsed.Day>12;
        }
    }
}

我想我必须同意公众的观点,如果不了解传入字符串文化,这不是一个容易解决的问题。即使我们像这样遍历所有可用的文化:

    public static bool IsDateNotAmbigous(this string stringDateTime)
    {
        return CultureInfo.GetCultures(CultureTypes.AllCultures).AsParallel().Select(ci =>
        {
            DateTime parsed = default(DateTime);
            bool success = DateTime.TryParse(stringDateTime, ci, DateTimeStyles.AssumeLocal, out parsed);
            bool test = parsed.Day > 12 || parsed.Day == parsed.Month;
            Trace.WriteLine(String.Format("{0,12}:{1,5}:{2,5}:{3:O}", ci.Name, success, test, parsed));
            if (!success)
                return -1;
            if (test)
                return 1;
            return 0;
        }).Where(w=>w>=0).Select(s=>s==1).Aggregate((b, b1) => b || b1);
    }

有些测试将不通过。但也许它会帮助某人想出一个优雅的解决方案。

无法停止思考

好吧,所以我们不能确定,没有一些传入文化的知识,但这应该让你更接近:

#region
using System;
using System.Globalization;
using System.Linq;
using NUnit.Framework;
#endregion
namespace UnitTestProject1
{
    [TestFixture]
    public class UnitTest1
    {
        [TestCase("2015-12-31", true)]
        [TestCase("2015-01-01", true)]
        [TestCase("2015-02-01", false)]
        [TestCase("2015-12-31 12:15:00+01:00", true)]
        [TestCase("4.3.2015", false)]
        [TestCase("4.13.2015", true)]
        [TestCase("13.13.2015", null, ExpectedException = typeof (InvalidOperationException))]
        public void TestMethod1(string input, bool expected)
        {
            Assert.AreEqual(input.DateIsLikelyNotAmbigous(), expected);
        }
    }
    public static class Extensions
    {
        public static bool DateIsLikelyNotAmbigous(this string stringDateTime)
        {
            return CultureInfo.GetCultures(CultureTypes.AllCultures).AsParallel().Select(ci =>
            {
                DateTime parsed = default(DateTime);
                bool success = DateTime.TryParse(stringDateTime, ci, DateTimeStyles.AssumeLocal, out parsed);
                if (!success)
                    return -1;
                if (parsed.Day > 12 || parsed.Day == parsed.Month)
                    return 1;
                return 0;
            }).Where(w => w >= 0).Average(a => a) > 0.02;
        }
    }
}

很想听听@hvd对此的看法。