/// <summary> /// Determines if this <b>Interval</b> is an integer multiple of another. /// </summary> /// <remarks>The calculation recognises that a week is seven days and that /// a year is twelve months. It also allows 1T to match any time period /// longer than a day and for any time period to be a multiple of 1 day.</remarks> /// <param name="other">The other <b>Interval</b> instance.</param> /// <returns><c>true</c> if this instance is an integer multiple of the /// other <b>Interval</b>, <c>false</c> otherwise.</returns> public bool IsMultipleOf(Interval other) { int value = 0; // 1T is a positive integer multiple (>= 1) of any frequency if ((multiplier == 1) && (period == Period.TERM) && (other.multiplier >= 1)) return (true); // Any period > 0 is a multiple of 1D if ((multiplier > 0) && (other.multiplier == 1) && (other.period == Period.DAY)) return (true); // Handle 1W = 7D and 1Y = 12M or multiples thereof if (period == other.Period) value = multiplier; else if ((period == Period.WEEK) && (other.Period == Period.DAY)) value = 7 * multiplier; else if ((period == Period.YEAR) && (other.Period == Period.MONTH)) value = 12 * multiplier; return (((value / other.Multiplier) >= 1) && ((value % other.Multiplier) == 0)); }
/// <summary> /// Calculates the result of adding another <b>Interval</b> to this /// one. /// </summary> /// <param name="other">The <b>Interval</b> to add.</param> /// <returns>A new <b>Interval</b> representing the combined time /// period.</returns> /// <exception cref="ArgumentException">If the two time periods /// cannot be combined.</exception> public Interval Plus(Interval other) { // One of the Intervals is zero length? if (multiplier == 0) return (other); if (other.multiplier == 0) return (this); // Both Intervals have the same unit? if (period == other.period) return (new Interval (multiplier + other.multiplier, period)); // Otherwise check for equivalences if ((period == Period.YEAR) && (other.period == Period.MONTH)) return (new Interval (12 * multiplier + other.multiplier, Period.MONTH)); if ((period == Period.MONTH) && (other.period == Period.YEAR)) return (new Interval (multiplier + 12 * other.multiplier, Period.MONTH)); if ((period == Period.WEEK) && (other.period == Period.DAY)) return (new Interval (7 * multiplier + other.multiplier, Period.DAY)); if ((period == Period.DAY) && (other.period == Period.WEEK)) return (new Interval (multiplier + 7 * other.multiplier, Period.DAY)); throw new ArgumentException ("Intervals cannot be combined"); }
/// <summary> /// Compares two <b>Interval</b> instance to see if they contain the /// same information. /// </summary> /// <remarks>This routine takes into account the equivalence of certain /// time intervals (e.g. 1Y = 12M and 1W = 7D).</remarks> /// <param name="other">The other <b>Interval</b> instance.</param> /// <returns>A <see cref="bool"/> value indicating equality.</returns> public bool Equals(Interval other) { if (period == other.period) return (multiplier == other.multiplier); // Handle 1Y == 12M equivalence if (period == Period.YEAR) { if (other.period == Period.MONTH) return ((multiplier * 12) == other.multiplier); return (false); } if (period == Period.MONTH) { if (other.period == Period.YEAR) return (multiplier == (other.multiplier * 12)); return (false); } // Handle 1W == 7D equivalence if (period == Period.WEEK) { if (other.period == Period.DAY) return ((multiplier * 7) == other.multiplier); return (false); } if (period == Period.DAY) { if (other.period == Period.WEEK) return (multiplier == (other.multiplier * 7)); return (false); } return (false); }
/// <summary> /// Creates a new <b>DateValue</b> based on the current instance and a given /// <see cref="Interval"/>. /// </summary> /// <param name="interval">The time <see cref="Interval"/>.</param> /// <returns>The adjusted date.</returns> public DateValue Plus(Interval interval) { int multiplier = interval.Multiplier; Period period = interval.Period; if (period == Period.DAY) return (PlusDays (multiplier)); else if (period == Period.WEEK) return (PlusWeeks (multiplier)); else if (period == Period.MONTH) return (PlusMonths (multiplier)); else if (period == Period.YEAR) return (PlusYears (multiplier)); else return (null); }
/// <summary> /// Creates a new <b>Date</b> based on the current instance and a given /// <see cref="Interval"/>. /// </summary> /// <param name="interval">The time <see cref="Interval"/>.</param> /// <returns>The adjusted date.</returns> public Date Plus(Interval interval) { return (new Date (dateValue.Plus (interval), timeZone)); }
// -------------------------------------------------------------------- /// <summary> /// Generates a set of dates according to schedule defined by a start date, /// an end date, an interval, roll convention and a calendar. /// </summary> /// <param name="start">The start date.</param> /// <param name="end">The end date.</param> /// <param name="frequency">The frequency of the schedule (e.g. 6M).</param> /// <param name="roll">The date roll convention or <c>null</c>.</param> /// <param name="calendar">The holiday calendar or <c>null</c>.</param> /// <returns>An array of calculated and adjusted dates.</returns> private static Date[] GenerateSchedule(Date start, Date end, Interval frequency, DateRoll roll, Calendar calendar) { Date current = start; ArrayList found = new ArrayList (); Date [] dates; while (Less (current, end)) { Date adjusted; if (roll != null) adjusted = roll.Adjust (calendar, current); else adjusted = current; if (!found.Contains (adjusted)) found.Add (adjusted); if (frequency.Period == Period.TERM) { if (Equal (current, start)) current = end; else break; } else current = current.Plus (frequency); } found.CopyTo (dates = new Date [found.Count]); return (dates); }
/// <summary> /// Tests if the payment date falls on a calculated date. /// </summary> /// <param name="paymentDate">The payment date.</param> /// <param name="startDate">The calculation period start date.</param> /// <param name="endDate">The calculation perion end date.</param> /// <param name="freq"> The period frequency.</param> /// <returns><c>true</c> if the payment date falls on a calculated date.</returns> private static bool IsUnadjustedCalculationPeriodDate(Date paymentDate, Date startDate, Date endDate, Interval freq) { Interval step = new Interval (0, Period.DAY); for (;;) { Date targetDate = startDate.Plus (step); if (targetDate.CompareTo (endDate) > 0) return (false); if (targetDate.Equals (paymentDate)) return (true); step = step.Plus (freq); } }