bin/projects/dbatools/dbatools/Utility/DbaTimeSpan.cs

using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Sqlcollaborative.Dbatools.Utility
{
    /// <summary>
    /// A wrapper class, encapsuling a regular TimeSpan object. Used to provide custom timespan display.
    /// </summary>
    public class DbaTimeSpan : IComparable, IComparable<TimeSpan>, IComparable<DbaTimeSpan>, IEquatable<TimeSpan>
    {
        internal TimeSpan _timespan;

        #region Properties
        /// <summary>
        /// Gets the days component of the time interval represented by the current TimeSpan structure.
        /// </summary>
        public int Days
        {
            get
            {
                return _timespan.Days;
            }
        }

        /// <summary>
        /// Gets the hours component of the time interval represented by the current TimeSpan structure.
        /// </summary>
        public int Hours
        {
            get
            {
                return _timespan.Hours;
            }
        }

        /// <summary>
        /// Gets the milliseconds component of the time interval represented by the current TimeSpan structure.
        /// </summary>
        public int Milliseconds
        {
            get
            {
                return _timespan.Milliseconds;
            }
        }

        /// <summary>
        /// Gets the minutes component of the time interval represented by the current TimeSpan structure.
        /// </summary>
        public int Minutes
        {
            get
            {
                return _timespan.Minutes;
            }
        }

        /// <summary>
        /// Gets the seconds component of the time interval represented by the current TimeSpan structure.
        /// </summary>
        public int Seconds
        {
            get
            {
                return _timespan.Seconds;
            }
        }

        /// <summary>
        /// Gets the number of ticks that represent the value of the current TimeSpan structure.
        /// </summary>
        public long Ticks
        {
            get
            {
                return _timespan.Ticks;
            }
        }

        /// <summary>
        /// Gets the value of the current TimeSpan structure expressed in whole and fractional days.
        /// </summary>
        public double TotalDays
        {
            get
            {
                return _timespan.TotalDays;
            }
        }

        /// <summary>
        /// Gets the value of the current TimeSpan structure expressed in whole and fractional hours.
        /// </summary>
        public double TotalHours
        {
            get
            {
                return _timespan.TotalHours;
            }
        }

        /// <summary>
        /// Gets the value of the current TimeSpan structure expressed in whole and fractional milliseconds.
        /// </summary>
        public double TotalMilliseconds
        {
            get
            {
                return _timespan.TotalMilliseconds;
            }
        }

        /// <summary>
        /// Gets the value of the current TimeSpan structure expressed in whole and fractional minutes.
        /// </summary>
        public double TotalMinutes
        {
            get
            {
                return _timespan.TotalMinutes;
            }
        }

        /// <summary>
        /// Gets the value of the current TimeSpan structure expressed in whole and fractional seconds.
        /// </summary>
        public double TotalSeconds
        {
            get
            {
                return _timespan.TotalSeconds;
            }
        }
        #endregion Properties

        #region Constructors
        /// <summary>
        ///
        /// </summary>
        /// <param name="Timespan"></param>
        public DbaTimeSpan(TimeSpan Timespan)
        {
            _timespan = Timespan;
        }

        /// <summary>
        /// Converts a string into a timespan
        /// </summary>
        /// <param name="Timespan">The string to convert</param>
        public DbaTimeSpan(string Timespan)
        {
            _timespan = ParseTimeSpan(Timespan);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ticks"></param>
        public DbaTimeSpan(long ticks)
        {
            _timespan = new TimeSpan(ticks);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="hours"></param>
        /// <param name="minutes"></param>
        /// <param name="seconds"></param>
        public DbaTimeSpan(int hours, int minutes, int seconds)
        {
            _timespan = new TimeSpan(hours, minutes, seconds);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="days"></param>
        /// <param name="hours"></param>
        /// <param name="minutes"></param>
        /// <param name="seconds"></param>
        public DbaTimeSpan(int days, int hours, int minutes, int seconds)
        {
            _timespan = new TimeSpan(days, hours, minutes, seconds);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="days"></param>
        /// <param name="hours"></param>
        /// <param name="minutes"></param>
        /// <param name="seconds"></param>
        /// <param name="milliseconds"></param>
        public DbaTimeSpan(int days, int hours, int minutes, int seconds, int milliseconds)
        {
            _timespan = new TimeSpan(days, hours, minutes, seconds, milliseconds);
        }
        #endregion Constructors

        #region Methods
        /// <summary>
        /// Parses an input string as timespan
        /// </summary>
        /// <param name="Value">The string to interpret</param>
        /// <returns>The interpreted timespan value</returns>
        internal static TimeSpan ParseTimeSpan(string Value)
        {
            if (String.IsNullOrWhiteSpace(Value))
                throw new ArgumentNullException("Cannot parse empty string!");

            try { return TimeSpan.Parse(Value, CultureInfo.CurrentCulture); }
            catch { }
            try { return TimeSpan.Parse(Value, CultureInfo.InvariantCulture); }
            catch { }

            bool positive = !(Value.Contains("-"));
            TimeSpan timeResult = new TimeSpan();
            string tempValue = Value.Replace("-", "").Trim();

            foreach (string element in tempValue.Split(' '))
            {
                if (Regex.IsMatch(element, @"^\d+$"))
                    timeResult = timeResult.Add(new TimeSpan(0, 0, Int32.Parse(element)));
                else if (UtilityHost.IsLike(element, "*ms") && Regex.IsMatch(element, @"^\d+ms$", RegexOptions.IgnoreCase))
                    timeResult = timeResult.Add(new TimeSpan(0, 0, 0, 0, Int32.Parse(Regex.Match(element, @"^(\d+)ms$", RegexOptions.IgnoreCase).Groups[1].Value)));
                else if (UtilityHost.IsLike(element, "*s") && Regex.IsMatch(element, @"^\d+s$", RegexOptions.IgnoreCase))
                    timeResult = timeResult.Add(new TimeSpan(0, 0, Int32.Parse(Regex.Match(element, @"^(\d+)s$", RegexOptions.IgnoreCase).Groups[1].Value)));
                else if (UtilityHost.IsLike(element, "*m") && Regex.IsMatch(element, @"^\d+m$", RegexOptions.IgnoreCase))
                    timeResult = timeResult.Add(new TimeSpan(0, Int32.Parse(Regex.Match(element, @"^(\d+)m$", RegexOptions.IgnoreCase).Groups[1].Value), 0));
                else if (UtilityHost.IsLike(element, "*h") && Regex.IsMatch(element, @"^\d+h$", RegexOptions.IgnoreCase))
                    timeResult = timeResult.Add(new TimeSpan(Int32.Parse(Regex.Match(element, @"^(\d+)h$", RegexOptions.IgnoreCase).Groups[1].Value), 0, 0));
                else if (UtilityHost.IsLike(element, "*d") && Regex.IsMatch(element, @"^\d+d$", RegexOptions.IgnoreCase))
                    timeResult = timeResult.Add(new TimeSpan(Int32.Parse(Regex.Match(element, @"^(\d+)d$", RegexOptions.IgnoreCase).Groups[1].Value), 0, 0, 0));
                else
                    throw new ArgumentException(String.Format("Failed to parse as timespan: {0} at {1}", Value, element));
            }

            if (!positive)
                return timeResult.Negate();
            return timeResult;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public TimeSpan Add(TimeSpan ts)
        {
            return _timespan.Add(ts);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int CompareTo(System.Object value)
        {
            return _timespan.CompareTo(value);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int CompareTo(TimeSpan value)
        {
            return _timespan.CompareTo(value);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int CompareTo(DbaTimeSpan value)
        {
            return _timespan.CompareTo(value.GetBaseObject());
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public TimeSpan Duration()
        {
            return _timespan.Duration();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public override bool Equals(System.Object value)
        {
            return _timespan.Equals(value);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Equals(TimeSpan obj)
        {
            return _timespan.Equals(obj);
        }

        /// <summary>
        /// Returns the wrapped base object
        /// </summary>
        /// <returns>The base object</returns>
        public TimeSpan GetBaseObject()
        {
            return _timespan;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return _timespan.GetHashCode();
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public TimeSpan Negate()
        {
            return _timespan.Negate();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public TimeSpan Subtract(TimeSpan ts)
        {
            return _timespan.Subtract(ts);
        }

        /// <summary>
        /// Returns the default string representation of the TimeSpan object
        /// </summary>
        /// <returns>The string representation of the DbaTimeSpan object</returns>
        public override string ToString()
        {
            if (UtilityHost.DisableCustomTimeSpan) { return _timespan.ToString(); }
            else if (_timespan.Ticks % 10000000 == 0) { return _timespan.ToString(); }
            else
            {
                string temp = _timespan.ToString();

                if (_timespan.TotalSeconds < 10) { temp = temp.Substring(0, temp.LastIndexOf(".") + 3); }
                else if (_timespan.TotalSeconds < 100) { temp = temp.Substring(0, temp.LastIndexOf(".") + 2); }
                else { temp = temp.Substring(0, temp.LastIndexOf(".")); }

                return temp;
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="format"></param>
        /// <returns></returns>
        public string ToString(string format)
        {
            return _timespan.ToString(format);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="format"></param>
        /// <param name="formatProvider"></param>
        /// <returns></returns>
        public string ToString(string format, System.IFormatProvider formatProvider)
        {
            return _timespan.ToString(format, formatProvider);
        }
        #endregion Methods

        #region Implicit Operators
        /// <summary>
        /// Implicitly converts a DbaTimeSpan object into a TimeSpan object
        /// </summary>
        /// <param name="Base">The original object to revert</param>
        public static implicit operator TimeSpan(DbaTimeSpan Base)
        {
            try { return Base.GetBaseObject(); }
            catch { }
            return new TimeSpan();
        }

        /// <summary>
        /// Implicitly converts a TimeSpan object into a DbaTimeSpan object
        /// </summary>
        /// <param name="Base">The original object to wrap</param>
        public static implicit operator DbaTimeSpan(TimeSpan Base)
        {
            return new DbaTimeSpan(Base);
        }
        #endregion Implicit Operators
    }
}