格式化TimeSpan大于24小时
假设我将这些秒转换成TimeSpan对象,如下所示:
Dim sec = 1254234568
Dim t As TimeSpan = TimeSpan.FromSeconds(sec)
如何将TimeSpan对象格式化为如下格式:
>105hr 56mn 47sec
是否有内置函数或需要编写自定义函数?
那么,最简单的做法就是自己设置格式,例如
return string.Format("{0}hr {1}mn {2}sec",
(int) span.TotalHours,
span.Minutes,
span.Seconds);
在VB中:
Public Shared Function FormatTimeSpan(span As TimeSpan) As String
Return String.Format("{0}hr {1}mn {2}sec", _
CInt(Math.Truncate(span.TotalHours)), _
span.Minutes, _
span.Seconds)
End Function
我不知道.NET 4中的任何TimeSpan
格式是否会使这个更简单。
微软目前没有一个简单的格式字符串快捷键。 最简单的选项已被共享。
string.Format("{0}hr {1:mm}mn {1:ss}sec", (int)t.TotalHours, t);
但是,一个非常彻底的选项是为TimeSpan
实现您自己的ICustomFormatter
。 我不会推荐它,除非你经常使用它,从长远来看它会节省你的时间。 但是,有时候你会写一个自己编写ICustomFormatter
的类,因此我以此为例。
/// <summary>
/// Custom string formatter for TimeSpan that allows easy retrieval of Total segments.
/// </summary>
/// <example>
/// TimeSpan myTimeSpan = new TimeSpan(27, 13, 5);
/// string.Format("{0:th,###}h {0:mm}m {0:ss}s", myTimeSpan) -> "27h 13m 05s"
/// string.Format("{0:TH}", myTimeSpan) -> "27.2180555555556"
///
/// NOTE: myTimeSpan.ToString("TH") does not work. See Remarks.
/// </example>
/// <remarks>
/// Due to a quirk of .NET Framework (up through version 4.5.1),
/// <code>TimeSpan.ToString(format, new TimeSpanFormatter())</code> will not work; it will always call
/// TimeSpanFormat.FormatCustomized() which takes a DateTimeFormatInfo rather than an
/// IFormatProvider/ICustomFormatter. DateTimeFormatInfo, unfortunately, is a sealed class.
/// </remarks>
public class TimeSpanFormatter : IFormatProvider, ICustomFormatter
{
/// <summary>
/// Used to create a wrapper format string with the specified format.
/// </summary>
private const string DefaultFormat = "{{0:{0}}}";
/// <remarks>
/// IFormatProvider.GetFormat implementation.
/// </remarks>
public object GetFormat(Type formatType)
{
// Determine whether custom formatting object is requested.
if (formatType == typeof(ICustomFormatter))
{
return this;
}
return null;
}
/// <summary>
/// Determines whether the specified format is looking for a total, and formats it accordingly.
/// If not, returns the default format for the given <para>format</para> of a TimeSpan.
/// </summary>
/// <returns>
/// The formatted string for the given TimeSpan.
/// </returns>
/// <remarks>
/// ICustomFormatter.Format implementation.
/// </remarks>
public string Format(string format, object arg, IFormatProvider formatProvider)
{
// only apply our format if there is a format and if the argument is a TimeSpan
if (string.IsNullOrWhiteSpace(format) ||
formatProvider != this || // this should always be true, but just in case...
!(arg is TimeSpan) ||
arg == null)
{
// return the default for whatever our format and argument are
return GetDefault(format, arg);
}
TimeSpan span = (TimeSpan)arg;
string[] formatSegments = format.Split(new char[] { ',' }, 2);
string tsFormat = formatSegments[0];
// Get inner formatting which will be applied to the int or double value of the requested total.
// Default number format is just to return the number plainly.
string numberFormat = "{0}";
if (formatSegments.Length > 1)
{
numberFormat = string.Format(DefaultFormat, formatSegments[1]);
}
// We only handle two-character formats, and only when those characters' capitalization match
// (e.g. 'TH' and 'th', but not 'tH'). Feel free to change this to suit your needs.
if (tsFormat.Length != 2 ||
char.IsUpper(tsFormat[0]) != char.IsUpper(tsFormat[1]))
{
return GetDefault(format, arg);
}
// get the specified time segment from the TimeSpan as a double
double valAsDouble;
switch (char.ToLower(tsFormat[1]))
{
case 'd':
valAsDouble = span.TotalDays;
break;
case 'h':
valAsDouble = span.TotalHours;
break;
case 'm':
valAsDouble = span.TotalMinutes;
break;
case 's':
valAsDouble = span.TotalSeconds;
break;
case 'f':
valAsDouble = span.TotalMilliseconds;
break;
default:
return GetDefault(format, arg);
}
// figure out if we want a double or an integer
switch (tsFormat[0])
{
case 'T':
// format Total as double
return string.Format(numberFormat, valAsDouble);
case 't':
// format Total as int (rounded down)
return string.Format(numberFormat, (int)valAsDouble);
default:
return GetDefault(format, arg);
}
}
/// <summary>
/// Returns the formatted value when we don't know what to do with their specified format.
/// </summary>
private string GetDefault(string format, object arg)
{
return string.Format(string.Format(DefaultFormat, format), arg);
}
}
请注意,正如代码中的注释一样, TimeSpan.ToString(format, myTimeSpanFormatter)
由于.NET Framework的怪异而不起作用,因此您将始终必须使用string.Format(format,myTimeSpanFormatter)来使用此类。 请参阅如何为DateTime创建和使用自定义IFormatProvider ?.
编辑 :如果你真的,我的意思是真的,希望这与TimeSpan.ToString(string, TimeSpanFormatter)
,你可以将以下内容添加到上面的TimeSpanFormatter
类中:
/// <remarks>
/// Update this as needed.
/// </remarks>
internal static string[] GetRecognizedFormats()
{
return new string[] { "td", "th", "tm", "ts", "tf", "TD", "TH", "TM", "TS", "TF" };
}
并在相同的命名空间中添加以下类:
public static class TimeSpanFormatterExtensions
{
private static readonly string CustomFormatsRegex = string.Format(@"([^])?({0})(?:,{{([^(}})]+)}})?", string.Join("|", TimeSpanFormatter.GetRecognizedFormats()));
public static string ToString(this TimeSpan timeSpan, string format, ICustomFormatter formatter)
{
if (formatter == null)
{
throw new ArgumentNullException();
}
TimeSpanFormatter tsFormatter = (TimeSpanFormatter)formatter;
format = Regex.Replace(format, CustomFormatsRegex, new MatchEvaluator(m => MatchReplacer(m, timeSpan, tsFormatter)));
return timeSpan.ToString(format);
}
private static string MatchReplacer(Match m, TimeSpan timeSpan, TimeSpanFormatter formatter)
{
// the matched non-'' char before the stuff we actually care about
string firstChar = m.Groups[1].Success ? m.Groups[1].Value : string.Empty;
string input;
if (m.Groups[3].Success)
{
// has additional formatting
input = string.Format("{0},{1}", m.Groups[2].Value, m.Groups[3].Value);
}
else
{
input = m.Groups[2].Value;
}
string replacement = formatter.Format(input, timeSpan, formatter);
if (string.IsNullOrEmpty(replacement))
{
return firstChar;
}
return string.Format("{0}{1}", firstChar, string.Join("", replacement.ToCharArray()));
}
}
在此之后,您可以使用
ICustomFormatter formatter = new TimeSpanFormatter();
string myStr = myTimeSpan.ToString(@"TH,{000.00}h:tmm:sss", formatter);
其中{000.00}
是您希望TotalHours int或double格式化的。 请注意括号中的大括号,它们不应该出现在string.Format()大小写中。 另请注意, formatter
必须声明(或ICustomFormatter
)为ICustomFormatter
而不是TimeSpanFormatter
。
过多? 是。 真棒? 唔....
string.Format("{0}hr {1}mn {2}sec", (int) t.TotalHours, t.Minutes, t.Seconds);