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

时间:2009-05-08 22:18:55

标签: c# timespan

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

TimeSpan dateDifference = endTime.Subtract(beginTime);

我现在如何使用C#以hh,mm mins,ss secs格式返回此字符串。

如果差异为00:06:32.4458750

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

14 个答案:

答案 0 :(得分:169)

我刚刚构建了一些TimeSpan Extension方法。以为我可以分享:

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;
}

答案 1 :(得分:118)

通过将其转换为日期时间,您可以获得本地化格式:

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

答案 2 :(得分:90)

这是最短的解决方案。

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

答案 3 :(得分:38)

TimeSpan.ToString()会为你做诀窍吗?如果没有,看起来该页面上的代码示例描述了如何自定义TimeSpan对象的格式。

答案 4 :(得分:32)

使用带有多个参数的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);
        }
    }
}

答案 5 :(得分:8)

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

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

只要时差不超过24小时,这就有效。

Today属性返回DateTime值,其中time组件为零,因此结果的时间分量为TimeSpan值。

答案 6 :(得分:8)

   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);
      }
   }

答案 7 :(得分:5)

根据the Microsoft documentation,TimeSpan结构将小时,分钟,秒和毫秒作为整数成员公开。也许你想要这样的东西:

dateDifference.Hours.ToString() + " hrs, " + dateDifference.Minutes.ToString() + " mins, " + dateDifference.Seconds.ToString() + " secs"

答案 8 :(得分:4)

感谢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;
        }
    }
}

答案 9 :(得分:4)

您可以使用以下代码。

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);
  }
}

答案 10 :(得分:3)

我知道这个问题比较旧,但.Net 4现在支持Custom TimeSpan formats

我也知道它已被提及,但它让我感到震惊,将Ticks转换为DateTime可以正常工作,但是不能正常处理24小时以上。

new DateTime((DateTime.Now - DateTime.Now.AddHours(-25)).Ticks).ToString("HH:mm")

这将使你得到01:00而不是25:00,正如你所料。

答案 11 :(得分:2)

我也有类似的问题,想出了我自己的扩展,但它似乎与其他所有内容有所不同。

    public static string TimeSpanToString(this TimeSpan timeSpan)
    {
        //if it's negative
        if (timeSpan.Ticks < 0)
        {
            timeSpan = timeSpan - timeSpan - timeSpan;
            if (timeSpan.Days != 0)
                return string.Format("-{0}:{1}", timeSpan.Days.ToString("d"), new DateTime(timeSpan.Ticks).ToString("HH:mm:ss"));
            else
                return new DateTime(timeSpan.Ticks).ToString("-HH:mm:ss");
        }

        //if it has days
        else if (timeSpan.Days != 0)
            return string.Format("{0}:{1}", timeSpan.Days.ToString("d"), new DateTime(timeSpan.Ticks).ToString("HH:mm:ss"));

        //otherwise return the time
        else
            return new DateTime(timeSpan.Ticks).ToString("HH:mm:ss");
    }

答案 12 :(得分:0)

我知道这是一个迟到的答案,但这对我有用:

TimeSpan dateDifference = new TimeSpan(0,0,0, (int)endTime.Subtract(beginTime).TotalSeconds); 

dateDifference现在应该排除小于一秒的部分。也适用于.net 2.0。

答案 13 :(得分:-11)

