是否有一种简便的方法来实现TimeSpan格式的条件复数?

时间:2018-08-13 16:25:50

标签: c# datetime format timespan

我有TimeSpan个对象,可以跟踪计算时间。 TimeSpan的范围从几秒到几天。我目前有一个非常冗长的方法,可以从TimeSpan中给我一个字符串,该字符串以长形式表示TimeSpan;例如:

3 Days 13 Hours 1 Minute 52 Seconds

TimeSpan小于1秒时,我显示Milliseconds属性。上面的代码很简单,但是很冗长。有没有一种类似于DateTime.Now.ToString("ddMMyyyy hhmmssffff")的简洁方法?下面是我当前的代码:

public static string GetLongTime(TimeSpan t) {
    string result = string.Empty;
    if (t.Days > 0) {
        if (t.Days == 1) result = "1 Day";
        else result = $"{t.Days} Days";
    } else if (t.TotalMilliseconds < 1000) {
        if (t.Milliseconds > 0)
            result = $"{t.Milliseconds}ms";
    } else {
        if (t.Hours > 0) {
            if (t.Hours == 1) result += "1 Hour ";
            else result += $"{t.Hours} Hours ";
        }
        if (t.Minutes > 0) {
            if (t.Minutes == 1) result += "1 Minute ";
            else result += $"{t.Minutes} Minutes ";
        }
        if (t.Seconds > 0) {
            if (t.Seconds == 1) result += "1 Second ";
            else result += $"{t.Seconds } Seconds ";
        }
    }
    return result;
}

DateTime一样,TimeSpan对象也有一个custom format list;但是,他们的示例列表显示带有良好{'1}}附件的字符串:

(s)
  

旅行时间:1天

     

旅行时间:01.12:24:02天

这不是我真正想要的。我也在这里查看了StackOverflow上的一些相关文章,正如一位用户在评论中指出的那样,它们是不错的资源。总体而言,这些都不是我正在寻找的解决方案,因为我对诸如此类的简明扼要的东西寄予厚望:

  TimeSpan duration = new TimeSpan(1, 12, 23, 62);
  Console.WriteLine("Time of Travel: {0:%d} day(s)", duration);
  Console.WriteLine("Time of Travel: {0:dd\\.hh\\:mm\\:ss} days", duration);

上面提供的只是伪造的,实际上不会做更多的事情:

  

3天?s

一些相关的帖子有望重构我的代码;例如,this post推荐条件赋值运算符:

return t.ToString("d Day?s");

尽管这可以缩短代码,但也不能使它看起来最干净(特别是对于新开发人员而言)。这也符合this post的建议,OP建议使用正确格式的string result = string.Empty; if (t.Days > 0) return $"{t.Days} {(t.Days > 1 ? "Days " : "Day ")}"; else if (t.TotalMilliseconds < 1000) { if (t.Milliseconds > 0) return $"{t.Milliseconds}ms"; } else { if (t.Hours > 0) result += $"{t.Hours} {(t.Hours > 1 ? "Hours " : "Hour ")}"; if (t.Minutes > 0) result += $"{t.Minutes} {(t.Minutes > 1 ? "Minutes " : "Minute ")}"; if (t.Seconds > 0) result += $"{t.Seconds} {(t.Seconds > 1 ? "Seconds " : "Second ")}"; } return result; ;但是,我同意该帖子上的{{3}}; 您的代码确实需要花费一些时间。那是我唯一不爱的东西。

有没有一种方法可以在格式字符串中实现条件复数;还是比我上面的方法更简单,简洁?

2 个答案:

答案 0 :(得分:1)

.NET中没有内置的TimeSpan格式说明符,因此无法实现。

但是,我之前已经实现了此功能。它可以在我的免费开放源代码utility library中获得。它是根据MIT许可发布的,因此您可以复制代码或将库包含在项目中。

用法(选择后者时)

安装NuGet软件包。在Package Manager控制台中键入以下内容:

Install-Package Karambolo.Common

然后,您可以使用 ToTimeReference 扩展方法转换 TimeSpan 值。

using System;
using Karambolo.Common;
using Karambolo.Common.Localization;

class Program
{
    static void Main(string[] args)
    {
        var ts = new TimeSpan(3, 13, 1, 52);
        Console.WriteLine(ts.ToTimeReference(4, "{0}", "now", "{0}", DefaultTextLocalizer.Instance));
    }
}

上面的代码打印:

3 days 13 hours 1 minute 52 seconds

在示例代码中使用的 ToTimeReference 重载使您可以完全控制输出的格式。最后一个参数是一个委托人,负责指定时间间隔字符串的格式(例如“ day”,“ hour”等)。它可用于本地化函数的输出。

答案 1 :(得分:1)

这只是一个较短的方法。这里的可读性只是一个角度问题:)

一些例子,看看是否满足要求。

TimeSpan ts = new TimeSpan(3, 4, 10, 25);
=> 3 Days 4 Hours 10 Minutes 25 Seconds

TimeSpan ts = new TimeSpan(0, 0, 0, 0, 700);
=> 700ms

TimeSpan ts = new TimeSpan(0, 2, 0, 1, 700);
=> 2 Hours 1 Second

TimeSpan ts = new TimeSpan(1, 1, 1, 1);
=> 1 Day 1 Hour 1 Minute 1 Second


TimeSpan ts = new TimeSpan([Some time span]);

string[] TFormat = new[] {
    (ts.Days > 1 ? ts.Days + " Days" : (ts.Days == 1 ? "1 Day" : "")),
    (ts.Hours > 1 ? " "+ ts.Hours + " Hours" : (ts.Hours == 1 ? " 1 Hour" : "")),
    (ts.Minutes > 1 ? " " + ts.Minutes + " Minutes" : (ts.Minutes == 1 ? " 1 Minute" : "")),
    (ts.Seconds > 1 ? " " + ts.Seconds + " Seconds" : (ts.Seconds == 1 ? " 1 Second" : "")),
    (ts.TotalMilliseconds < 1000 ? $"{ts.TotalMilliseconds }ms" : "")
};

Console.WriteLine($"{TFormat[0]}{TFormat[1]}{TFormat[2]}{TFormat[3]}{TFormat[4]}".TrimStart());