namespace Unosquare.Swan
{
using System;
///
/// Represents a struct of DateTimeSpan to compare dates and get in
/// separate fields the amount of time between those dates.
///
/// Based on https://stackoverflow.com/a/9216404/1096693.
///
public struct DateTimeSpan
{
///
/// Initializes a new instance of the struct.
///
/// The years.
/// The months.
/// The days.
/// The hours.
/// The minutes.
/// The seconds.
/// The milliseconds.
public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
{
Years = years;
Months = months;
Days = days;
Hours = hours;
Minutes = minutes;
Seconds = seconds;
Milliseconds = milliseconds;
}
///
/// Gets the years.
///
///
/// The years.
///
public int Years { get; }
///
/// Gets the months.
///
///
/// The months.
///
public int Months { get; }
///
/// Gets the days.
///
///
/// The days.
///
public int Days { get; }
///
/// Gets the hours.
///
///
/// The hours.
///
public int Hours { get; }
///
/// Gets the minutes.
///
///
/// The minutes.
///
public int Minutes { get; }
///
/// Gets the seconds.
///
///
/// The seconds.
///
public int Seconds { get; }
///
/// Gets the milliseconds.
///
///
/// The milliseconds.
///
public int Milliseconds { get; }
internal static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
{
if (date2 < date1)
{
var sub = date1;
date1 = date2;
date2 = sub;
}
var current = date1;
var years = 0;
var months = 0;
var days = 0;
var phase = Phase.Years;
var span = new DateTimeSpan();
var officialDay = current.Day;
while (phase != Phase.Done)
{
switch (phase)
{
case Phase.Years:
if (current.AddYears(years + 1) > date2)
{
phase = Phase.Months;
current = current.AddYears(years);
}
else
{
years++;
}
break;
case Phase.Months:
if (current.AddMonths(months + 1) > date2)
{
phase = Phase.Days;
current = current.AddMonths(months);
if (current.Day < officialDay &&
officialDay <= DateTime.DaysInMonth(current.Year, current.Month))
current = current.AddDays(officialDay - current.Day);
}
else
{
months++;
}
break;
case Phase.Days:
if (current.AddDays(days + 1) > date2)
{
current = current.AddDays(days);
var timespan = date2 - current;
span = new DateTimeSpan(
years,
months,
days,
timespan.Hours,
timespan.Minutes,
timespan.Seconds,
timespan.Milliseconds);
phase = Phase.Done;
}
else
{
days++;
}
break;
}
}
return span;
}
private enum Phase
{
Years,
Months,
Days,
Done,
}
}
}