Random random = new Random(); DateTime earlierDate = new DateTime(2006, 4, 15, 23, 0, 0); DateTime laterDate = new DateTime(2106, 04, 14, 23, 0, 0); int month = 0; while (laterDate > earlierDate) { DateTimeSpan dts = GetDateDiff(earlierDate, laterDate); if (dts.Months != month) { Console.WriteLine(laterDate); month = dts.Months; } DateTime calculatedDate = earlierDate.AddYears(dts.Years).AddMonths(dts.Months).AddDays(dts.Days) .AddHours(dts.Hours).AddMinutes(dts.Minutes).AddSeconds(dts.Seconds); if (calculatedDate != laterDate) throw new Exception("Crap code"); laterDate = laterDate.Subtract(new TimeSpan(0, 0, random.Next(60))); }and it chugged thro the 100 years at < I minute intervals without error.....
> public struct DateTimeSpan > : IEquatable<DateTimeSpan>, > IComparable, IComparable<DateTimeSpan> > { > #region Fields > //______________________________________________________________________ > private Int32 _Years; > public Int32 Years > { > get { return _Years; } > set > { > if (!value.Between(0, 9999)) > throw new ArgumentOutOfRangeException("Years", "between 0 and 9999"); > _Years = value ; > } > } > //______________________________________________________________________ > private byte _Months; > public Int32 Months > { > get { return _Months; } > set > { > if (!value.Between(0, 11)) > throw new ArgumentOutOfRangeException("Months", "between 0 and 11"); > _Months = unchecked((byte)value); > } > } > //______________________________________________________________________ > private byte _Days; > public Int32 Days > { > get { return _Days; } > set > { > if (!value.Between(0, 30)) > throw new ArgumentOutOfRangeException("Days", "between 0 and 30"); > _Days = unchecked((byte)value); > } > } > //______________________________________________________________________ > private byte _Hours; > public Int32 Hours > { > get { return _Hours; } > set > { > if (!value.Between(0, 23)) > throw new ArgumentOutOfRangeException("Hours", "between 0 and 23"); > _Hours = unchecked((byte)value); > } > } > //______________________________________________________________________ > private byte _Minutes; > public Int32 Minutes > { > get { return _Minutes; } > set > { > if (!value.Between(0, 59)) > throw new ArgumentOutOfRangeException("Hours", "between 0 and 59"); > _Minutes = unchecked((byte)value); > } > } > //______________________________________________________________________ > private byte _Seconds; > public Int32 Seconds > { > get { return _Seconds; } > set > { > if (!value.Between(0, 59)) > throw new ArgumentOutOfRangeException("Seconds", "between 0 and 59"); > _Seconds = unchecked((byte)value); > } > } > //______________________________________________________________________ > private ushort _MilliSeconds; > public Int32 MilliSeconds > { > get { return _MilliSeconds; } > set > { > if (!value.Between(0, 999)) > throw new ArgumentOutOfRangeException("MilliSeconds", "between 0 and 999"); > _MilliSeconds = unchecked((ushort)value); > } > } > //______________________________________________________________________ > //______________________________________________________________________ > #endregion Fields > #region Constructors > //______________________________________________________________________ > public DateTimeSpan(int years, int months, int days) > : this(years, months, days, 0,0,0, 0) > { > } > //______________________________________________________________________ > public DateTimeSpan( > int years, int months, int days, > int hours, int minutes, int seconds > ) : this(years, months, days, hours, minutes, seconds, 0) > { > > } > //______________________________________________________________________ > public DateTimeSpan( > int years, int months, int days, > int hours, int minutes, int seconds, int milliSeconds > ) > { > HashCode = _Years = _MilliSeconds = _Months = _Days = _Hours = _Minutes = _Seconds = 0; > HasCodePresent = false; > > Years = years; Months = months; Days = days; > Hours = hours; Minutes = minutes; Seconds = seconds; > MilliSeconds = milliSeconds; > > > } > //______________________________________________________________________ > /* > * start: 2012/03/14 > * end: 2022/04/15 > * years: 2022 - 2012, > * months: 04-03 > * days 2022/04/14 >> 2022/04/15 = 1 > * > * start: 2012/03/14 > * end: 2022/02/13 > * years: 2022 - 2012 + 1 > * months: 02 - 03 + 12 > * days: 2022/01/14 >> 2022/02/13 = 30 > */ > > public DateTimeSpan(DateTime start, DateTime end) > { > if (start > end) > throw new ArgumentException("startDate <= endDate"); > > HashCode = _Years = _MilliSeconds = _Months = _Days = _Hours = _Minutes = _Seconds = 0; > > HasCodePresent = false; > > Years = end.Year - start.Year; > > int months = end.Month - start.Month; > > if (months < 0) > { > months += 12; > Years--; > } > > TimeSpan tsStart = new TimeSpan(start.Day, start.Hour, start.Minute, start.Second, start.Millisecond); > TimeSpan tsEnd = new TimeSpan(end.Day, end.Hour, end.Minute, end.Second, end.Millisecond); > > if (tsStart > tsEnd) > { > if (--months < 0) > { > months += 12; > Years--; > } > > } > Months = months; > > DateTime between = start.AddYears(Years).AddMonths(months); > TimeSpan delta = end - between; > > > Days = delta.Days; > Hours = delta.Hours; > Minutes = delta.Minutes; > Seconds = delta.Seconds; > MilliSeconds = delta.Milliseconds; > > } > //______________________________________________________________________ > #endregion Constructors > //______________________________________________________________________ > #region ToString > //______________________________________________________________________ > public override string ToString() > { > return string.Format("Years:{0} Months:{1} Days:{2} Hours:{3} Minutes:{4} Seconds:{5}", > Years, Months, Days, Hours, Minutes, Seconds); > } > //______________________________________________________________________ > public string ToString(bool comparable) > { > if (!comparable) > return ToString(); > > return String.Format("{0:0000}{1:00}{2:00}{3:00}{4:00}{5:00}{6:000}", > Years,Months, Days, > Hours, Minutes, Seconds, MilliSeconds); > } > //______________________________________________________________________ > #endregion ToString > > #region IComparable > //______________________________________________________________________ > public int CompareTo(object other) > { > if (other == null) > return 1; > > if (!(other is DateTimeSpan)) > throw new ArgumentException("not a DateTimeSpan", "other"); > > return CompareTo((DateTimeSpan)other); > > } > //______________________________________________________________________ > #endregion IComparable > > #region IComparable<T> > //______________________________________________________________________ > public int CompareTo(DateTimeSpan other) > { > return String.CompareOrdinal(ToString(true), other.ToString(true)); > } > //______________________________________________________________________ > #endregion IComparable<T> > > #region Equals > //______________________________________________________________________ > public override bool Equals(object other) > { > return other is DateTimeSpan ? Equals((DateTimeSpan)other) : false; > } > //______________________________________________________________________ > #endregion Equals > #region IEquatable<T> > //______________________________________________________________________ > public bool Equals(DateTimeSpan other) > { > return CompareTo(other) == 0; > } > //______________________________________________________________________ > #endregion IEquatable<T> > > #region GetHashCode > //______________________________________________________________________ > private bool HasCodePresent; > private int HashCode; > > public override int GetHashCode() > { > if (!HasCodePresent) > { > using (RandomNumberGenerator rnd = RandomNumberGenerator.Create()) > { > byte[] bytes = new byte[ByteSize.Int32]; > rnd.GetBytes(bytes); > HashCode = BitConverter.ToInt32(bytes, 0); > > } > } > return HashCode; > } > //______________________________________________________________________ > #endregion GetHashCode > > #region Operators > //______________________________________________________________________ > public static bool operator ==(DateTimeSpan dts1, DateTimeSpan dts2) > { > return dts1.Equals(dts2); > } > //______________________________________________________________________ > public static bool operator !=(DateTimeSpan dts1, DateTimeSpan dts2) > { > return !(dts1 == dts2); > } > //______________________________________________________________________ > public static bool operator <(DateTimeSpan dts1, DateTimeSpan dts2) > { > return dts1.CompareTo(dts1) < 0; > } > //______________________________________________________________________ > public static bool operator >=(DateTimeSpan dts1, DateTimeSpan dts2) > { > return !(dts1 < dts2); > } > //______________________________________________________________________ > public static bool operator >(DateTimeSpan dts1, DateTimeSpan dts2) > { > return dts1.CompareTo(dts1) > 0; > } > //______________________________________________________________________ > public static bool operator <=(DateTimeSpan dts1, DateTimeSpan dts2) > { > return !(dts1 < dts2); > } > //______________________________________________________________________ > > #endregion Operators > } >>
>public static partial class ExtensionMethods_Comparison > { > //______________________________________________________________________ > /// <summary> > /// tells whether s between s1 and s2 > /// </summary> > /// <typeparam name="T"></typeparam> > /// <param name="s"></param> > /// <param name="s1"></param> > /// <param name="s2"></param> > /// <returns>true or false</returns> > // > // IComparable<T> > // - By definition, any object compares greater than a null reference > // - two null references compare equal to each other > public static bool Between<T>(this T s, T s1, T s2) where T : IComparable<T> > { > if (s != null) > return (s.CompareTo(s1) >= 0) && (s.CompareTo(s2) <= 0); > > // s == null here > > /* > * s1 s s2 s1<=s s<=s2 final > * !=null null !null false true false > * null null !null true true true * > * !null null null false true false > * null null null true true true * > */ > /* > * conclusion > * It does not matter whether s2 is null or not > * s < non-null-s2 > * s == null-s2 > * hence always: s <= s2 > * > * the only thing that matters is s1 > * non_null_s1 < s > * null_s1 == s > */ > return (s1 == null); > } > //______________________________________________________________________ > } >>
> public class ByteSize > { > public const int Byte = 1; > public const int SByte = 1; > > public const int Char = 2; > > public const int Int16 = 2; > public const int UInt16 = 2; > > public const int Int32 = 4; > public const int UInt32 = 4; > > public const int Int64 = 8; > public const int UInt64 = 8; > } >>
> class Class1 > { > static void Main(string[] args) > { > Test(); > Console.ReadLine(); > > } > > static DateTimeSpanTest[] TestData = > { new DateTimeSpanTest( > new DateTime(2011, 04, 15, 0, 0, 0), > new DateTime(2012, 03, 14, 0, 0, 0), > new DateTimeSpan(0, 10, 28) > ) > ,new DateTimeSpanTest( > new DateTime(2011, 04, 15, 17, 0, 0), > new DateTime(2012, 04, 15, 16, 59, 59), > new DateTimeSpan(0, 11, 30, 23, 59, 59) > ) > ,new DateTimeSpanTest( > new DateTime(2011, 04, 15, 17, 0, 0), > new DateTime(2013, 04, 15, 16, 59, 59), > new DateTimeSpan(1, 11, 30, 23, 59, 59) > ) > ,new DateTimeSpanTest( > new DateTime(2011, 04, 15, 17, 0, 0), > new DateTime(2011, 04, 16, 16, 59, 59), > new DateTimeSpan(0, 0, 0, 23, 59, 59) > ) > ,new DateTimeSpanTest( > new DateTime(2012, 02, 28, 17, 0, 0), > new DateTime(2012, 03, 01, 16, 59, 59), > new DateTimeSpan(0, 0, 1, 23, 59, 59) > ) > ,new DateTimeSpanTest( > new DateTime(2011, 02, 28, 17, 0, 0), > new DateTime(2011, 03, 01, 16, 59, 59), > new DateTimeSpan(0, 0, 0, 23, 59, 59) > ) > ,new DateTimeSpanTest( > new DateTime(2011, 02, 28, 17, 0, 0), > new DateTime(2011, 03, 01, 18, 01, 02), > new DateTimeSpan(0, 0, 1, 01, 01, 02) > ) > }; > static bool Test() > { > bool success = true; > bool caseResult; > > foreach (DateTimeSpanTest testcase in TestData) > { > DateTimeSpan result = new DateTimeSpan(testcase.Start, testcase.End); > caseResult = result == testcase.Delta; > > Console.WriteLine("{0} - {1} : \n{2} expected\n{3} got\n{4}", > testcase.Start, testcase.End, testcase.Delta, result, > caseResult ? "OK" : "fail" > ); > > if (!caseResult) > { > success = false; > break; > } > > } > return success; > } > } > class DateTimeSpanTest > { > public DateTime Start; > public DateTime End; > public DateTimeSpan Delta; > > public DateTimeSpanTest(DateTime start, DateTime end, DateTimeSpan delta) > { > Start = start; > End = end; > Delta = delta; > } > } >