在 C# 中将字符串解析为 TimeSpan

Parse string to TimeSpan in C#

我需要在 C# 中将字符串“26h44m3s”解析为 TimeSpan。我找不到在 .NET 中实现的任何可以处理它的东西。那么我如何以干净的方式完成它呢?是否有任何现有的 nugets?

我在 Twitch API 端点 GetVideos.

上从 "duration" 属性 接收字符串

您可以在没有任何外部依赖的情况下使用正则表达式解析来做到这一点:

public static TimeSpan ParseTwitchTime(string input)
{
    var m = Regex.Match(input, @"^((?<hours>\d+)h)?((?<minutes>\d+)m)?((?<seconds>\d+)s)?$", RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.RightToLeft);

    int hs = m.Groups["hours"].Success ? int.Parse(m.Groups["hours"].Value) : 0;
    int ms = m.Groups["minutes"].Success ? int.Parse(m.Groups["minutes"].Value) : 0;
    int ss = m.Groups["seconds"].Success ? int.Parse(m.Groups["seconds"].Value) : 0;

    return TimeSpan.FromSeconds(hs*60*60 + ms*60 + ss);
}

用法:

        var d = ParseTwitchTime("100h");
        d = ParseTwitchTime("23m1000s");
        d = ParseTwitchTime("12345h678s");

PS:RightToLeft 选项仅用于正则表达式性能而不影响输出结果(如果没有它,它会回溯很多)。

您可以为此使用 Noda Time,解析为 Duration。您 可以 然后将其转换为 TimeSpan - 或者您可以在任何地方使用 Noda Time 并获得更好的体验:)

示例代码:

using System;
using NodaTime;
using NodaTime.Text;

class Program
{
    static void Main()
    {
        string text = "26h44m3s";
        var pattern = DurationPattern.CreateWithInvariantCulture("H'h'm'm's's'");
        var duration = pattern.Parse(text).Value;
        Console.WriteLine(duration);
        var ts = duration.ToTimeSpan();
        Console.WriteLine(ts);
    }
}

如果您有多个需要匹配的模式,您可以创建一个复合模式 - 尽管您需要明确列出所有模式。这是一个例子:

using System;
using System.Linq;
using NodaTime;
using NodaTime.Text;

class Program
{
    static void Main()
    {

        string[] formats =
        {
            "H'h'm'm's's'", "H'h'm'm'", "M'm's's'", "H'h'", "M'm'", "S's'"
        };
        var patterns = formats.Select(DurationPattern.CreateWithInvariantCulture);
        var builder = new CompositePatternBuilder<Duration>();
        foreach (var pattern in patterns)
        {            
            // The second parameter is used to choose which pattern is
            // used for formatting. Let's ignore it for now.
            builder.Add(pattern, _ => true);
        }
        var composite = builder.Build();


        string[] values = { "26h8m", "26h", "15s", "56m47s" };
        foreach (var value in values)
        {
            Console.WriteLine(composite.Parse(value).Value);
        }
    }
}

我写了一个自定义方法来让你这样做:

public static class TimeSpanHelper
{
    private static List<(string Abbreviation, TimeSpan InitialTimeSpan)> timeSpanInfos = new List<(string Abbreviation, TimeSpan InitialTimeSpan)>
    {
            ("y", TimeSpan.FromDays(365)), // Year
            ("M", TimeSpan.FromDays(30)), // Month
            ("w", TimeSpan.FromDays(7)), // Week
            ("d", TimeSpan.FromDays(1)), // Day
            ("h", TimeSpan.FromHours(1)), // Hour
            ("m", TimeSpan.FromMinutes(1)), // Minute
            ("s", TimeSpan.FromSeconds(1)), // Second
            ("t", TimeSpan.FromTicks(1)) // Tick
    };

    public static TimeSpan ParseDuration(string format)
    {
        var result = timeSpanInfos
            .Where(timeSpanInfo => format.Contains(timeSpanInfo.Abbreviation))
            .Select(timeSpanInfo => timeSpanInfo.InitialTimeSpan * int.Parse(new Regex(@$"(\d+){timeSpanInfo.Abbreviation}").Match(format).Groups[1].Value))
            .Aggregate((accumulator, timeSpan) => accumulator + timeSpan);
        return result;
    }
}

您可以通过以下方式使用它:

var total = TimeSpanHelper.ParseDuration("26h44m3s");