我的任务是以“HHmm”格式表示持续时间。这至少在名义上是 Nodatime.DurationPattern 解析时应该没有问题的,因为它遵循here指定的要求。事实上,它是作为可以使用的模式的示例而专门提到的。
如果不在小时和分钟之间添加某种分隔符,我就无法正确解析它(例如“HH | mm”或“HH!mm”等将解析没有问题)。
我编写了这个测试代码来演示该问题:
public void ConvertWithPattern()
{
var result1 = DurationPattern.CreateWithInvariantCulture("HH mm").Parse("12 13");
var result2 = DurationPattern.CreateWithInvariantCulture("HHmm").Parse("1213");
Assert.True(result1.Success);
Assert.Equal(12, result1.Value.Hours);
Assert.Equal(13, result1.Value.Minutes);
Assert.True(result2.Success); // this assertion fails
Assert.Equal(result1, result2);
}
失败的 ParseResult 报告显示 UnparsableValueException 并显示以下消息:
值字符串与格式中所需的数字不匹配 字符串“毫米”。正在解析的值:'1213^'。 (^表示错误 位置。)
有什么方法可以用 Nodatime.DurationPattern 解析这个模式吗?
有什么方法可以用 Nodatime.DurationPattern 解析这个模式吗?
有潜力。作为解释,当使用“总值”说明符(如
H
)时,出现的字母数将用作 minimum 数字,而不是 maximum。它将解析尽可能多的数字(无论如何,最多 13 个)。所以基本上 Noda Time 正在解析“1213 小时”的值,然后查找分钟 - 这就是出错的地方。
如果您只需要考虑 00:00 到 23:59 范围内的持续时间,您可以使用“partial”
hh
说明符而不是 HH
:
var pattern = DurationPattern.CreateWithInvariantCulture("hhmm")
var result = pattern.Parse("1234");
如果您需要支持比这更多的时间,那就变得很棘手 - 我们基本上需要解析,直到分钟只剩下两个字符,而这不是 Noda Time 目前支持的方法。
如果您需要支持“超过 23 小时,但最多 99 小时”(因此恰好是两位数),那么对于当前架构来说,这至少是“可行的”,但无法轻松地用现有模式来表示。 我已就此事
提出问题一个选项在字符串分配和潜在报告错误方面都非常糟糕,但它至少允许您使用IPattern<Duration>
直到 Noda Time 本身有更好的解决方案,那就是自己实现
IPattern<Duration>
来插入一个解析前分离,格式化前删除。这是一个至少具有合理功能的示例:using NodaTime;
using NodaTime.Text;
using System.Text;
public sealed class HHmmDurationPattern : IPattern<Duration>
{
private readonly DurationPattern patternWithColons = DurationPattern.CreateWithInvariantCulture("HH:mm");
public StringBuilder AppendFormat(Duration value, StringBuilder builder) =>
builder.Append(Format(value));
public string Format(Duration value)
{
string formatted = patternWithColons.Format(value);
return formatted.Replace(":", "");
}
public ParseResult<Duration> Parse(string text)
{
// If the input is too short, just let the underlying pattern complain.
if (text.Length < 2)
{
return patternWithColons.Parse(text);
}
var textWithColons = text.Substring(0, text.Length - 2) + ":" + text.Substring(text.Length - 2);
return patternWithColons.Parse(textWithColons);
}
}
请注意,这不
强制总小时数只有 2 位 - 因此它将“12345”解析为“123 小时 45 分钟”。它可能并不理想,但作为临时措施可能会有所帮助。