''' <summary>
''' Return specified Double # (NumDbl) as String using specified Number Format String (FormatStr, 
''' Default = "N0") and Format Provider (FmtProvider, Default = Nothing) followed by space and,  
''' if NumDbl = 1, the specified Singular Unit Name (SglUnitStr), else the Plural Unit Name 
''' (PluralUnitStr).
''' </summary>
''' <param name="NumDbl"></param>
''' <param name="SglUnitStr"></param>
''' <param name="PluralUnitStr"></param>
''' <param name="FormatStr"></param>
''' <param name="FmtProvider"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function PluralizeUnitsStr( _
    ByVal NumDbl As Double, _
    ByVal SglUnitStr As String, _
    ByVal PluralUnitStr As String, _
    Optional ByVal FormatStr As String = "N0", _
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _
    ) As String

    PluralizeUnitsStr = NumDbl.ToString(FormatStr, FmtProvider) & " "

    Dim RsltUnitStr As String

    If NumDbl = 1 Then
        RsltUnitStr = SglUnitStr
    Else
        RsltUnitStr = PluralUnitStr
    End If

    PluralizeUnitsStr &= RsltUnitStr

End Function

''' <summary>
''' Info about a # Unit.
''' </summary>
''' <remarks></remarks>
Public Class clsNumUnitInfoItem
    ''' <summary>
    ''' Name of a Singular Unit (i.e. "day", "trillion", "foot")
    ''' </summary>
    ''' <remarks></remarks>
    Public UnitSglStr As String

    ''' <summary>
    ''' Name of a Plural Unit (i.e. "days", "trillion", "feet")
    ''' </summary>
    ''' <remarks></remarks>
    Public UnitPluralStr As String

    ''' <summary>
    ''' # of Units to = 1 of Next Higher (aka Parent) Unit (i.e. 24 "hours", 1000 "million", 
    ''' 5280 "feet")
    ''' </summary>
    ''' <remarks></remarks>
    Public UnitsInParentInt As Integer
End Class ' -- clsNumUnitInfoItem

Dim TimeLongEnUnitInfoItms As clsNumUnitInfoItem() = { _
    New clsNumUnitInfoItem With {.UnitSglStr = "day", .UnitPluralStr = "days", .UnitsInParentInt = 1}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "hour", .UnitPluralStr = "hours", .UnitsInParentInt = 24}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "minute", .UnitPluralStr = "minutes", .UnitsInParentInt = 60}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "second", .UnitPluralStr = "seconds", .UnitsInParentInt = 60}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "millisecond", .UnitPluralStr = "milliseconds", .UnitsInParentInt = 1000} _
    } ' -- Dim TimeLongEnUnitInfoItms

Dim TimeShortEnUnitInfoItms As clsNumUnitInfoItem() = { _
    New clsNumUnitInfoItem With {.UnitSglStr = "day", .UnitPluralStr = "days", .UnitsInParentInt = 1}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "hr", .UnitPluralStr = "hrs", .UnitsInParentInt = 24}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "min", .UnitPluralStr = "mins", .UnitsInParentInt = 60}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "sec", .UnitPluralStr = "secs", .UnitsInParentInt = 60}, _
    New clsNumUnitInfoItem With {.UnitSglStr = "msec", .UnitPluralStr = "msecs", .UnitsInParentInt = 1000} _
    } ' -- Dim TimeShortEnUnitInfoItms

