【问题标题】:.NET: Why is TryParseExact failing on Hmm and Hmmss?.NET:为什么 TryParseExact 在 Hmm 和 Hmmss 上失败?
【发布时间】:2011-01-02 05:44:18
【问题描述】:

我正在尝试DateTime.TryParseExact 方法,但我遇到了一个我不明白的案例。我有一些格式和一些主题要解析,每个都应该完美匹配其中一种格式:

var formats = new[]
     {
         "%H",
         "HH",
         "Hmm",
         "HHmm",
         "Hmmss",
         "HHmmss",
     };

var subjects = new[]
     {
         "1",
         "12",
         "123",
         "1234",
         "12345",
         "123456",
     };

然后我尝试将它们全部解析并打印出结果:

foreach(var subject in subjects)
{
    DateTime result;
    DateTime.TryParseExact(subject, formats, 
        CultureInfo.InvariantCulture, 
        DateTimeStyles.NoCurrentDateDefault,
        out result);

    Console.WriteLine("{0,-6} : {1}", 
        subject,
        result.ToString("T", CultureInfo.InvariantCulture));
}

我得到以下信息:

1      : 01:00:00
12     : 12:00:00
123    : 00:00:00
1234   : 12:34:00
12345  : 00:00:00
123456 : 12:34:56

对于我的问题......为什么它在 123 和 12345 上失败了?那些不应该变成 01:23:00 和 01:23:45 吗?我在这里想念什么?我怎样才能让它像我期望的那样工作?


更新:所以,看起来我们可能已经弄清楚了为什么这会失败。似乎H 实际上是在抓取两位数,然后只为mm 留下一位,然后会失败。但是,有没有人知道如何更改此代码以获得所需的结果?

另一个更新: 认为我现在找到了一个合理的解决方案。添加它作为答案。将在 2 天内接受它,除非其他人想出更好的。感谢您的帮助!

【问题讨论】:

  • 您在我的机器上的确切代码,打印上午和下午,并在其他情况下将 123 和 12345 解析为上午 12 点而不是下午。这有点奇怪,因为它没有任何意义。
  • Coincoin: ToLongTimeString 取决于当前的文化。写 ToString("HH:mm:ss") 来保持一致可能会更好。
  • @Coincoin:这可能是因为你在不同的文化中打印出来。我将更新我的代码以使其更加不变。

标签: c# .net datetime parsing datetime-format


【解决方案1】:

0123 012345

我猜当它找到一串这样的数字时,它会寻找 2/4/6 的长度。 123应该是上午还是下午? 0123 不是那样的模棱两可。

【讨论】:

  • 嗯,H 应该是 24 小时格式(h 代表 12 小时)。在我的脑海中,当格式是 Hmm 并且字符串是 123 时,它不应该真的有太多的歧义空间。虽然可能是 H 需要 12,然后无法将 3 匹配到 m 中……但是是的……那我该如何解决呢?
  • 在这种情况下,我希望 24 小时符号需要 2 位数字。我不知道单个 H 会或应该如何解释。
  • 根据 msdn 是一样的,只是没有使用前导零:"H" -- 小时,使用从 0 到 23 的 24 小时制。
  • 我认为从不可能是两位数小时的数字开始可能会起作用,但“300”也无法解析。
【解决方案2】:

“123”和“12345”对于 TryParseExact 方法似乎是模棱两可的。例如,“12345”可以是 12:34:50 或 01:23:45。不过只是猜测。

