An Interval is a length of time expressed as an integer multiple of some Period, for example five days or three months.
        /// <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);
            }
        }