using System;
using System.Collections.Generic;
namespace InABox.Core
{
///
/// Custom string formatter for TimeSpan that allows easy retrieval of Total segments.
///
///
/// 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.
///
///
/// Due to a quirk of .NET Framework (up through version 4.5.1),
/// TimeSpan.ToString(format, new TimeSpanFormatter())
will not work; it will always call
/// TimeSpanFormat.FormatCustomized() which takes a DateTimeFormatInfo rather than an
/// IFormatProvider/ICustomFormatter. DateTimeFormatInfo, unfortunately, is a sealed class.
///
public class TimeSpanFormatter : IFormatProvider, ICustomFormatter
{
///
/// Used to create a wrapper format string with the specified format.
///
private const string DefaultFormat = "{{0:{0}}}";
///
/// Determines whether the specified format is looking for a total, and formats it accordingly.
/// If not, returns the default format for the given
/// format
/// of a TimeSpan.
///
///
/// The formatted string for the given TimeSpan.
///
///
/// ICustomFormatter.Format implementation.
///
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);
var span = (TimeSpan)arg;
var formatSegments = format.Split(new[] { ',' }, 2);
var tsFormat = formatSegments[0].ToLower();
if (!string.IsNullOrWhiteSpace(tsFormat))
{
var results = new List();
var segments = tsFormat.Replace("\\", "").Split(':');
try
{
foreach (var segment in segments)
if (segment.Equals("d"))
results.Add(span.Days.ToString());
else if (segment.Equals("dd"))
results.Add(span.Days.ToString("D2"));
else if (segment.Equals("h"))
results.Add(span.Hours.ToString());
else if (segment.Equals("hh"))
results.Add(span.Hours.ToString("D2"));
else if (segment.Equals("hhh"))
results.Add(((int)span.TotalHours).ToString());
else if (segment.Equals("mm"))
results.Add(span.Minutes.ToString("D2"));
else if (segment.Equals("ss"))
results.Add(span.Seconds.ToString("D2"));
else if (segment.Equals("zzz"))
results.Add(span.Milliseconds.ToString("D3"));
return string.Join(":", results);
}
catch
{
return GetDefault(format, arg);
}
}
return span.ToString();
}
///
/// IFormatProvider.GetFormat implementation.
///
public object GetFormat(Type formatType)
{
// Determine whether custom formatting object is requested.
if (formatType == typeof(ICustomFormatter)) return this;
return null;
}
///
/// Returns the formatted value when we don't know what to do with their specified format.
///
private string GetDefault(string format, object arg)
{
return string.Format(string.Format(DefaultFormat, format), arg);
}
}
}