/// <summary> /// Returns the PeriodField for the given index, in the range 0-8 inclusive. /// </summary> private static IPeriodField GetFieldForIndex(PeriodFieldSet fields, int index) { switch (index) { case YearIndex: return(fields.Years); case MonthIndex: return(fields.Months); case WeekIndex: return(fields.Weeks); case DayIndex: return(fields.Days); case HourIndex: return(fields.Hours); case MinuteIndex: return(fields.Minutes); case SecondIndex: return(fields.Seconds); case MillisecondIndex: return(fields.Milliseconds); case TickIndex: return(fields.Ticks); default: throw new ArgumentOutOfRangeException("index"); } }
/// <summary> /// Returns the PeriodField for the given unit value, or null if the values does /// not represent a single unit. /// </summary> private static IPeriodField GetSingleField(PeriodFieldSet fields, PeriodUnits units) { switch (units) { case PeriodUnits.Years: return(fields.Years); case PeriodUnits.Months: return(fields.Months); case PeriodUnits.Weeks: return(fields.Weeks); case PeriodUnits.Days: return(fields.Days); case PeriodUnits.Hours: return(fields.Hours); case PeriodUnits.Minutes: return(fields.Minutes); case PeriodUnits.Seconds: return(fields.Seconds); case PeriodUnits.Milliseconds: return(fields.Milliseconds); case PeriodUnits.Ticks: return(fields.Ticks); default: return(null); } }
/// <summary> /// Adds the contents of this period to the given local instant in the given calendar system. /// </summary> internal LocalInstant AddTo(LocalInstant localInstant, CalendarSystem calendar, int scalar) { Preconditions.CheckNotNull(calendar, "calendar"); PeriodFieldSet fields = calendar.PeriodFields; LocalInstant result = localInstant; if (years != 0) { result = fields.Years.Add(result, years * scalar); } if (months != 0) { result = fields.Months.Add(result, months * scalar); } if (weeks != 0) { result = fields.Weeks.Add(result, weeks * scalar); } if (days != 0) { result = fields.Days.Add(result, days * scalar); } if (hours != 0) { result = fields.Hours.Add(result, hours * scalar); } if (minutes != 0) { result = fields.Minutes.Add(result, minutes * scalar); } if (seconds != 0) { result = fields.Seconds.Add(result, seconds * scalar); } if (milliseconds != 0) { result = fields.Milliseconds.Add(result, milliseconds * scalar); } if (ticks != 0) { result = fields.Ticks.Add(result, ticks * scalar); } return(result); }
/// <summary> /// Returns the period between a start and an end date/time, using only the given units. /// </summary> /// <remarks> /// If <paramref name="end"/> is before <paramref name="start" />, each property in the returned period /// will be negative. If the given set of units cannot exactly reach the end point (e.g. finding /// the difference between 1am and 3:15am in hours) the result will be such that adding it to <paramref name="start"/> /// will give a value between <paramref name="start"/> and <paramref name="end"/>. In other words, /// any rounding is "towards start"; this is true whether the resulting period is negative or positive. /// </remarks> /// <param name="start">Start date/time</param> /// <param name="end">End date/time</param> /// <param name="units">Units to use for calculations</param> /// <exception cref="ArgumentException"><paramref name="units"/> is empty or contained unknown values.</exception> /// <exception cref="ArgumentException"><paramref name="start"/> and <paramref name="end"/> use different calendars.</exception> /// <returns>The period between the given date/times, using the given units.</returns> public static Period Between(LocalDateTime start, LocalDateTime end, PeriodUnits units) { Preconditions.CheckArgument(units != 0, "units", "Units must not be empty"); Preconditions.CheckArgument((units & ~PeriodUnits.AllUnits) == 0, "units", "Units contains an unknown value: {0}", units); CalendarSystem calendar = start.Calendar; Preconditions.CheckArgument(calendar.Equals(end.Calendar), "end", "start and end must use the same calendar system"); LocalInstant startLocalInstant = start.LocalInstant; LocalInstant endLocalInstant = end.LocalInstant; if (startLocalInstant == endLocalInstant) { return(Zero); } PeriodFieldSet fields = calendar.PeriodFields; // Optimization for single field var singleField = GetSingleField(fields, units); if (singleField != null) { long value = singleField.Subtract(end.LocalInstant, start.LocalInstant); return(new Period(units, value)); } // Multiple fields long[] values = new long[ValuesArraySize]; LocalInstant remaining = startLocalInstant; int numericFields = (int)units; for (int i = 0; i < ValuesArraySize; i++) { if ((numericFields & (1 << i)) != 0) { var field = GetFieldForIndex(fields, i); values[i] = field.Subtract(endLocalInstant, remaining); remaining = field.Add(remaining, values[i]); } } return(new Period(values)); }
private CalendarSystem(string id, string name, YearMonthDayCalculator yearMonthDayCalculator, int minDaysInFirstWeek) { this.id = id; this.name = name; this.yearMonthDayCalculator = yearMonthDayCalculator; this.weekYearCalculator = new WeekYearCalculator(yearMonthDayCalculator, minDaysInFirstWeek); this.minYear = yearMonthDayCalculator.MinYear; this.maxYear = yearMonthDayCalculator.MaxYear; this.minTicks = yearMonthDayCalculator.GetYearTicks(minYear); this.maxTicks = yearMonthDayCalculator.GetYearTicksSafe(maxYear + 1) - 1; this.eras = new ReadOnlyCollection <Era>(new List <Era>(yearMonthDayCalculator.Eras)); this.periodFields = new PeriodFieldSet.Builder(TimeOfDayCalculator.TimeFields) { Days = FixedDurationPeriodField.Days, Weeks = FixedDurationPeriodField.Weeks, Months = new MonthsPeriodField(yearMonthDayCalculator), Years = new YearsPeriodField(yearMonthDayCalculator) }.Build(); }