如何将TimeSpan转换为格式化的字符串?

142

我有两个 DateTime 变量,beginTime 和 endTime。我通过以下方式得到它们之间的差:

TimeSpan dateDifference = endTime.Subtract(beginTime);

如何使用C#将时间差以hh小时mm分钟ss秒的格式返回字符串。

如果时间差为00:06:32.4458750

则应该返回00小时06分钟32秒


1
要获取更现代的答案,请访问此问题:https://dev59.com/ZHRB5IYBdhLWcg3wl4Sc - User
14个回答

211

我刚刚编写了一些TimeSpan扩展方法,想分享一下:

public static string ToReadableAgeString(this TimeSpan span)
{
    return string.Format("{0:0}", span.Days / 365.25);
}

public static string ToReadableString(this TimeSpan span)
{
    string formatted = string.Format("{0}{1}{2}{3}",
        span.Duration().Days > 0 ? string.Format("{0:0} day{1}, ", span.Days, span.Days == 1 ? string.Empty : "s") : string.Empty,
        span.Duration().Hours > 0 ? string.Format("{0:0} hour{1}, ", span.Hours, span.Hours == 1 ? string.Empty : "s") : string.Empty,
        span.Duration().Minutes > 0 ? string.Format("{0:0} minute{1}, ", span.Minutes, span.Minutes == 1 ? string.Empty : "s") : string.Empty,
        span.Duration().Seconds > 0 ? string.Format("{0:0} second{1}", span.Seconds, span.Seconds == 1 ? string.Empty : "s") : string.Empty);

    if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);

    if (string.IsNullOrEmpty(formatted)) formatted = "0 seconds";

    return formatted;
}

