【问题标题】:DateTime.TryParseExact Parses date value but adds default time value (where there was none)DateTime.TryParseExact 解析日期值,但添加默认时间值(没有时间值)
【发布时间】:2021-06-29 07:51:53
【问题描述】:

编辑:因为我有很多关于使用单一格式而不是数组的 TryParseExact 的 cmets:

  • 我必须测试数组中的所有格式 - 输入可能是这些格式,而我对这些其他格式的单元测试确实有效。我必须全部使用它们。
  • 我知道 DateTime.TryParse 将匹配第一个而不是进一步迭代。因此我使用 TryParseExact as Microsoft shows。它应该完全匹配。但它在这种情况下不起作用。

TLDR:给定格式为"dd/MM/yyyy" 且值为"29/11/2019" 的字符串 DateTime.TryParseExact 返回格式为"dd/MM/yyyy hh:mm tt" 和值29/11/2019 12:00 AM 的匹配项。为什么?

问题:使用 TryParseExact 时,如何确保 "dd/MM/yyyy" 格式的字符串与 "dd/MM/yyyy" 格式而不是 "dd/MM/yyyy hh:mm tt" 格式匹配?

上下文的长解释;

我有以下问题。我需要将多种日期格式从字符串解析为日期时间值。它们(输入字符串)可以以下列格式出现:

{ "dd/MM/yyyy hh:mm tt", "dd/M/yyyy hh:mm tt", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:m", "dd/MM/yyyy", "dd-MM-yyyy", "d-M-yyyy", "dddd, d MMMM yyyy"};

为了解决这个问题,我编写了一个字符串扩展,它解析给定的输入字符串并返回 bool 成功和潜在的匹配格式。

  private static readonly string[] _DateFormats = new string[] { "dd/MM/yyyy hh:mm tt", "dd/M/yyyy hh:mm tt", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:m", "dd/MM/yyyy", "dd-MM-yyyy", "d-M-yyyy", "dddd, d MMMM yyyy"};

  public static bool StringToDateTime(this string dateTimeString, out DateTime dateTimeValue, out string matchingFormat)
  {
      matchingFormat = ""; // defaults
      dateTimeValue = new DateTime();
      if (string.IsNullOrEmpty(dateTimeString)) return false;
      foreach (string format in DateFormats)
      {
          matchingFormat = format;
          if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue)) return true;
      }
      return false;
  }

这会将字符串输入"29/11/2019 successfully" 作为日期时间29/11/2019 12:00 AM 返回,其匹配格式为"dd/MM/yyyy hh:mm tt",而不是与原始输入29/11/2019 匹配的格式。

鉴于这个问题,我能想到的唯一(胶带)解决方案是:

public static bool StringToDateTime(this string dateTimeString, out DateTime dateTimeValue, out string matchingFormat)
{
    matchingFormat = ""; // defaults
    dateTimeValue = new DateTime();
    if (string.IsNullOrEmpty(dateTimeString)) return false;
    foreach (string format in DateFormats)
    {
        matchingFormat = format;
        if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue))
        {
            // ensure the datetime format is consistent with the dateTimeString passed to us.
            if(dateTimeString.Length != matchingFormat.Length)
            {
                var _matchingFormat = DateFormats.First(d => d.Length == dateTimeString.Length);
                matchingFormat = string.IsNullOrEmpty(_matchingFormat) ? matchingFormat : _matchingFormat;
            }
            return true;
        }
    }
    return false;
}

这可行,但显然,这还有其他问题(产生输入格式等)。所以我宁愿不用这个。

【问题讨论】:

  • 你的意思是什么确切“返回与格式的匹配”? DateTime 总是有一个时间组件,默认是午夜。此外,DateTime 没有格式,它是一个表示日期和时间的值,将其转换为字符串涉及格式。只需在调试器中查看DateTime 值通常也会显示时间组件。 .NET 6 将获得 TimeOnly 和 DateOnly 类型,不会有这个,但 DateTime 总是 有日期和时间组件。
  • 请edit your post,以便它包含正确的minimal reproducible example,以及对代码的作用、与您的预期有何不同以及确切 你需要帮助。除了您似乎混淆了TryParse() 和TryParseExact()(您在上面提到了两者)这一事实之外,您似乎对DateTime 值的工作方式有一些不合理/不正确的期望。
  • 正如其他人所说,DateTime 没有格式。在内部,它只是one 64-bit integer。
  • 我指的是从我的函数返回的时间格式。我将对其进行编辑以使其更加清晰。我认为 TLDR 说它以该值返回已经很清楚了。
  • @Karlsen 我了解两者的工作原理,并且我绝对在寻找与 TryParseExact 完全匹配的方法。我在这里指的是 TryParse 和 TryParse 的同义词,因为两者都与我的问题无关:如何确保格式为“dd/MM/yyyy”的字符串与格式“dd/MM/”匹配返回使用 TryParseExact 时使用 yyyy" 而不是 "dd/MM/yyyy hh:mm tt"?

标签: c# date datetime c#-8.0


【解决方案1】:

System.DateTime 不能在没有时间组件的情况下存在,因此不可能将日期解析为 DateTime 而不是时间组件。它将默认为一天的开始,例如12:00 AM,与调用dateTime.Date() 的结果相同。这将允许您在不考虑时间的情况下比较两个日期。

如果拥有或存储时间元素真的让您感到困扰,那么您可以创建自己的 struct 来存储日期,或者考虑使用像 NodaTime 这样提供仅日期结构的东西。

此外,Dotnet 6 将引入 DateOnly 和 TimeOnly 结构来执行此操作。您可以在MS devblogs 上阅读更多相关信息。

【讨论】:

  • 我知道 DateTime 使用默认时间值初始化(因此输出)。问题是它匹配错误的格式。
【解决方案2】:

您正在传递整个格式数组,因此它将匹配其中任何一个。

由于您在foreach 上超过DateFormats,因此您只需匹配当前值即可。

所以替换这一行

if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue))
    return true;

有了这个

if (DateTime.TryParseExact(dateTimeString, format, AUSCulture, DateTimeStyle, out dateTimeValue))
    return true;

【讨论】:

  • 我想匹配数组中的任何格式,这不是重点。
  • 无论如何你都在foreach 中而不是DateFormats,所以它最终会匹配其中一个
  • 是的,问题是它最初匹配第一种格式并停止。阅读我解释所有这些的问题。
  • 再次,我阅读了这个问题,并试图向您解释:您在foreach 的每个循环中传递所有格式,所以它即使在第一次运行时也将始终匹配任何格式。这是你需要改变的。你真的试过我展示的代码吗?
  • 你根本没有读到我说的一个字。我再重复一遍:如果你一次性传递所有格式,它会尝试匹配任何个,这就是你在循环中所做的。而如果你只传递循环变量format 只有那个会匹配。看到这个小提琴dotnetfiddle.net/9fE5B5
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
相关资源
最近更新 更多