从字符串值中检索可能的 DateTime 格式列表

Retrieve list of possible DateTime formats from string value

我希望能够从 csv 文件解析日期 and/or 日期时间值并获取它们的日期时间格式(或 Excel 术语 NumberFormat)。

例如,我想将“2008-06-07 00:00:00.000”传递给一个函数,并使其 return 类似于 "yyyy-MM-dd hh:mm:ss.000"。

要注意的是,csv 文件中可能有许多可能的日期格式,并且无法提前知道它们,所以我不能使用 DateTime.TryParseExact(),因为它需要您知道 DateTime提前格式化字符串以测试它是否适用于特定值。

通过了解日期格式,我可以将其设置为 Excel 中的自定义数字格式并输入值,它会与 csv 文件中的文本完全一样,同时还具有在 Excel 公式中使用它的能力。

当然可能会有歧义,所以理想情况下,最好先获取一个可能的日期格式列表,然后检查多个日期,通过查看可能的日期格式列表的交集来删除一些选项.

我刚刚发现了 NodaTime API,看起来它可以做这样的事情,但我还没有看到可以实现这一点的示例代码,因为大多数关于类似查询的问题被要求提供似乎不受支持的早期版本。

任何其他执行此操作的方法也将不胜感激。

编辑

正如 Jon Skeet 所说,我认为唯一的方法是列出常见模式并针对它们进行测试。 我可以通过执行以下操作来获取所有培养的日期时间模式集。但是,此列表将缺少一些可能常用的自定义模式。比如(不知道这个常用不常用)yyyy/dd/MM不在列表中

    private static HashSet<string> _patterns; 
    public static HashSet<string> AllCulturedDateTimePatterns
    {
        get
        {
            if (_patterns != null)
                return _patterns;

            _patterns = new HashSet<string>();
            var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
            foreach (var culture in cultures)
            {
                _patterns.UnionWith(culture.DateTimeFormat.GetAllDateTimePatterns());
            }
            return _patterns;
        }
    }

你必须对传入数据有标准。没有这个你会把自己逼疯的。即使你用 vba 宏清理它(无论如何我建议你这样做),如果你在没有接受规则的情况下盲目接受所有格式,数据将永远不会正确。

你可以做的一件事(使用你的 vba 宏)是输入数据源(它应该有一个已知的日期格式)并根据该格式清理它。例如,站点 example.com 给你一个日期格式 MM/dd/yyyy 的 .csv,你的宏应该足够聪明,知道它不是 dd/MM/yyyy.

格式

如果您熟悉 Excel vba,这对您来说应该很有意义。如果你不是那么欢迎在 Excel vba!

编程

没有"all possible date formats"这样的东西。例如,"'Year:' yyyy 'Month:' MM 'Day:' dd" 的格式是有效的,但非常不常见。 Noda Time 在这里提供的任何内容都特别有帮助。我怀疑您需要创建自己的列表,列出您见过的所有 date/time 格式 - 然后您可以在 Noda Time 内为每种格式创建一个模式,并尝试解析它以检查是否成功结果,或在 BCL 中使用 DateTime.TryParseExact。例如:

BCL 版本

var allFormats = new List<string>
{
    "yyyy-MM-dd HH:mm:ss",
    "dd/MM/yyyy HH:mm:ss",
    "MM/dd/yyyy HH:mm:ss",
    // etc
};

DateTime ignored;
var matchingFormats = allFormats
    .Where(format => DateTime.TryParseExact(text, format, CultureInfo.InvariantCulture,
                                            DateTimeStyles.None, out ignored))
    .ToList();

野田时代版

var allFormats = ...; // As before
var allPatterns = allFormats
    .Select(format => LocalDateTimePattern.CreateWithInvariantCulture(format))
    .ToList();

var matchingPatterns = allPatterns.Where(pattern => pattern.Parse(text).Success)
                                  .ToList();

注意 IIRC,我们目前不公开来自 LocalDateTimePattern(或任何其他模式)的基础格式字符串。我们可以这样做,但目前我们不这样做...