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

我有两个日期时间变量,开始时间和结束时间:

TimeSpan dateDifference = endTime.Subtract(beginTime);

现在如何使用 C # 以 hh hrs mm mins ss secs 格式返回这样的字符串。

如果差额是00:06:32.4458750

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

332211 次浏览

ToString ()会为你做这个魔术吗?如果没有,那么该页面上的代码示例似乎描述了如何对 TimeSpan对象进行自定义格式化。

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

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

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

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

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

根据 Microsoft 文档,TimeSpan 结构将小时、分钟、秒和毫秒作为整数成员公开:

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

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

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

我只是构建了一些 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;
}
   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);
}
}

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

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

Datedifferent 现在应该排除小于一秒的部分,在.net 2.0中也可以工作。

''' <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

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

我也遇到过类似的问题,我想出了自己的扩展,但它似乎有点不同于其他任何东西。

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

我知道这个问题比较老,但是.Net 4现在已经支持 自定义时间跨度格式了。

我也知道它被提到,但它抓住了我,转换 Ticks 到日期时间工作,但不能正确处理超过24小时的跨度。

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

那会让你一点到,而不是你所期望的25点。

您可以使用以下代码。

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

这是最短的解决方案。

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