【问题标题】:Check if given string is valid format string for converting DateTime检查给定字符串是否是用于转换 DateTime 的有效格式字符串
【发布时间】:2019-06-28 13:52:43
【问题描述】:

TLDR;

我需要验证给定的输入字符串是否是有效的“格式字符串”来解析 DateTime。例如,

  • yy-mm-dd 有效
  • yy-aaaaaaa123 无效

我正在开发一个program,它接受日期格式作为用户的输入。下面是我剥离出来的代码

private string datetimeFormat;

public Logger(string dateFormat)
{
    datetimeFormat = dateFormat;
}

...
...
...

// Inside some function
string pretext = $"{DateTime.Now.ToString(datetimeFormat)},{logLevel},";

我需要为dateFormat 字符串输入添加验证。

我正在考虑在一个数组中有许多可能的组合并且只接受那些字符串。但是还有其他方法可以验证吗?


更新

我的输入字符串不包含任何日期。这不是 specified question 的副本。

This question 根本与 DateTime 无关。

【问题讨论】:

  • 技术上,yy-aaaaaaa123 是有效的:两位数年份后跟-aaaaaaa123;例如"98-aaaaaaa123" 将被解析为 1 Jan 1998 0:00:00
  • @KolappanNathan 在哪种情况下有效?如果您确切知道什么对您有效,则创建一个有效格式数组并使用Contains,即if(validFormats.Contains(inputFormat))
  • 一些格式,如dd-mm-yyyy,是有效,看起来不错,但错误天-分钟-。可能,您可能希望枚举合理的格式并让用户选择分隔符:dd-MM-yyyydd/MM/yyyydd.MM.yyyy 等。
  • “我正在考虑在一个数组中有许多可能的组合并且只接受那些字符串。” - 这是正确的解决方案
  • 你为什么允许用户指定他们的日期格式?只有几个标准的,它们得到了很好的支持。 ISO8601 的存在是有原因的。

标签: c# string validation string-formatting datetime-format


【解决方案1】:

这取决于你所说的“有效”是什么意思,以及你认为“只有DateTime,没有别的”限制对你来说有多重要。

以下是我们可以用来测试格式字符串的一些规则,但有一些明确的限制:

  1. 必须适合传递给DateTime.ToString(string format) 以将DateTime 值转换为字符串。

  2. 必须可用于将规则 1 的输出解析为有效的 DateTime 值。

  3. 规则 2 的输出不得包含时间部分。

  4. (可选)规则 2 的输出应与定义的精度范围内的输入相同。

只要您期望输出是完全指定的日期,这些对于许多用途来说已经足够了。必须指定年、月和日。下面是一些用于测试这些规则的代码:

static System.Globalization.CultureInfo DateTimeProvider = System.Globalization.CultureInfo.InvariantCulture;
const System.Globalization.DateTimeStyles ParseExactStyle = System.Globalization.DateTimeStyles.None;
static DateTime[] DateSamples = new[]
    {
        DateTime.Now,
        DateTime.Today,
        DateTime.Today.AddDays(1 - DateTime.Today.Day),
        DateTime.Parse("10-Jan-2000"),
        DateTime.Parse("01-Oct-1990"),
        DateTime.Parse("13-Feb-1901")
    };

public static bool IsValidDateFormat(string format, out string result)
{
    var maxDifference = TimeSpan.FromDays(1);
    foreach (var sample in DateSamples)
    {       
        // Rule 1: Must be suitable for '.ToString(...)'
        string sampleString;
        try
        {
            sampleString = sample.ToString(format);
        }
        catch (FormatException e)
        {
            result = $"Failed rule 1: {e.Message}";
            return false;
        }

        // Rule 2: Must be able to parse the produced string
        if (!DateTime.TryParseExact(sampleString, format, DateTimeProvider, ParseExactStyle, out var parsed))
        {
            result = $"Failed rule 2: does not parse it's own output. '{sampleString}'";
            return false;
        }

        // Rule 3: No time values.
        if (parsed != parsed.Date)
        {
            result = $"Failed rule 3: No time values. '{sampleString}' => #{parsed}#";
            return false;
        }

        // Rule 4: Difference must be less than maxDifference
        TimeSpan difference = sample < parsed ? parsed - sample : sample - parsed;
        if (difference >= maxDifference)
        {
            result = $"Failed rule 4: difference '{difference}' too large.";
            return false;
        }
    }

    result = "OK";
    return true;
}

(这会将result out 参数设置为格式字符串失败原因的描述,或者如果它通过则OK,但您可能更愿意返回一个简单的枚举值。)

这适用于各种奇怪的格式,包括那些带有额外的非上下文(或至少是非时间)字符的格式。样本包括一些针对时间值、顺序反转等的测试。

但是有一些限制:

  • TryParseExact 不适用于 standard format strings,例如 d、'F' 等。
  • 它也不适用于 3 位以上的年份格式 (yyy) 和其他拉伸格式。
  • 样本包括一项测试,可防止使用 2 位数年份。

简而言之,对于简单的工作来说已经足够了。你可以稍微修剪一下。

【讨论】:

    猜你喜欢
    • 2010-12-23
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多