TimeSpanFormatter.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using System.Collections.Generic;
  3. namespace InABox.Core
  4. {
  5. /// <summary>
  6. /// Custom string formatter for TimeSpan that allows easy retrieval of Total segments.
  7. /// </summary>
  8. /// <example>
  9. /// TimeSpan myTimeSpan = new TimeSpan(27, 13, 5);
  10. /// string.Format("{0:th,###}h {0:mm}m {0:ss}s", myTimeSpan) -> "27h 13m 05s"
  11. /// string.Format("{0:TH}", myTimeSpan) -> "27.2180555555556"
  12. /// NOTE: myTimeSpan.ToString("TH") does not work. See Remarks.
  13. /// </example>
  14. /// <remarks>
  15. /// Due to a quirk of .NET Framework (up through version 4.5.1),
  16. /// <code>TimeSpan.ToString(format, new TimeSpanFormatter())</code> will not work; it will always call
  17. /// TimeSpanFormat.FormatCustomized() which takes a DateTimeFormatInfo rather than an
  18. /// IFormatProvider/ICustomFormatter. DateTimeFormatInfo, unfortunately, is a sealed class.
  19. /// </remarks>
  20. public class TimeSpanFormatter : IFormatProvider, ICustomFormatter
  21. {
  22. /// <summary>
  23. /// Used to create a wrapper format string with the specified format.
  24. /// </summary>
  25. private const string DefaultFormat = "{{0:{0}}}";
  26. /// <summary>
  27. /// Determines whether the specified format is looking for a total, and formats it accordingly.
  28. /// If not, returns the default format for the given
  29. /// <para>format</para>
  30. /// of a TimeSpan.
  31. /// </summary>
  32. /// <returns>
  33. /// The formatted string for the given TimeSpan.
  34. /// </returns>
  35. /// <remarks>
  36. /// ICustomFormatter.Format implementation.
  37. /// </remarks>
  38. public string Format(string format, object arg, IFormatProvider formatProvider)
  39. {
  40. // only apply our format if there is a format and if the argument is a TimeSpan
  41. if (string.IsNullOrWhiteSpace(format) ||
  42. formatProvider != this || // this should always be true, but just in case...
  43. !(arg is TimeSpan) ||
  44. arg == null)
  45. // return the default for whatever our format and argument are
  46. return GetDefault(format, arg);
  47. var span = (TimeSpan)arg;
  48. var formatSegments = format.Split(new[] { ',' }, 2);
  49. var tsFormat = formatSegments[0].ToLower();
  50. if (!string.IsNullOrWhiteSpace(tsFormat))
  51. {
  52. var results = new List<string>();
  53. var segments = tsFormat.Replace("\\", "").Split(':');
  54. try
  55. {
  56. foreach (var segment in segments)
  57. if (segment.Equals("d"))
  58. results.Add(span.Days.ToString());
  59. else if (segment.Equals("dd"))
  60. results.Add(span.Days.ToString("D2"));
  61. else if (segment.Equals("h"))
  62. results.Add(span.Hours.ToString());
  63. else if (segment.Equals("hh"))
  64. results.Add(span.Hours.ToString("D2"));
  65. else if (segment.Equals("hhh"))
  66. results.Add(((int)span.TotalHours).ToString());
  67. else if (segment.Equals("mm"))
  68. results.Add(span.Minutes.ToString("D2"));
  69. else if (segment.Equals("ss"))
  70. results.Add(span.Seconds.ToString("D2"));
  71. else if (segment.Equals("zzz"))
  72. results.Add(span.Milliseconds.ToString("D3"));
  73. return string.Join(":", results);
  74. }
  75. catch (Exception e)
  76. {
  77. return GetDefault(format, arg);
  78. }
  79. }
  80. return span.ToString();
  81. }
  82. /// <remarks>
  83. /// IFormatProvider.GetFormat implementation.
  84. /// </remarks>
  85. public object GetFormat(Type formatType)
  86. {
  87. // Determine whether custom formatting object is requested.
  88. if (formatType == typeof(ICustomFormatter)) return this;
  89. return null;
  90. }
  91. /// <summary>
  92. /// Returns the formatted value when we don't know what to do with their specified format.
  93. /// </summary>
  94. private string GetDefault(string format, object arg)
  95. {
  96. return string.Format(string.Format(DefaultFormat, format), arg);
  97. }
  98. }
  99. }