''' <summary>
''' Convert a specified Double Number (NumDbl) to a long (aka verbose) format (i.e. "1 day, 
''' 2 hours, 3 minutes, 4 seconds and 567 milliseconds") with a specified Array of Time Unit 
''' Info Items (TimeUnitInfoItms), Conjunction (ConjStr, Default = "and"), Minimum Unit Level 
''' Shown (MinUnitLevInt) (0 to TimeUnitInfoItms.Length - 1, -1=All), Maximum Unit Level Shown 
''' (MaxUnitLevInt) (-1=All), Maximum # of Unit Levels Shown (MaxNumUnitLevsInt) (1 to 0 to 
''' TimeUnitInfoItms.Length - 1, 0=All) and Round Last Shown Units Up Flag (RoundUpBool).  
''' Suppress leading 0 Unit Levels.
''' </summary>
''' <param name="NumDbl"></param>
''' <param name="NumUnitInfoItms"></param>
''' <param name="ConjStr"></param>
''' <param name="MinUnitLevInt"></param>
''' <param name="MaxUnitLevInt"></param>
''' <param name="MaxNumUnitLevsInt"></param>
''' <param name="RoundUpBool"></param>
''' <param name="FormatStr"></param>
''' <param name="FmtProvider"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function NumToLongStr( _
    ByVal NumDbl As Double, _
    ByVal NumUnitInfoItms As clsNumUnitInfoItem(), _
    Optional ByVal ConjStr As String = "and", _
    Optional ByVal MinUnitLevInt As Integer = -1, _
    Optional ByVal MaxUnitLevInt As Integer = -1, _
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _
    Optional ByVal RoundUpBool As Boolean = False, _
    Optional ByVal FormatStr As String = "N0", _
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _
    ) As String
    NumToLongStr = ""

    Const TUnitDelimStr As String = ", "

    If (MinUnitLevInt < -1) OrElse (MinUnitLevInt >= NumUnitInfoItms.Length) Then
        Throw New Exception("Invalid MinUnitLevInt: " & MaxUnitLevInt)
    End If

    If (MaxUnitLevInt < -1) OrElse (MaxUnitLevInt >= NumUnitInfoItms.Length) Then
        Throw New Exception("Invalid MaxDetailLevelInt: " & MaxUnitLevInt)
    End If

    If (MaxNumUnitLevsInt < 0) OrElse (MaxNumUnitLevsInt > NumUnitInfoItms.Length) Then
        Throw New Exception("Invalid MaxNumUnitLevsInt: " & MaxNumUnitLevsInt)
    End If

    Dim PrevNumUnitsDbl As Double = NumDbl
    Dim CurrUnitLevInt As Integer = -1
    Dim NumUnitLevsShownInt As Integer = 0

    For Each UnitInfoItem In NumUnitInfoItms
        CurrUnitLevInt += 1

        With UnitInfoItem

            Dim CurrNumUnitsDbl As Double = PrevNumUnitsDbl * .UnitsInParentInt
            Dim CurrTruncNumUnitsInt As Integer = Math.Truncate(CurrNumUnitsDbl)
            PrevNumUnitsDbl = CurrNumUnitsDbl
            If CurrUnitLevInt < MinUnitLevInt Then Continue For
            PrevNumUnitsDbl -= CurrTruncNumUnitsInt

            'If (CurrUnitLevInt > TimeUnitInfoItms.Length) _
            '    OrElse _
            '    ( _
            '    (CurrUnitLevInt > MaxUnitLevInt) AndAlso _
            '    (MaxUnitLevInt <> -1) _
            '    ) _
            '    OrElse _
            '    ( _
            '    (NumUnitLevsShownInt + 1 > MaxNumUnitLevsInt) AndAlso _
            '    (MaxNumUnitLevsInt <> 0) _
            '    ) Then Exit For

            If (CurrUnitLevInt = (NumUnitInfoItms.Length - 1)) OrElse _
                (CurrUnitLevInt = MaxUnitLevInt) OrElse _
                ((NumUnitLevsShownInt + 1) = MaxNumUnitLevsInt) Then

                If NumUnitLevsShownInt > 0 Then
                    Dim TUnitDelimStrLenInt As Integer = TUnitDelimStr.Length
                    NumToLongStr = NumToLongStr.Remove( _
                        NumToLongStr.Length - TUnitDelimStrLenInt, _
                        TUnitDelimStrLenInt)
                    NumToLongStr &= " " & ConjStr & " "
                End If

                Dim CurrNunUnitsRoundedInt As Integer
                If RoundUpBool Then
                    If CurrNumUnitsDbl <> CurrTruncNumUnitsInt Then
                        CurrNunUnitsRoundedInt = CurrTruncNumUnitsInt + 1
                    Else
                        CurrNunUnitsRoundedInt = CurrTruncNumUnitsInt
                    End If
                Else
                    CurrNunUnitsRoundedInt = Math.Round( _
                        value:=CurrNumUnitsDbl, mode:=MidpointRounding.AwayFromZero)
                End If

                NumToLongStr &= _
                    PluralizeUnitsStr(CurrNunUnitsRoundedInt, _
                        .UnitSglStr, .UnitPluralStr, FormatStr, FmtProvider)
                Exit For

            Else ' -- Not (MaxUnitLevInt or MaxNumUnitLevsInt)

                If NumUnitLevsShownInt > 0 OrElse CurrTruncNumUnitsInt <> 0 Then
                    NumToLongStr &= _
                        PluralizeUnitsStr(CurrTruncNumUnitsInt, _
                            .UnitSglStr, .UnitPluralStr, FormatStr, FmtProvider) & _
                        TUnitDelimStr
                    NumUnitLevsShownInt += 1
                End If

            End If ' -- Else Not (MaxUnitLevInt or MaxNumUnitLevsInt)

        End With ' -- UnitInfoItem

    Next UnitInfoItem

End Function

''' <summary>
''' Call NumToLongStr with a specified TimeSpan's (TS) TotalDays.
''' </summary>
''' <param name="TS"></param>
''' <param name="TimeUnitInfoItms"></param>
''' <param name="ConjStr"></param>
''' <param name="MinUnitLevInt"></param>
''' <param name="MaxUnitLevInt"></param>
''' <param name="MaxNumUnitLevsInt"></param>
''' <param name="RoundUpBool"></param>
''' <param name="FormatStr"></param>
''' <param name="FmtProvider"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function TimeSpanToStr( _
    ByVal TS As TimeSpan, _
    ByVal TimeUnitInfoItms As clsNumUnitInfoItem(), _
    Optional ByVal ConjStr As String = "and", _
    Optional ByVal MinUnitLevInt As Integer = -1, _
    Optional ByVal MaxUnitLevInt As Integer = -1, _
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _
    Optional ByVal RoundUpBool As Boolean = False, _
    Optional ByVal FormatStr As String = "N0", _
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _
    ) As String

    Return NumToLongStr( _
        NumDbl:=TS.TotalDays, _
        NumUnitInfoItms:=TimeUnitInfoItms, _
        ConjStr:=ConjStr, _
        MinUnitLevInt:=MinUnitLevInt, _
        MaxUnitLevInt:=MaxUnitLevInt, _
        MaxNumUnitLevsInt:=MaxNumUnitLevsInt, _
        RoundUpBool:=RoundUpBool, _
        FormatStr:=FormatStr, _
        FmtProvider:=FmtProvider _
        )

End Function

''' <summary>
''' Call TimeSpanToStr with TimeLongEnUnitInfoItms.
''' </summary>
''' <param name="TS"></param>
''' <param name="MinUnitLevInt"></param>
''' <param name="MaxUnitLevInt"></param>
''' <param name="MaxNumUnitLevsInt"></param>
''' <param name="RoundUpBool"></param>
''' <param name="FormatStr"></param>
''' <param name="FmtProvider"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Function TimeSpanToLongEnStr( _
    ByVal TS As TimeSpan, _
    Optional ByVal MinUnitLevInt As Integer = -1, _
    Optional ByVal MaxUnitLevInt As Integer = -1, _
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _
    Optional ByVal RoundUpBool As Boolean = False, _
    Optional ByVal FormatStr As String = "N0", _
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _
    ) As String

    Return TimeSpanToStr( _
        TS:=TS, _
        TimeUnitInfoItms:=TimeLongEnUnitInfoItms, _
        MinUnitLevInt:=MinUnitLevInt, _
        MaxUnitLevInt:=MaxUnitLevInt, _
        MaxNumUnitLevsInt:=MaxNumUnitLevsInt, _
        RoundUpBool:=RoundUpBool, _
        FormatStr:=FormatStr, _
        FmtProvider:=FmtProvider _
        )
End Function