【讨论】:

    【解决方案3】:

    我可能是错的,但我怀疑这可能与格式字符串的“H”部分固有的歧义有关——即,给定字符串“123”,您可能正在处理小时“1” (01:00) 或“12”小时 (12:00);由于TryParseExact 不知道哪个是正确的,所以它返回false。

    至于为什么该方法没有提供“最佳猜测”:恐怕文档不在您这边。来自MSDN documentation on DateTime.TryParse(强调我的):

    当这个方法返回时,包含 DateTime 值相当于日期 和时间包含在 s 中,如果 转换成功,DateTime.MinValue 如果 转换失败。转换 如果 sformat 则失败 参数是null,是空字符串,或者不是 包含日期和时间 对应于指定的模式 格式。该参数通过 未初始化。

    【讨论】:

    • 是的,我也想过,但 in 应该还是不会失败吧?
    • 好吧,我认为如果这种方法(接受 out 参数,返回布尔值)返回 false,那么您不应该使用分配给 out 的方法。范围。因此,一旦该方法意识到它会失败,它就会退出,而无需冒险进行“最佳猜测”。 (当然,这只是我自己的想法……)
    • 嗯,很明显。但这里的重点不是我是否应该使用结果,而是为什么它一开始就没有给我一个;-)
    • 这样想:使用DateTime 这可能看起来微不足道,但通常需要一些工作才能将字符串解析为给定的数据类型。当结果无论如何都不会有用时,与其工作,为什么不直接退出并告诉你的调用者你做不到呢?
    • 因为规范说我可以 :p 这是我们软件的一个特殊功能,允许用户更快地输入日期和时间。我有一个类似的日期功能,例如如果没有足够的数字来提取一个,则使用当前月份和/或年份。
    【解决方案4】:

    引用 MSDN 的 Using Single Custom Format Specifiers

    自定义日期和时间格式字符串由两个或多个字符组成。例如,如果格式字符串仅包含说明符 h,则格式字符串被解释为标准日期和时间格式说明符。但是,在这种特殊情况下,会引发异常,因为没有 h 标准日期和时间格式说明符。

    要使用单个自定义日期和时间格式说明符,请在日期和时间说明符之前或之后包含一个空格,或者在单个自定义日期和时间说明符之前包含一个百分比 (%) 格式说明符。例如,格式字符串“h”和“%h”被解释为自定义日期和时间格式字符串,显示当前日期和时间值所代表的小时。请注意,如果使用了空格,它将在结果字符串中显示为文字字符。

    那么,% H 应该是 formats 数组的第一个元素吗?

    希望这会有所帮助, 最好的祝福, 汤姆。

    【讨论】:

      【解决方案5】:

      如果您不使用日期或时间 自定义格式模式中的分隔符, 使用不变的文化 提供者参数和最宽的形式 每个自定义格式说明符。为了 例如,如果您想指定小时 在模式中,指定更宽的 形式,“HH”,而不是较窄的 表格,“H”

      引用: http://msdn.microsoft.com/en-us/library/ms131044.aspx

      正如其他人指出的那样,H 是模棱两可的,因为它意味着一天 10 小时,而 HH 是 12

      【讨论】:

      • H 表示小时的单个人类可读数字。因此,可能的选项是 0-9 或 10 个不同的小时。由于我们每天有 12 小时,而人类可读的数字是以 10 为基数,因此输入至少需要 HH 小时
      • H 并不表示小时数。它将小时表示为从 0 到 23 的数字。来源:The "H" Custom Format Specifier on MSDN
      【解决方案6】:

      好的,我想我现在已经弄清楚了这一切,这要归功于更多的阅读、实验和其他有用的答案。发生的事情是 Hms 实际上会在可能的情况下抓取两个数字,即使没有足够的数字用于其余数字的格式。因此,例如使用 Hmm 格式和数字 123H 会抓取 12,并且只会有一个3 离开。而 mm 需要两位数,所以它失败了。 忠告

      所以,我目前的解决方案是只使用以下三种格式:

      var formats = new[]
          {
              "%H",
              "Hm",
              "Hms",
          };
      

      由于我的问题中的其余代码保持不变,我将得到以下结果:

      1      : 01:00:00
      12     : 12:00:00
      123    : 12:03:00
      1234   : 12:34:00
      12345  : 12:34:05
      123456 : 12:34:56
      

      我认为应该既合理又可以接受:)

      【讨论】:

      • 嗯,这是一个解决方案。我不知道我是否会按照输入“123”的预期时间拨打 12:03!
      • 我有点同意,但同时它确实使 some 至少有意义 :p 我只是不确定如何将其解析为 1:23 而没有一堆更多的代码。有好的想法请赐教!
      • 在时间前面加上足够多的 0 使其成为六位数
      • ParseExact 用词不当。
      • 只是为了扩展这个答案:日 (d)、月 (M) 和年 (y) 的行为完全相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      • 2021-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多