【问题标题】:DateTime.ParseExact - how to parse single- and double-digit hours with same format string?DateTime.ParseExact - 如何解析具有相同格式字符串的一位数和两位数小时?
【发布时间】:2013-09-29 12:25:58
【问题描述】:

我希望能够解析 时间(小时、分钟、秒)的字符串,其中小时从 0 到 23,并且前面的零表示一位数小时是可选的。

我希望能够解析为有效DateTime 对象的时间 字符串示例:

  • 212540
  • 061525
  • 94505

我正在尝试使用 C# 方法 DateTime.ParseExact 来管理解析,但我无法在它的生命周期内想出一个可以处理“不带零的个位数小时”场景的格式字符串。

我应该如何指定DateTime.ParseExact 格式字符串以使用同一行代码充分解析上面的所有示例?

受MSDN page on custom date and time formats的启发,我尝试了以下方法:

DateTime.ParseExact(time_string, "Hmmss", CultureInfo.InvariantCulture);
DateTime.ParseExact(time_string, "%Hmmss", CultureInfo.InvariantCulture);
DateTime.ParseExact(time_string, "HHmmss", CultureInfo.InvariantCulture);

所有这些格式字符串都适用于上面的前两个示例情况,但面对一位数小时且前面没有零,所有公式都会抛出 FormatException。

【问题讨论】:

  • 如果time_string 只有五个字符宽,为什么不加一个零?
  • 您需要使用 Reflector 来反汇编 DateTime.Parse 的代码,因为据我所见,Hmmss 适用于前 2 个而不是最后一个。奇怪的是,根据文档,它技术上不应该适用于第二个,应该适用于最后一个。

标签: c# datetime string-parsing


【解决方案1】:

如果你知道你总是有六个字符,你可以填充你的输入字符串。

string input = "94505";
if(input.Length < 6)
   input = input.PadLeft(6, '0');

(如果您有其他更短的有效格式,则使用input.Length == 5)。

【讨论】:

  • 谢谢,@keyboardP,但我必须填充我的时间字符串以使解析工作似乎有点牵强?毕竟,使用“Hmmss”作为 output 格式说明符效果很好,例如new DateTime(2013, 9, 24, 7, 0, 0).ToString("Hmmss") 将输出“70000”。我仍然希望有人能想出“神奇”的格式字符串:-)
  • 进行了一些测试,似乎h 或H 试图获取两个字符,这会导致格式的其余部分失效。如果您将顺序颠倒到05459 并使用ssmmH,它工作正常。不是答案,但可能会有所帮助:)
  • 感谢@keyboardP 进一步调查。非常烦人的限制;最后我会看看如何在我自己的代码中解决这个问题。
  • 在您的特定情况下,您可以直觉正确的含义是什么,但在更一般的情况下,您会遇到输入字符串“111”和格式字符串“Hm”等问题。这可能是从 1:11 开始编码的,也可能是 11:01。对于如何解决这些问题,他们必须选择一个确定性、高性能且理想直观(或至少易于记忆)的规则。贪婪解析在大多数情况下都适合所有这些。事实证明,我们人类知道 Hmmss 应该在 12345 上具有确定性,但这可能是处理器的大量开销。
【解决方案2】:

您可以像这样在小时、分钟和秒之间插入分隔符:

string timeString = "94505";
string formatedTimeString = Regex.Replace(str, @"\d{1,2}(?=(\d{2})+$)", "$&:");
var datetime = DateTime.ParseExact(formatedTimeString, "H:mm:ss", CultureInfo.InvariantCulture);

更新: 我在使用格式字符串"Hmmss" 解析"94505" 时发现了the cause of failure:

发生的情况是,H、m 和 s 实际上会在可能的情况下抓取两位数字,即使对于其余格式而言没有足够的数字。因此,例如格式为 Hmm 和数字 123,H 将抓取 12,并且只剩下 3。而 mm 需要两位数,所以它失败了。

所以基本上你有两种选择来处理“个位数小时而不是前面零”的情况:

  1. 更改时间格式:将小时放在末尾(例如,"ssmmH" 或 "mmssH")或使用分隔符(例如,"H:mm:ss")

  2. 按照我之前的建议或 keyboardP has 修改字符串。

【讨论】:

  • 谢谢@Alexander,但理想情况下,我不想在解析之前修改我的时间字符串。如果我仍然需要,用前面的零填充字符串会容易得多,比如keyboardP is suggesting。
  • 感谢@Alexander 的更新和相关问题的链接。由于我无法影响输入时间字符串的格式,这是一个非常令人沮丧的情况,但现在我至少对背景了解了一点。
【解决方案3】:

如何使用:

DateTime.ParseExact(time_string, "Hmmss", CultureInfo.InvariantCulture).ToString("HH:mm:ss")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多