2
如果我不想显示秒或天怎么办。这样做不太可扩展:( 但它肯定是正确的方向,你应该在这里接受一个像“hh:mm”这样的字符串,并根据它构建时间。就像ToString()一样,我认为@rubenroid的答案是最好的答案。 - Piotr Kula
2
@ppumkin的回答以完全固定的格式显示结果。而这个回答将处理1秒钟到数百天的合理显示,但@ppumkin的回答则不会。 - NickG
3
如果你只想显示TimeSpan中最重要的部分,例如“2天前”或“15分钟前”,那么请查看受@Peter anwear启发的此代码片段:https://gist.github.com/Rychu-Pawel/fefb89e21b764e97e4993ff517ff0129 - Rychu
@Rychu 你的代码需要使用 C# 8.0 版本。 - Mecanik

157

通过将其转换为datetime,您可以获得本地化格式:

new DateTime(timeSpan.Ticks).ToString("HH:mm");

6
请确保使用"HH"而不是"hh"作为格式说明符,否则小时值为0的情况可能会打印为"12" - 我猜测格式说明符的解释取决于所设置的区域设置。 - weiji
5
同样的问题也存在于Guffa提出的代码中——如果经过的时间长达26小时,输出结果会显示为"02:00"小时。但我非常喜欢这种格式化字符串的打印方式。 - weiji
我需要在VB表达式中使用一行代码。这个非常完美。 - Jamie F
7
如果时间跨度为负数,这种方法将会出现问题。 - Sugrue
这不适用于“d”天。如果使用DateTime,则天数始终为“1”。 - Charles

147

这是最短的解决方案。

timeSpan.ToString(@"hh\:mm");

12
这里有一个错误。时间跨度为1天、0小时和33分钟,尽管实际上是24:33,但它会返回00:33。请修复此问题。 - Rick Rat
13
在我看来,我不会把它称为一个错误,因为它通常用于显示两个时间段之间经过的时间。这很少会超过一整天。 无论如何,我理解你的观点,如果是这种情况,那么这个解决方案对你来说可能就不适用了。 但我认为这个想法很棒。 - Falgantil
7
这是因为答案中的格式字符串没有指定要显示时间跨度的天数部分的值;24小时滚动到1天。这不是错误,只是没有显示出来。 - AnotherUser
4
timeSpan.ToString(@"d:hh:mm"); - markthewizard1234
3
@BjarkeSøgaard 我同意这不是一个 bug,如果你想显示日期,你必须在格式字符串中包含它,但是对于两个 DateTime 的 TimeSpan 差异很少超过一整天的假设是从哪里来的呢? - Thomas Mulder
显示剩余4条评论

47

你是否可以利用TimeSpan.ToString()方法完成所需的操作?如果不行, 那么该页面上的代码示例似乎描述了如何自定义格式化TimeSpan对象。


1
我得到了相同的结果,重新搜索并更新了链接。这个链接对你有效吗? - Andy
74
该页面并未描述程序员如何任意格式化TimeSpan字符串。它仅描述了当使用ToString()进行转换时返回TimeSpan的格式。该ToString()不接受任何自定义参数,例如“mm:ss”。代码示例仅显示了在给定不同TimeSpan值的情况下自动生成的字符串的外观,而没有展示如何任意格式化它。您需要先将TimeSpan转换为DateTime(TimeSpan.Ticks).ToString("mm:ss")。 - MrSparkly
我是这样转换的 => timespan.tostring("%d") + " " +timespan.tostring(@"hh:mm:\ss"); 。这个想法是分别获取所需的字符串,然后将它们连接起来。 - prabhakaran
26
FYI自从.Net 4.0以来,ToString方法可以接受自定义格式作为参数(例如mm\\:ss),具体请参见此页面:http://msdn.microsoft.com/en-us/library/dd992632.aspx。 - JYL
更多选项请参见: https://msdn.microsoft.com/zh-cn/library/ee372287(v=vs.110).aspx - Burak Karakuş
1
该链接文章中不包含任何带有ToString()调用的代码... - David

37
使用 String.Format() 处理多个参数。
using System;

namespace TimeSpanFormat
{
    class Program
    {
        static void Main(string[] args)
        {
            TimeSpan dateDifference = new TimeSpan(0, 0, 6, 32, 445);
            string formattedTimeSpan = string.Format("{0:D2} hrs, {1:D2} mins, {2:D2} secs", dateDifference.Hours, dateDifference.Minutes, dateDifference.Seconds);
            Console.WriteLine(formattedTimeSpan);
        }
    }
}

14
   public static class TimeSpanFormattingExtensions
   {
      public static string ToReadableString(this TimeSpan span)
      {
         return string.Join(", ", span.GetReadableStringElements()
            .Where(str => !string.IsNullOrWhiteSpace(str)));
      }

      private static IEnumerable<string> GetReadableStringElements(this TimeSpan span)
      {
         yield return GetDaysString((int)Math.Floor(span.TotalDays));
         yield return GetHoursString(span.Hours);
         yield return GetMinutesString(span.Minutes);
         yield return GetSecondsString(span.Seconds);
      }

      private static string GetDaysString(int days)
      {
         if (days == 0)
            return string.Empty;

         if (days == 1)
            return "1 day";

         return string.Format("{0:0} days", days);
      }

      private static string GetHoursString(int hours)
      {
         if (hours == 0)
            return string.Empty;

         if (hours == 1)
            return "1 hour";

         return string.Format("{0:0} hours", hours);
      }

      private static string GetMinutesString(int minutes)
      {
         if (minutes == 0)
            return string.Empty;

         if (minutes == 1)
            return "1 minute";

         return string.Format("{0:0} minutes", minutes);
      }

      private static string GetSecondsString(int seconds)
      {
         if (seconds == 0)
            return string.Empty;

         if (seconds == 1)
            return "1 second";

         return string.Format("{0:0} seconds", seconds);
      }
   }

1
正是我需要的答案。以非常易读的格式显示时间跨度。 - Thameem

8

格式化 TimeSpan 最简单的方法是将其添加到 DateTime 并进行格式化:

string formatted = (DateTime.Today + dateDifference).ToString("HH 'hrs' mm 'mins' ss 'secs'");

只要时间差不超过24小时,这个方法就可以工作。

Today属性返回一个DateTime值,其中时间组件为零,因此结果的时间组件是TimeSpan值。


2
我认为这是最简单的方法。您可能想要删除零小时和分钟,例如:.ToString("HH '小时' mm '分钟' ss '秒钟'").Replace("00 小时", "").Replace("00 分钟", "").Trim() - Igor Krupitsky

6
根据Microsoft文档,TimeSpan结构体将小时、分钟、秒和毫秒作为整数成员暴露出来。也许你需要像这样的东西:
dateDifference.Hours.ToString() + " hrs, " + dateDifference.Minutes.ToString() + " mins, " + dateDifference.Seconds.ToString() + " secs"

5
您可以使用以下代码。
public static class TimeSpanExtensions
{
  public static String Verbose(this TimeSpan timeSpan)
  {
    var hours = timeSpan.Hours;
    var minutes = timeSpan.Minutes;

    if (hours > 0) return String.Format("{0} hours {1} minutes", hours, minutes);
    return String.Format("{0} minutes", minutes);
  }
}

5

感谢Peter提供的扩展方法。我对其进行了修改,以更好地处理较长时间跨度:

namespace ExtensionMethods
{
    public static class TimeSpanExtensionMethods
    {
        public static string ToReadableString(this TimeSpan span)
        {
            string formatted = string.Format("{0}{1}{2}",
                (span.Days / 7) > 0 ? string.Format("{0:0} weeks, ", span.Days / 7) : string.Empty,
                span.Days % 7 > 0 ? string.Format("{0:0} days, ", span.Days % 7) : string.Empty,
                span.Hours > 0 ? string.Format("{0:0} hours, ", span.Hours) : string.Empty);

            if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);

            return formatted;
        }
    }
}

可以加年份吗?但我认为加年份可能不准确。 - Thunder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接