Extension methods for the DateTime class.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace Extensions
{
    public static class DateTimeExtensions
    {
        private static readonly DateTime _date1970 = new DateTime(1970, 1, 1);

        private const int EVENING_ENDS = 2;
        private const int MORNING_ENDS = 12;
        private const int AFTERNOON_ENDS = 6;

        /// <summary>
        /// Gets the System UTC Offset.
        /// </summary>
        /// <value>The UTC offset.</value>
        public static double UtcOffset
        {
            get
            {
                return DateTime.Now.Subtract(DateTime.UtcNow).TotalHours;
            }
        }

        /// <summary>
        /// Converts a nullable date/time value to UTC.
        /// </summary>
        /// <param name="dateTime">The nullable date/time</param>
        /// <returns>The nullable date/time in UTC</returns>
        public static DateTime? ToUniversalTime(this DateTime? dateTime)
        {
            return dateTime.HasValue ? dateTime.Value.ToUniversalTime() : (DateTime?)null;
        }

        /// <summary>
        /// Converts a nullable UTC date/time value to local time.
        /// </summary>
        /// <param name="dateTime">The nullable UTC date/time</param>
        /// <returns>The nullable UTC date/time as local time</returns>
        public static DateTime? ToLocalTime(this DateTime? dateTime)
        {
            return dateTime.HasValue ? dateTime.Value.ToLocalTime() : (DateTime?)null;
        }

        public static long ToJavaScriptTicks(this DateTime dateTime)
        {
            DateTimeOffset utcDateTime = dateTime.ToUniversalTime();
            long javaScriptTicks = (utcDateTime.Ticks - BeginOfEpoch.Ticks) / (long)10000;
            return javaScriptTicks;
        }

        /// <summary>
        /// Determines whether the specified DateTime object occurs on a weekend.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <returns></returns>
        public static bool IsWeekend(this DateTime self)
        {
            return (self.DayOfWeek == DayOfWeek.Sunday || self.DayOfWeek == DayOfWeek.Saturday);
        }

        /// <summary>
        /// Determines whether the specified DayOfWeek occurs on a weekend.
        /// </summary>
        /// <param name="self">The Day of Week.</param>
        /// <returns></returns>
        public static bool IsWeekend(this DayOfWeek self)
        {
            return !self.IsWeekday();
        }

        /// <summary>
        /// Determines whether the specified DateTime occurs on a week day.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <returns></returns>
        public static bool IsWeekday(this DateTime self)
        {
            return !self.IsWeekend();
        }

        /// <summary>
        /// Determines whether the specified DayOfWeek occurs on a week day.
        /// </summary>
        /// <param name="self">The DayOfWeek.</param>
        /// <returns></returns>
        public static bool IsWeekday(this DayOfWeek self)
        {
            switch (self)
            {
                case DayOfWeek.Sunday:
                case DayOfWeek.Saturday:
                    return false;
                default:
                    return true;
            }
        }

        /// <summary>
        /// Add number of working days to a DateTime.
        /// </summary>
        /// <param name="self">The self.</param>
        /// <param name="days">The days.</param>
        /// <example>
        ///     // due date is in 10 working days.
        ///     DateTime due = DateTime.Today.AddWorkDays(10);
        /// </example>
        /// <remarks>Does not take into account holidays.</remarks>
        /// <returns></returns>
        public static DateTime AddWorkDays(this DateTime self, int days)
        {
            // start from a weekday
            while (self.DayOfWeek.IsWeekday())
            {
                self = self.AddDays(1.0);
            }

            for (int i = 0; i < days; ++i)
            {
                self = self.AddDays(1.0);
                while (self.DayOfWeek.IsWeekday())
                {
                    self = self.AddDays(1.0);
                }
            }

            return self;
        }

        /// <summary>
        /// Determines if the date is between the two provided dates.
        ///
        /// Example:
        ///     var today = DateTime.Now;
        ///     var start = new DateTime(2012, 1, 1);
        ///     var end = new DateTime(2013, 11, 25);
        ///
        ///     Boolean isBetween = today.IsBetween(start, end);
        /// </summary>
        /// <param name="self">The self.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <param name="compareTime">The compare time.</param>
        /// <returns></returns>
        public static Boolean IsBetween(this DateTime self, DateTime startDate, DateTime endDate, Boolean compareTime = false)
        {
               return compareTime ?
                                self >= startDate && self <= endDate :
                                   self.Date >= startDate.Date && self.Date <= endDate.Date;
        }

        /// <summary>
        /// Determines if a DateTime is within a given DateTime range.
        /// </summary>
        /// <param name="self">The current DateTime.</param>
        /// <param name="beginDate">The beginning DateTime.</param>
        /// <param name="endDate">The ending DateTime.</param>
        /// <example>
        ///     var monday = DateTime.Now.ThisWeekMonday();
        ///     var friday = DateTime.Now.ThisWeekFriday();
        ///
        ///     If (DateTime.Now.IsInRange(monday, friday)
        ///         // do something...
        /// </example>
        /// <returns></returns>
        public static bool IsInRange(this DateTime self, DateTime beginDate, DateTime endDate)
        {
            return (self >= beginDate && self <= endDate);
        }

        /// <summary>
        /// Determines whether the set year is a Leap Year.
        /// </summary>
        /// <example>
        ///     bool isLeap = DateTime.Today.IsLeapYear();
        /// </example>
        /// <param name="self">The datetime object.</param>
        /// <returns>True if it is a Leap Year, otherwise false.</returns>
        public static bool IsLeapYear(this DateTime self)
        {
            return (DateTime.DaysInMonth(self.Year, 2) == 29);
        }

        /// <summary>
        /// Determines whether the DateTime value is the Leap Day.
        /// </summary>
        /// <example>
        ///     bool isLeapDay = new DateTime(2012, 2, 29).IsLeapDay();
        /// </example>
        /// <param name="self">The DateTime object.</param>
        /// <returns></returns>
        public static Boolean IsLeapDay(this DateTime self)
        {
            return(self.Month == 2 && self.Day == 29);
        }

        /// <summary>
        /// Determines whether the given date is the last day of the month.
        /// </summary>
        /// <example>
        ///     var isLastDay = DateTime.Now.IsLastDayOfMonth()
        /// </example>
        /// <param name="self">The self.</param>
        /// <returns></returns>
        public static bool IsLastDayOfMonth(this DateTime self)
        {
            return self == new DateTime(self.Year, self.Month, 1).AddMonths(1).AddDays(-1);
        }

        /// <summary>
        /// Determines if the two date ranges intersect.
        ///
        /// Example:
        ///     bool eventsInterect = eventXStartDate.Intersects(eventXEndDate, eventYStartDate, eventYEndDate);
        /// </summary>
        /// <param name="self">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <param name="intersectingStartDate">The intersecting start date.</param>
        /// <param name="intersectingEndDate">The intersecting end date.</param>
        /// <returns></returns>
        public static bool Intersects(this DateTime self, DateTime endDate, DateTime intersectingStartDate, DateTime intersectingEndDate)
        {
            return (intersectingEndDate >= self && intersectingStartDate <= endDate);
        }

        /// <summary>
        /// Calculates the age based on today.
        /// </summary>
        /// <param name="self">The date of birth.</param>
        /// <returns>The calculated age.</returns>
        public static int Age(this DateTime self)
        {
            return Age(self, DateTime.Today.Date);
        }

        /// <summary>
        /// Calculates the age based on a passed reference date.
        /// </summary>
        /// <param name="self">The date of birth.</param>
        /// <param name="referenceDate">The reference date to calculate on.</param>
        /// <returns>The calculated age.</returns>
        public static int Age(this DateTime self, DateTime referenceDate)
        {
            int years = referenceDate.Year - self.Year;

            if (referenceDate.Month < self.Month ||
                (referenceDate.Month == self.Month && referenceDate.Day < self.Day))
            {
                --years;
            }

            return years;
        }

        /// <summary>
        /// Generates a humanized Age string.
        ///
        /// Based on: http://stackoverflow.com/a/3055445
        /// </summary>
        /// <param name="self">The DateTime.</param>
        /// <returns>ex: 1 day, </returns>
        public static string HumanizeAge(this DateTime self)
        {
            DateTime dt = DateTime.Today;

            int days = dt.Day - self.Day;
            if (days < 0)
            {
                dt = dt.AddMonths(-1);
                days += DateTime.DaysInMonth(dt.Year, dt.Month);
            }

            int months = dt.Month - self.Month;
            if (months < 0)
            {
                dt = dt.AddYears(-1);
                months += 12;
            }

            int years = dt.Year - self.Year;
            if (years <= 0)
            {
                if (months >= 1)
                {
                    return string.Format("{0} month{1} and {2} day{3}",
                        months,
                        (months == 1) ? "" : "s",
                        days,
                        (days == 1) ? "" : "s");
                }

                if (months <= 0)
                {
                    return string.Format("{0} day{1}",
                        days,
                        (days == 1) ? "" : "s");
                }
            }

            return string.Format("{0} year{1}, {2} month{3} and {4} day{5}",
                years,
                (years == 1) ? "" : "s",
                months,
                (months == 1) ? "" : "s",
                days,
                (days == 1) ? "" : "s");
        }

        /// <summary>
        /// Gets the date range to.
        ///
        /// Example: Get next 80 days
        ///     var dateRange = DateTime.Now.GetDateRangeTo(DateTime.Now.AddDays(80));
        /// </summary>
        /// <param name="self">The self.</param>
        /// <param name="toDate">To date.</param>
        /// <returns></returns>
        public static IEnumerable<DateTime> GetDateRangeTo(this DateTime self, DateTime toDate)
        {
            IEnumerable<int> range = Enumerable.Range(0, new TimeSpan(toDate.Ticks - self.Ticks).Days);

            return from p in range
                   select self.Date.AddDays(p);
        }

        /// <summary>
        /// Date diff (SQL style).
        ///</summary>
        /// <example>
        /// Accepted DateParts:
        ///
        ///     "year" (abbr. "yy", "yyyy")
        ///     "quarter" (abbr. "qq", "q")
        ///     "month" (abbr. "mm", "m")
        ///     "day" (abbr. "dd", "d")
        ///     "week" (abbr. "wk", "ww")
        ///     "hour" (abbr. "hh")
        ///     "minute" (abbr. "mi", "n")
        ///     "second" (abbr. "ss", "s")
        ///     "millisecond" (abbr. "ms")
        ///
        /// Examples:
        ///
        /// Gets the total days from 01/01/2000:
        ///
        ///     DateTime dt = new DateTime(2000, 01, 01);
        ///     Int64 days = dt.DateDiff("day", DateTime.Now);
        ///
        /// Gets the total hours from 01/01/2000:
        ///
        ///     Int64 hours = dt.DateDiff("hour", DateTime.Now);
        /// </example>
        /// <param name="startDate">The start date.</param>
        /// <param name="datePart">The date part.</param>
        /// <param name="endDate">The end date.</param>
        /// <returns></returns>
        public static long DateDiff(DateTime startDate, string datePart, DateTime endDate)
        {
            long dateDiffVal;
            Calendar cal = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
            var ts = new TimeSpan(endDate.Ticks - startDate.Ticks);

            switch (datePart.ToLower().Trim())
            {
                case "year":
                case "yy":
                case "yyyy":
                    dateDiffVal = (cal.GetYear(endDate) - cal.GetYear(startDate));
                    break;
                case "quarter":
                case "qq":
                case "q":
                    dateDiffVal = ((((cal.GetYear(endDate) -
                                      cal.GetYear(startDate)) * 4) +
                                    ((cal.GetMonth(endDate) - 1) / 3)) -
                                   ((cal.GetMonth(startDate) - 1) / 3));
                    break;
                case "month":
                case "mm":
                case "m":
                    dateDiffVal = (((cal.GetYear(endDate) - cal.GetYear(startDate)) * 12 +
                                    cal.GetMonth(endDate)) -
                                   cal.GetMonth(startDate));
                    break;
                case "day":
                case "d":
                case "dd":
                    dateDiffVal = (long)ts.TotalDays;
                    break;
                case "week":
                case "wk":
                case "ww":
                    dateDiffVal = (long)(ts.TotalDays / 7);
                    break;
                case "hour":
                case "hh":
                    dateDiffVal = (long)ts.TotalHours;
                    break;
                case "minute":
                case "mi":
                case "n":
                    dateDiffVal = (long)ts.TotalMinutes;
                    break;
                case "second":
                case "ss":
                case "s":
                    dateDiffVal = (long)ts.TotalSeconds;
                    break;
                case "millisecond":
                case "ms":
                    dateDiffVal = (long)ts.TotalMilliseconds;
                    break;
                default:
                    throw new Exception(String.Format("DatePart \"{0}\" is unknown.", datePart));
            }

            return dateDiffVal;
        }

        /// <summary>
        /// Converts a DateTime to a RFC822 date string.
        ///
        /// Example:
        ///     var s = DateTime.Now.ToRFC822DateString();
        /// </summary>
        /// <param name="self">The self.</param>
        /// <returns>The specified date formatted as a RFC822 date string.</returns>
        public static string ToRfc822DateString(this DateTime self)
        {
            int offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours;
            string timeZone = string.Format("+{0}", offset.ToString(CultureInfo.InvariantCulture).PadLeft(2, '0'));

            if (offset < 0)
            {
                int i = offset * -1;
                timeZone = string.Format("-{0}", i.ToString(CultureInfo.InvariantCulture).PadLeft(2, '0'));
            }

            return self.ToString(string.Format("ddd, dd MMM yyyy HH:mm:ss {0}", timeZone.PadRight(5, '0')), CultureInfo.GetCultureInfo("en-US"));
        }

        /// <summary>
        /// Get milliseconds of UNIX area.
        /// This is the milliseconds since 1/1/1970
        /// </summary>
        /// <param name="self">Up to which time.</param>
        /// <returns>number of milliseconds.</returns>
        public static long GetEpoch(this DateTime self)
        {
            TimeSpan ts = self.Subtract(_date1970);

            return (long)ts.TotalMilliseconds;
        }

        /// <summary>
        /// Get milliseconds of UNIX area.
        /// This is the milliseconds since 1/1/1970
        /// </summary>
        /// <param name="self">The date time.</param>
        /// <returns>number of milliseconds.</returns>
        /// <remarks>This is the same as GetEpoch,
        ///  but more descriptive.
        /// </remarks>
        public static long ToUnixTime(this DateTime self)
        {
            return GetEpoch(self);
        }

        /// <summary>
        /// Generates a DateTime object from a UNIX/Epoch timestamp value.
        /// DateTimeKind is UTC.
        /// See: http://stackoverflow.com/a/7844741
        ///
        /// </summary>
        /// <param name="self">The UNIX/Epoch timestamp value.</param>
        /// <returns></returns>
        public static DateTime FromUnixTime(this long self)
        {
            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return epoch.AddSeconds(self);
        }

        /// <summary>
        /// Generates a human friendly string from the DateTime object.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <param name="isUtc">Is the DateTime object in UTC?</param>
        /// <returns>A nicely formatted duration. ex: "3 seconds ago", "4 hours ago"</returns>
        public static string Humanize(this DateTime self, bool isUtc = false)
        {
            TimeSpan timespan = isUtc ? (DateTime.UtcNow - self) : (DateTime.Now - self);

            var totalDays = (int)timespan.TotalDays;
            var totalHours = (int)timespan.TotalHours;
            var totalMinutes = (int)timespan.TotalMinutes;
            var totalSeconds = (int)timespan.TotalSeconds;

            var sb = new StringBuilder();

            // A year or more?  Do "[Y] years and [M] months ago"
            if (totalDays >= 365)
            {
                // Years
                int nYears = totalDays / 365;
                sb.Append(nYears);
                sb.Append(nYears > 1 ? " years" : " year");

                // Months
                int remainingDays = totalDays - (nYears * 365);
                int nMonths = remainingDays / 30;
                if (nMonths == 1)
                {
                    sb.Append(" and ").Append(nMonths).Append(" month");
                }
                else if (nMonths > 1)
                {
                    sb.Append(" and ").Append(nMonths).Append(" months");
                }
            }
            // More than 60 days? (approx. 2 months or 8 weeks)
            else if (totalDays >= 60)
            {
                // Do months
                int nMonths = totalDays / 30;
                sb.Append(nMonths).Append(" months");
            }
            // Weeks? (7 days or more)
            else if (totalDays >= 7)
            {
                int nWeeks = totalDays / 7;
                sb.Append(nWeeks);
                sb.Append(nWeeks == 1 ? " week" : " weeks");
            }
            // Days? (1 or more)
            else if (totalDays >= 1)
            {
                int nDays = totalDays;
                sb.Append(nDays);
                sb.Append(nDays == 1 ? " day" : " days");
            }
            // Hours?
            else if (totalHours >= 1)
            {
                int nHours = totalHours;
                sb.Append(nHours);
                sb.Append(nHours == 1 ? " hour" : " hours");
            }
            // Minutes?
            else if (totalMinutes >= 1)
            {
                int nMinutes = totalMinutes;
                sb.Append(nMinutes);
                sb.Append(nMinutes == 1 ? " minute" : " minutes");
            }
            // Seconds?
            else if (totalSeconds >= 1)
            {
                int nSeconds = totalSeconds;
                sb.Append(nSeconds);
                sb.Append(nSeconds == 1 ? " second" : " seconds");
            }
            // Just say "1 second" as the smallest unit of time
            else
            {
                sb.Append("1 second");
            }

            sb.Append(" ago");

            // For anything more than 6 months back,
            // put "([Month] [Year])" at the end, for better reference
            if (totalDays >= 30 * 6)
            {
                sb.AppendFormat(" ({0} {1})", self.ToString("MMMM"), self.Year);
            }

            return sb.ToString();
        }

        /// <summary>
        /// Generates a human friendly string from the DateTime object.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <param name="sinceDate">The when date.</param>
        /// <returns>A nicely formatted duration. ex: "3 seconds ago", "4 hours ago"</returns>
        public static string Humanize(this DateTime self, DateTime sinceDate)
        {
            TimeSpan timespan = (self - sinceDate);

            var totalDays = (int)timespan.TotalDays;
            var totalHours = (int)timespan.TotalHours;
            var totalMinutes = (int)timespan.TotalMinutes;
            var totalSeconds = (int)timespan.TotalSeconds;

            var sb = new StringBuilder();

            // A year or more?  Do "[Y] years and [M] months ago"
            if (totalDays >= 365)
            {
                // Years
                int nYears = totalDays / 365;
                sb.Append(nYears);
                sb.Append(nYears > 1 ? " years" : " year");

                // Months
                int remainingDays = totalDays - (nYears * 365);
                int nMonths = remainingDays / 30;
                if (nMonths == 1)
                {
                    sb.Append(" and ").Append(nMonths).Append(" month");
                }
                else if (nMonths > 1)
                {
                    sb.Append(" and ").Append(nMonths).Append(" months");
                }
            }
            // More than 60 days? (approx. 2 months or 8 weeks)
            else if (totalDays >= 60)
            {
                // Do months
                int nMonths = totalDays / 30;
                sb.Append(nMonths).Append(" months");
            }
            // Weeks? (7 days or more)
            else if (totalDays >= 7)
            {
                int nWeeks = totalDays / 7;
                sb.Append(nWeeks);
                sb.Append(nWeeks == 1 ? " week" : " weeks");
            }
            // Days? (1 or more)
            else if (totalDays >= 1)
            {
                int nDays = totalDays;
                sb.Append(nDays);
                sb.Append(nDays == 1 ? " day" : " days");
            }
            // Hours?
            else if (totalHours >= 1)
            {
                int nHours = totalHours;
                sb.Append(nHours);
                sb.Append(nHours == 1 ? " hour" : " hours");
            }
            // Minutes?
            else if (totalMinutes >= 1)
            {
                int nMinutes = totalMinutes;
                sb.Append(nMinutes);
                sb.Append(nMinutes == 1 ? " minute" : " minutes");
            }
            // Seconds?
            else if (totalSeconds >= 1)
            {
                int nSeconds = totalSeconds;
                sb.Append(nSeconds);
                sb.Append(nSeconds == 1 ? " second" : " seconds");
            }
            // Just say "1 second" as the smallest unit of time
            else
            {
                sb.Append("1 second");
            }

            sb.Append(" ago");

            // For anything more than 6 months back,
            // put "([Month] [Year])" at the end, for better reference
            if (totalDays >= 30 * 6)
            {
                sb.AppendFormat(" ({0} {1})", self.ToString("MMMM"), self.Year);
            }

            return sb.ToString();
        }

        /// <summary>
        /// Represents dates in a user friendly way.
        ///
        /// For example, when displaying a news article on a webpage, you might want
        /// articles that were published one day ago to have their publish dates
        /// represented as "yesterday at 12:30 PM". Or if the article was publish today,
        /// show the date as "Today, 3:33 PM".
        /// </summary>
        /// <param name="self">The date.</param>
        /// <param name="culture">Specific Culture</param>
        /// <returns>ex: "yesterday at 12:30 PM"</returns>
        public static string ToFriendlyDateString(this DateTime self, CultureInfo culture)
        {
            var sbFormattedDate = new StringBuilder();

            if (self.Date == DateTime.Today)
            {
                sbFormattedDate.Append("Today");
            }
            else if (self.Date == DateTime.Today.AddDays(-1))
            {
                sbFormattedDate.Append("Yesterday");
            }
            else if (self.Date > DateTime.Today.AddDays(-6))
            {
                // *** Show the Day of the week
                sbFormattedDate.Append(self.ToString("dddd").ToString(culture));
            }
            else
            {
                sbFormattedDate.Append(self.ToString("MMMM dd, yyyy").ToString(culture));
            }

            //append the time portion to the output
            sbFormattedDate.Append(" at ").Append(self.ToString("t").ToLower());

            return sbFormattedDate.ToString();
        }

        /// <summary>
        /// Represents dates in a user friendly way.
        ///
        /// For example, when displaying a news article on a webpage, you might want
        /// articles that were published one day ago to have their publish dates
        /// represented as "yesterday at 12:30 PM". Or if the article was publish today,
        /// show the date as "Today, 3:33 PM".
        /// </summary>
        /// <param name="self">The date.</param>
        /// <returns>ex: "yesterday at 12:30 PM"</returns>
        public static string ToFriendlyDateString(this DateTime self)
        {
            return ToFriendlyDateString(self, CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Get the elapsed time since the DateTime object.
        /// </summary>
        /// <param name="self">Input DateTime</param>
        /// <param name="isUtc">Is the DateTime object in UTC?</param>
        /// <example>
        ///     DateTime dtStart = DateTime.Now;
        ///     // Do something here...
        ///     Console.WriteLine(dtStart.Elapsed().TotalMilliseconds);
        /// </example>
        /// <returns>
        /// Returns a TimeSpan value with the elapsed time since the self DateTime
        /// </returns>
        public static TimeSpan Elapsed(this DateTime self, bool isUtc = false)
        {
            return isUtc ? DateTime.UtcNow.Subtract(self) : DateTime.Now.Subtract(self);
        }

        /// <summary>
        /// Gest the elapsed seconds since the DateTime.
        /// </summary>
        /// <example>
        ///     DateTime dtStart = DateTime.Now;
        ///     // Do something
        ///     Double elapsed = dtStart.ElapsedSeconds();
        /// </example>
        /// <param name="self">The DateTime object.</param>
        /// <param name="isUtc">Is the DateTime object in UTC?</param>
        /// <returns></returns>
        public static Double ElapsedSeconds(this DateTime self, bool isUtc = false)
        {
            return isUtc ? DateTime.UtcNow.Subtract(self).TotalSeconds : DateTime.Now.Subtract(self).TotalSeconds;
        }

        /// <summary>
        /// Gest the elapsed seconds since the input DateTime.
        /// </summary>
        /// <param name="input">Input DateTime</param>
        /// <returns>Returns a Double value with the elapsed seconds since the input
        /// DateTime.
        /// </returns>
        /// <example>
        /// Double elapsed = dtStart.ElapsedSeconds();
        /// </example>
        /// <seealso cref="Elapsed()"/>
        public static Double ElapsedSeconds(this DateTime self)
        {
            return DateTime.Now.Subtract(self).TotalSeconds;
        }

        /// <summary>
        /// Gets a new DateTime object corresponding to first day
        /// of the month.
        /// </summary>
        /// <example>
        ///     var firstDay = DateTime.Now.MonthStart();
        /// </example>
        /// <param name="self">The DateTime object.</param>
        /// <returns></returns>
        public static DateTime MonthStart(this DateTime self)
        {
                        return new DateTime(self.Year, self.Month, 1);
        }

        /// <summary>
        /// Gets a new DateTime object corresponding to last day
        /// of the month.
        /// </summary>
        /// <example>
        ///     var lastDay = DateTime.Now.MonthEnd();
        /// </example>
        /// <param name="self">The DateTime object.</param>
        /// <returns></returns>
        public static DateTime MonthEnd(this DateTime self)
        {
            DateTime endOfTheMonth = new DateTime(self.Year, self.Month, 1).AddMonths(1).AddDays(-1);
            return endOfTheMonth;
        }

        /// <summary>
        /// Gets a DateTime object corresponding to the beginning of the day.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <example>
        ///     var dayBegins = DateTime.Now.DayStart();
        /// </example>
        /// <returns></returns>
        public static DateTime DayStart(this DateTime self)
        {
            return new DateTime(self.Year, self.Month, self.Day);
        }

        /// <summary>
        /// Gets a DateTime object corresponding to the end of the day.
        /// </summary>
        /// <param name="self">The DateTime object.</param>
        /// <example>
        ///     var dayEnds = DateTime.Now.DayEnd();
        /// </example>
        /// <returns></returns>
        public static DateTime DayEnd(this DateTime self)
        {
            return new DateTime(self.Year, self.Month, self.Day, 23, 59, 59, 999);
        }

        /// <summary>
        /// Returns the date at 12:00:00 for the specified DateTime
        /// </summary>
        /// <param name="time">The current date</param>
        /// <returns></returns>
        public static DateTime Noon(this DateTime time)
        {
            return time.SetTime(12, 0, 0);
        }

        /// <summary>
        /// Returns the date at 00:00:00 for the specified DateTime
        /// </summary>
        /// <param name="time">The current date</param>
        /// <returns></returns>
        public static DateTime Midnight(this DateTime time)
        {
            return time.SetTime(0, 0, 0, 0);
        }

        /// <summary>
        /// Get the number of days within that year.
        /// </summary>
        /// <param name="year">The year.</param>
        /// <returns>the number of days within that year</returns>
        public static int GetDays(int year)
        {
            return GetDays(year, CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Get the number of days within that year.
        /// Uses the culture specified.
        /// </summary>
        /// <param name="year">The year.</param>
        /// <param name="culture">Specific culture</param>
        /// <returns>the number of days within that year</returns>
        public static int GetDays(int year, CultureInfo culture)
        {
            var first = new DateTime(year, 1, 1, culture.Calendar);
            var last = new DateTime(year + 1, 1, 1, culture.Calendar);

            return GetDays(first, last);
        }

        /// <summary>
        /// Get the number of days within that date year.
        /// </summary>
        /// <param name="self">The date.</param>
        /// <returns>the number of days within that year</returns>
        public static int GetDays(this DateTime self)
        {
            return GetDays(self.Year, CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Get the number of days within that date year.
        /// </summary>
        /// <param name="self">The date.</param>
        /// <param name="culture">Specific culture</param>
        /// <returns>the number of days within that year</returns>
        public static int GetDays(this DateTime self, CultureInfo culture)
        {
            return GetDays(self.Year, culture);
        }

        /// <summary>
        /// Get the number of days between two dates.
        /// </summary>
        /// <param name="self">The origin year.</param>
        /// <param name="toDate">To year</param>
        /// <returns>The number of days between the two years</returns>
        public static int GetDays(this DateTime self, DateTime toDate)
        {
            return Convert.ToInt32(toDate.Subtract(self).TotalDays);
        }

        /// <summary>
        /// Returns the number of days in the month of the provided date.
        /// </summary>
        /// <param name="self">The date.</param>
        /// <returns>The number of days.</returns>
        public static int GetCountDaysOfMonth(this DateTime self)
        {
            DateTime nextMonth = self.AddMonths(1);

            return new DateTime(nextMonth.Year, nextMonth.Month, 1).AddDays(-1).Day;
        }

        /// <summary>
        /// Indicates whether the source DateTime is before the supplied DateTime.
        /// </summary>
        /// <param name="self">The source DateTime.</param>
        /// <param name="other">The compared DateTime.</param>
        /// <returns>True if the source is before the other DateTime, False otherwise</returns>
        public static bool IsBefore(this DateTime self, DateTime other)
        {
            return self.CompareTo(other) < 0;
        }

        /// <summary>
        /// Indicates whether the source DateTime is before the supplied DateTime.
        /// </summary>
        /// <param name="self">The source DateTime.</param>
        /// <param name="other">The compared DateTime.</param>
        /// <returns>True if the source is before the other DateTime, False otherwise</returns>
        public static bool IsAfter(this DateTime self, DateTime other)
        {
            return self.CompareTo(other) > 0;
        }

        /// <summary>
        /// Gets a DateTime representing Next Day.
        /// </summary>
        /// <param name="self">The current day</param>
        /// <returns>The next Day.</returns>
        public static DateTime Tomorrow(this DateTime self)
        {
            return self.AddDays(1);
        }

        /// <summary>
        /// Gets a DateTime representing Previous Day.
        /// </summary>
        /// <param name="self">The current day</param>
        /// <returns>The previous Day.</returns>
        public static DateTime Yesterday(this DateTime self)
        {
            return self.AddDays(-1);
        }

        /// <summary>
        /// Indicates whether the date is today.
        /// </summary>
        /// <param name="self">The date.</param>
        /// <returns>
        /// <c>true</c> if the specified date is today; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsToday(this DateTime self)
        {
            return (self.Date == DateTime.Today);
        }

        /// <summary>
        /// Sets the time on the specified DateTime value.
        /// </summary>
        /// <param name="self">The base date.</param>
        /// <param name="hours">The hours to be set.</param>
        /// <param name="minutes">The minutes to be set.</param>
        /// <param name="seconds">The seconds to be set.</param>
        /// <returns>The DateTime including the new time value</returns>
        public static DateTime SetTime(this DateTime self, int hours, int minutes, int seconds)
        {
            return self.SetTime(new TimeSpan(hours, minutes, seconds));
        }

        /// <summary>
        /// Sets the time on the specified DateTime value.
        /// </summary>
        /// <param name="self">The base date.</param>
        /// <param name="hours">The hour</param>
        /// <param name="minutes">The minute</param>
        /// <param name="seconds">The second</param>
        /// <param name="milliseconds">The millisecond</param>
        /// <remarks>Added overload for milliseconds - jtolar</remarks>
        /// <returns>The DateTime including the new time value</returns>
        public static DateTime SetTime(this DateTime self, int hours, int minutes, int seconds, int milliseconds)
        {
            return self.SetTime(new TimeSpan(0, hours, minutes, seconds, milliseconds));
        }

        /// <summary>
        /// Sets the time on the specified DateTime value.
        /// </summary>
        /// <param name="self">The base date.</param>
        /// <param name="time">The TimeSpan to be applied.</param>
        /// <returns>The DateTime including the new time value</returns>
        public static DateTime SetTime(this DateTime self, TimeSpan time)
        {
            return self.Date.Add(time);
        }

        /// <summary>
        /// Converts a DateTime into a DateTimeOffset using the local system time zone.
        /// </summary>
        /// <param name="self">The local DateTime.</param>
        /// <returns>The converted DateTimeOffset</returns>
        public static DateTimeOffset ToDateTimeOffset(this DateTime self)
        {
            return self.ToDateTimeOffset(null);
        }

        /// <summary>
        /// Converts a DateTime into a DateTimeOffset using the specified time zone.
        /// </summary>
        /// <param name="self">The local DateTime.</param>
        /// <param name="localTimeZone">The local time zone.</param>
        /// <returns>The converted DateTimeOffset</returns>
        public static DateTimeOffset ToDateTimeOffset(this DateTime self, TimeZoneInfo localTimeZone)
        {
            localTimeZone = (localTimeZone ?? TimeZoneInfo.Local);

            if (self.Kind != DateTimeKind.Unspecified)
            {
                self = new DateTime(self.Ticks, DateTimeKind.Unspecified);
            }

            return TimeZoneInfo.ConvertTimeToUtc(self, localTimeZone);
        }

        /// <summary>
        /// Return a period "Morning", "Afternoon", or "Evening"
        /// </summary>
        /// <param name="self">The date.</param>
        /// <returns>The period "morning", "afternoon", or "evening"</returns>
        public static string GetPeriodOfDay(this DateTime self)
        {
            int hour = self.Hour;

            if (hour < EVENING_ENDS)
            {
                return "evening";
            }

            if (hour < MORNING_ENDS)
            {
                return "morning";
            }

            return hour < AFTERNOON_ENDS ? "afternoon" : "evening";
        }

        public static int TotalDaysAgo(this DateTimeOffset d)
        {
            return Convert.ToInt32(Math.Round(DateTimeOffset.Now.Subtract(d).TotalDays));
        }
    }
}