123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- using System;
- using System.Collections.Generic;
- namespace InABox.Core
- {
- /// <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}}}";
- /// <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);
- var span = (TimeSpan)arg;
- var formatSegments = format.Split(new[] { ',' }, 2);
- var tsFormat = formatSegments[0].ToLower();
- if (!string.IsNullOrWhiteSpace(tsFormat))
- {
- var results = new List<string>();
- 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 (Exception e)
- {
- return GetDefault(format, arg);
- }
- }
- return span.ToString();
- }
- /// <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>
- /// 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);
- }
- }
- }
|