/// <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); } }
public static Period Between(LocalDate start, LocalDate end, PeriodUnits units) { Preconditions.CheckArgument((units & PeriodUnits.AllTimeUnits) == 0, nameof(units), "Units contains time units: {0}", units); Preconditions.CheckArgument(units != 0, nameof(units), "Units must not be empty"); Preconditions.CheckArgument((units & ~PeriodUnits.AllUnits) == 0, nameof(units), "Units contains an unknown value: {0}", units); CalendarSystem calendar = start.Calendar; Preconditions.CheckArgument(calendar.Equals(end.Calendar), nameof(end), "start and end must use the same calendar system"); if (start == end) { return Zero; } // Optimization for single field switch (units) { case PeriodUnits.Years: return FromYears(DatePeriodFields.YearsField.UnitsBetween(start, end)); case PeriodUnits.Months: return FromMonths(DatePeriodFields.MonthsField.UnitsBetween(start, end)); case PeriodUnits.Weeks: return FromWeeks(DatePeriodFields.WeeksField.UnitsBetween(start, end)); case PeriodUnits.Days: return FromDays(DaysBetween(start, end)); } // Multiple fields DateComponentsBetween(start, end, units, out int years, out int months, out int weeks, out int days); return new Period(years, months, weeks, days); }
private String GetTextForUnitPlural(PeriodUnits unit) { switch (unit) { case PeriodUnits.Days: return(Properties.Resources.ManyDays); case PeriodUnits.Hours: return(Properties.Resources.ManyHours); case PeriodUnits.Milliseconds: return(Properties.Resources.ManyMilliseconds); case PeriodUnits.Minutes: return(Properties.Resources.ManyMinutes); case PeriodUnits.Months: return(Properties.Resources.ManyMonths); case PeriodUnits.Seconds: return(Properties.Resources.ManySeconds); case PeriodUnits.Ticks: return(Properties.Resources.ManyTicks); case PeriodUnits.Weeks: return(Properties.Resources.ManyWeeks); case PeriodUnits.Years: return(Properties.Resources.ManyYears); default: throw new ArgumentOutOfRangeException("unit", "GetTextForUnitPlural only takes a single unit"); } }
private String GetTextForUnitSingular(PeriodUnits unit) { switch (unit) { case PeriodUnits.Days: return(Properties.Resources.OneDay); case PeriodUnits.Hours: return(Properties.Resources.OneHour); case PeriodUnits.Milliseconds: return(Properties.Resources.OneMillisecond); case PeriodUnits.Minutes: return(Properties.Resources.OneMinute); case PeriodUnits.Months: return(Properties.Resources.OneMonth); case PeriodUnits.Seconds: return(Properties.Resources.OneSecond); case PeriodUnits.Ticks: return(Properties.Resources.OneTick); case PeriodUnits.Weeks: return(Properties.Resources.OneWeek); case PeriodUnits.Years: return(Properties.Resources.OneYear); default: throw new ArgumentOutOfRangeException("unit", "GetTextForUnitSingular only takes a single unit"); } }
public static Period Between(LocalTime start, LocalTime end, PeriodUnits units) { Preconditions.CheckArgument((units & PeriodUnits.AllDateUnits) == 0, nameof(units), "Units contains date units: {0}", units); Preconditions.CheckArgument(units != 0, nameof(units), "Units must not be empty"); Preconditions.CheckArgument((units & ~PeriodUnits.AllUnits) == 0, nameof(units), "Units contains an unknown value: {0}", units); // We know that the difference is in the range of +/- 1 day, which is a relatively small // number of nanoseconds. All the operations can be done with simple long division/remainder ops, // so we don't need to delegate to TimePeriodField. long remaining = unchecked (end.NanosecondOfDay - start.NanosecondOfDay); // Optimization for a single unit switch (units) { case PeriodUnits.Hours: return FromHours(remaining / NanosecondsPerHour); case PeriodUnits.Minutes: return FromMinutes(remaining / NanosecondsPerMinute); case PeriodUnits.Seconds: return FromSeconds(remaining / NanosecondsPerSecond); case PeriodUnits.Milliseconds: return FromMilliseconds(remaining / NanosecondsPerMillisecond); case PeriodUnits.Ticks: return FromTicks(remaining / NanosecondsPerTick); case PeriodUnits.Nanoseconds: return FromNanoseconds(remaining); } TimeComponentsBetween(remaining, units, out long hours, out long minutes, out long seconds, out long milliseconds, out long ticks, out long nanoseconds); return new Period(hours, minutes, seconds, milliseconds, ticks, nanoseconds); }
/// <summary> /// Creates a new period with the given single value. /// </summary> private Period(PeriodUnits periodUnit, long value) { switch (periodUnit) { case PeriodUnits.Years: years = value; break; case PeriodUnits.Months: months = value; break; case PeriodUnits.Weeks: weeks = value; break; case PeriodUnits.Days: days = value; break; case PeriodUnits.Hours: hours = value; break; case PeriodUnits.Minutes: minutes = value; break; case PeriodUnits.Seconds: seconds = value; break; case PeriodUnits.Milliseconds: milliseconds = value; break; case PeriodUnits.Ticks: ticks = value; break; default: throw new ArgumentException("Unit must be singular", "periodUnit"); } }
internal PeriodUnits GetSignificantUnitsForPeriod(Period period) { var baseValues = new[] { new { Unit = PeriodUnits.Years, Value = period.Years }, new { Unit = PeriodUnits.Months, Value = period.Months }, new { Unit = PeriodUnits.Weeks, Value = period.Weeks }, new { Unit = PeriodUnits.Days, Value = period.Days }, new { Unit = PeriodUnits.Hours, Value = period.Hours }, new { Unit = PeriodUnits.Minutes, Value = period.Minutes }, new { Unit = PeriodUnits.Seconds, Value = period.Seconds }, new { Unit = PeriodUnits.Milliseconds, Value = period.Milliseconds } }.ToList(); var values = this.Parameters.DisplaySignificantZeroValueUnits ? baseValues.SkipWhile(a => a.Value == 0).Reverse().SkipWhile(a => a.Value == 0).Reverse().Take(this.MaxiumumNumberOfUnitsToDisplay) : baseValues.Where(a => a.Value != 0).Take(this.MaxiumumNumberOfUnitsToDisplay); PeriodUnits significantUnits = PeriodUnits.None; foreach (var item in values) { significantUnits = significantUnits | item.Unit; } return(significantUnits); }
internal override CoreMargin PrepareChart(AxisOrientation source, ChartCore chart) { // Get the current configued values from the view _initialDateTime = ((IDateAxisView)View).InitialDateTime; _period = ((IDateAxisView)View).Period; return(base.PrepareChart(source, chart)); }
public void HasDateComponent_SingleValued(PeriodUnits unit, bool hasDateComponent) { var period = new PeriodBuilder { [unit] = 1 }.Build(); Assert.AreEqual(hasDateComponent, period.HasDateComponent); }
public void GetRelativeTime_UnitsToDisplay(String startLdt, String endLdt, PeriodUnits unitsToDisplay, String expectedResult) { var start = LocalDateTimePattern.ExtendedIsoPattern.Parse(startLdt).Value; var end = LocalDateTimePattern.ExtendedIsoPattern.Parse(endLdt).Value; var result = new Humanizer(unitsToDisplay).GetRelativeTime(start, end); Assert.AreEqual(expectedResult, result); }
/// <summary> /// Returns the list of distinct units that are interesting to display, e.g.: Years, Months, Week, Days, Hours, Minutes, Seconds and Milliseconds. /// </summary> /// <param name="units">The units enumeration value to get the distinct units from</param> /// <returns></returns> public static IEnumerable <PeriodUnits> GetDistinctUnits(this PeriodUnits units) { foreach (var unit in Enum.GetValues(typeof(PeriodUnits)) .Cast <PeriodUnits>() .Where(u => units.Contains(u))) { //Only return single units, compound units are ignored switch (unit) { case PeriodUnits.Years: yield return(PeriodUnits.Years); break; case PeriodUnits.Months: yield return(PeriodUnits.Months); break; case PeriodUnits.Weeks: yield return(PeriodUnits.Weeks); break; case PeriodUnits.Days: yield return(PeriodUnits.Days); break; case PeriodUnits.Hours: yield return(PeriodUnits.Hours); break; case PeriodUnits.Minutes: yield return(PeriodUnits.Minutes); break; case PeriodUnits.Seconds: yield return(PeriodUnits.Seconds); break; case PeriodUnits.Milliseconds: yield return(PeriodUnits.Milliseconds); break; case PeriodUnits.Ticks: yield return(PeriodUnits.Ticks); break; } } }
/// <summary> /// Get a random <see cref="Period"/>. Default 1 week/7 days. /// </summary> public Period Period(Period?maximum = null, LocalDateTime?anchor = null, PeriodUnits units = global::NodaTime.PeriodUnits.AllUnits) { var anchorTime = anchor ?? LocalDateTime.Now(); var span = maximum ?? global::NodaTime.Period.FromDays(7); var periodTicks = global::NodaTime.Period.Between(anchorTime, anchorTime + span, global::NodaTime.PeriodUnits.Ticks); var randomTicks = global::NodaTime.Period.FromTicks(Random.Long(0, periodTicks.Ticks)); return(global::NodaTime.Period.Between(anchorTime, anchorTime + randomTicks, units)); }
public void BetweenLocalTimes_SingleUnit(string startText, string endText, PeriodUnits units, long expectedValue) { var start = LocalTimePattern.ExtendedIso.Parse(startText).Value; var end = LocalTimePattern.ExtendedIso.Parse(endText).Value; var actual = Period.Between(start, end, units); var expected = new PeriodBuilder { [units] = expectedValue }.Build(); Assert.AreEqual(expected, actual); }
/// <summary> /// Gets or sets the value of a single unit. /// </summary> /// <param name="unit">A single value within the <see cref="PeriodUnits"/> enumeration.</param> /// <returns>The value of the given unit within this period builder, or zero if the unit is unset.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="unit"/> is not a single unit.</exception> public long this[PeriodUnits unit] { get { switch (unit) { case PeriodUnits.Years: return(Years); case PeriodUnits.Months: return(Months); case PeriodUnits.Weeks: return(Weeks); case PeriodUnits.Days: return(Days); case PeriodUnits.Hours: return(Hours); case PeriodUnits.Minutes: return(Minutes); case PeriodUnits.Seconds: return(Seconds); case PeriodUnits.Milliseconds: return(Milliseconds); case PeriodUnits.Ticks: return(Ticks); default: throw new ArgumentOutOfRangeException("unit", "Indexer for PeriodBuilder only takes a single unit"); } } set { switch (unit) { case PeriodUnits.Years: Years = value; return; case PeriodUnits.Months: Months = value; return; case PeriodUnits.Weeks: Weeks = value; return; case PeriodUnits.Days: Days = value; return; case PeriodUnits.Hours: Hours = value; return; case PeriodUnits.Minutes: Minutes = value; return; case PeriodUnits.Seconds: Seconds = value; return; case PeriodUnits.Milliseconds: Milliseconds = value; return; case PeriodUnits.Ticks: Ticks = value; return; default: throw new ArgumentOutOfRangeException("unit", "Indexer for PeriodBuilder only takes a single unit"); } } }
public void Between_ExtremeValues(PeriodUnits units) { // We can't use None, and Ticks will *correctly* overflow. if (units == PeriodUnits.None || units == PeriodUnits.Ticks) { return; } var minValue = new LocalDateTime(new LocalInstant(CalendarSystem.Iso.MinTicks)); var maxValue = new LocalDateTime(new LocalInstant(CalendarSystem.Iso.MaxTicks)); Period.Between(minValue, maxValue, units); }
public void Between_ExtremeValues(PeriodUnits units) { // We can't use None, and Nanoseconds will *correctly* overflow. if (units == PeriodUnits.None || units == PeriodUnits.Nanoseconds) { return; } var minValue = LocalDate.MinIsoValue.At(LocalTime.MinValue); var maxValue = LocalDate.MaxIsoValue.At(LocalTime.MaxValue); Period.Between(minValue, maxValue, units); }
private String GetTextForUnit(PeriodUnits unit, String textValue) { //Depending on singular or plural, fetch different properties if (textValue == "1") { return(this.GetTextForUnitSingular(unit)); } else { return(String.Format(this.GetTextForUnitPlural(unit), textValue)); } }
public void Between_ExtremeValues(PeriodUnits units) { // We can't use None, and Ticks/Nanoseconds will *correctly* overflow. if (units == PeriodUnits.None || units == PeriodUnits.Ticks || units == PeriodUnits.Nanoseconds) { return; } var iso = CalendarSystem.Iso; var minValue = new LocalDateTime(iso.MinYear, 1, 1, 0, 0); var maxValue = new LocalDateTime(iso.MaxYear, 12, 31, 23, 59, 59, 999, (int)(NodaConstants.TicksPerMillisecond - 1)); Period.Between(minValue, maxValue, units); }
public static string GetTimeBetween(DateTime startTime, DateTime endTime, PeriodUnits pu, bool label) { // https://nodatime.org/2.4.x/userguide/rationale LocalDateTime start = new LocalDateTime(startTime.Year, startTime.Month, startTime.Day, startTime.Hour, startTime.Minute, startTime.Second); LocalDateTime end = new LocalDateTime(endTime.Year, endTime.Month, endTime.Day, endTime.Hour, endTime.Minute, endTime.Second); Period period = Period.Between(start, end, pu); string s = string.Empty; if ((pu & PeriodUnits.Years) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Years, label ? " Years" : ""); } if ((pu & PeriodUnits.Months) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Months, label ? " Months" : ""); } if ((pu & PeriodUnits.Weeks) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Weeks, label ? " Weeks" : ""); } if ((pu & PeriodUnits.Days) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Days, label ? " Days" : ""); } if ((pu & PeriodUnits.Hours) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Hours, label ? " Hours" : ""); } if ((pu & PeriodUnits.Minutes) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Minutes, label ? " Minutes" : ""); } if ((pu & PeriodUnits.Seconds) != 0) { s = s + string.Format("{0}{1}{2}", string.IsNullOrEmpty(s) ? "" : " ", period.Seconds, label ? " Seconds" : ""); } return(s); }
public void BetweenYearMonth_SingleUnit(string startText, string endText, PeriodUnits units, int expectedValue) { var start = YearMonthPattern.Iso.Parse(startText).Value; var end = YearMonthPattern.Iso.Parse(endText).Value; var forward = Period.Between(start, end, units); var expectedForward = new PeriodBuilder { [units] = expectedValue }.Build(); Assert.AreEqual(expectedForward, forward); var backward = Period.Between(end, start, units); var expectedBackward = new PeriodBuilder { [units] = -expectedValue }.Build(); Assert.AreEqual(expectedBackward, backward); }
/// <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)); }
/// <summary> /// Common code to perform the time parts of the Between methods for long-representable nanos. /// </summary> /// <param name="totalNanoseconds">Number of nanoseconds to compute the units of</param> /// <param name="units">Units to compute</param> /// <param name="hours">(Out) Hours component of result</param> /// <param name="minutes">(Out) Minutes component of result</param> /// <param name="seconds">(Out) Seconds component of result</param> /// <param name="milliseconds">(Out) Milliseconds component of result</param> /// <param name="ticks">(Out) Ticks component of result</param> /// <param name="nanoseconds">(Out) Nanoseconds component of result</param> private static void TimeComponentsBetween(long totalNanoseconds, PeriodUnits units, out long hours, out long minutes, out long seconds, out long milliseconds, out long ticks, out long nanoseconds) { hours = UnitsBetween(PeriodUnits.Hours, NanosecondsPerHour); minutes = UnitsBetween(PeriodUnits.Minutes, NanosecondsPerMinute); seconds = UnitsBetween(PeriodUnits.Seconds, NanosecondsPerSecond); milliseconds = UnitsBetween(PeriodUnits.Milliseconds, NanosecondsPerMillisecond); ticks = UnitsBetween(PeriodUnits.Ticks, NanosecondsPerTick); nanoseconds = UnitsBetween(PeriodUnits.Nanoseconds, 1); long UnitsBetween(PeriodUnits mask, long nanosecondsPerUnit) { if ((mask & units) == 0) { return 0; } return Math.DivRem(totalNanoseconds, nanosecondsPerUnit, out totalNanoseconds); } }
/// <summary> /// Returns a new period with only the specified units. /// </summary> /// <param name="period">The period whose values should be used.</param> /// <param name="units">The units that should be taken from the given period.</param> /// <returns>A new period with only the specified units.</returns> public static Period OnlyWith(this Period period, PeriodUnits units = PeriodUnits.AllUnits) { var builder = new PeriodBuilder(); if (units.HasFlag(PeriodUnits.Years)) { builder.Years = period.Years; } if (units.HasFlag(PeriodUnits.Months)) { builder.Months = period.Months; } if (units.HasFlag(PeriodUnits.Weeks)) { builder.Weeks = period.Weeks; } if (units.HasFlag(PeriodUnits.Days)) { builder.Days = period.Days; } if (units.HasFlag(PeriodUnits.Hours)) { builder.Hours = period.Hours; } if (units.HasFlag(PeriodUnits.Minutes)) { builder.Minutes = period.Minutes; } if (units.HasFlag(PeriodUnits.Seconds)) { builder.Seconds = period.Seconds; } if (units.HasFlag(PeriodUnits.Milliseconds)) { builder.Milliseconds = period.Milliseconds; } if (units.HasFlag(PeriodUnits.Ticks)) { builder.Ticks = period.Ticks; } return(builder.Build()); }
/// <inheritdoc/> public string ToDelimitedString() { System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture; string separator = IsSubcomponent ? Configuration.SubcomponentSeparator : Configuration.ComponentSeparator; return(string.Format( culture, StringHelper.StringFormatSequence(0, 11, separator), RepeatPatternCode?.ToDelimitedString(), CalendarAlignment, PhaseRangeBeginValue.HasValue ? PhaseRangeBeginValue.Value.ToString(Consts.NumericFormat, culture) : null, PhaseRangeEndValue.HasValue ? PhaseRangeEndValue.Value.ToString(Consts.NumericFormat, culture) : null, PeriodQuantity.HasValue ? PeriodQuantity.Value.ToString(Consts.NumericFormat, culture) : null, PeriodUnits?.ToDelimitedString(), InstitutionSpecifiedTime, Event, EventOffsetQuantity.HasValue ? EventOffsetQuantity.Value.ToString(Consts.NumericFormat, culture) : null, EventOffsetUnits?.ToDelimitedString(), GeneralTimingSpecification ).TrimEnd(separator.ToCharArray())); }
public static PeriodUnits GetSmallestSingleUnit(this PeriodUnits units) { if (units.Contains(PeriodUnits.Milliseconds)) { return(PeriodUnits.Milliseconds); } else if (units.Contains(PeriodUnits.Seconds)) { return(PeriodUnits.Seconds); } else if (units.Contains(PeriodUnits.Minutes)) { return(PeriodUnits.Minutes); } else if (units.Contains(PeriodUnits.Hours)) { return(PeriodUnits.Hours); } else if (units.Contains(PeriodUnits.Days)) { return(PeriodUnits.Days); } else if (units.Contains(PeriodUnits.Weeks)) { return(PeriodUnits.Weeks); } else if (units.Contains(PeriodUnits.Months)) { return(PeriodUnits.Months); } else if (units.Contains(PeriodUnits.Years)) { return(PeriodUnits.Years); } else { throw new ArgumentOutOfRangeException("unit"); } }
//TODO A few unit tests to be added here, just to make a point :-) internal PeriodUnits GetLastUnitToDisplay(PeriodUnits significantUnits) { if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Milliseconds) == PeriodUnits.Milliseconds) { return(PeriodUnits.Milliseconds); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Seconds) == PeriodUnits.Seconds) { return(PeriodUnits.Seconds); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Minutes) == PeriodUnits.Minutes) { return(PeriodUnits.Minutes); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Hours) == PeriodUnits.Hours) { return(PeriodUnits.Hours); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Days) == PeriodUnits.Days) { return(PeriodUnits.Days); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Weeks) == PeriodUnits.Weeks) { return(PeriodUnits.Weeks); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Months) == PeriodUnits.Months) { return(PeriodUnits.Months); } else if ((this.UnitsToDisplay & significantUnits & PeriodUnits.Years) == PeriodUnits.Years) { return(PeriodUnits.Years); } //If nothing was found, there is no common unit between UnitsToDisplay and significantsUnits... Let's simply return the smallest unit in UnitsToDisplay. return(this.UnitsToDisplay.GetSmallestSingleUnit()); }
public void Between_ExtremeValues(PeriodUnits units) { // We can't use None, and Ticks/Nanoseconds will *correctly* overflow. if (units == PeriodUnits.None || units == PeriodUnits.Ticks || units== PeriodUnits.Nanoseconds) { return; } var iso = CalendarSystem.Iso; var minValue = new LocalDateTime(iso.MinYear, 1, 1, 0, 0); var maxValue = new LocalDateTime(iso.MaxYear, 12, 31, 23, 59, 59, 999, (int) (NodaConstants.TicksPerMillisecond - 1)); Period.Between(minValue, maxValue, units); }
/// <summary> /// Common code to perform the date parts of the Between methods. /// </summary> /// <param name="start">Start date</param> /// <param name="end">End date</param> /// <param name="units">Units to compute</param> /// <param name="years">(Out) Year component of result</param> /// <param name="months">(Out) Months component of result</param> /// <param name="weeks">(Out) Weeks component of result</param> /// <param name="days">(Out) Days component of result</param> /// <returns>The resulting date after adding the result components to <paramref name="start"/> (to /// allow further computations to be made)</returns> private static LocalDate DateComponentsBetween(LocalDate start, LocalDate end, PeriodUnits units, out int years, out int months, out int weeks, out int days) { LocalDate result = start; years = UnitsBetween(units & PeriodUnits.Years, ref result, end, DatePeriodFields.YearsField); months = UnitsBetween(units & PeriodUnits.Months, ref result, end, DatePeriodFields.MonthsField); weeks = UnitsBetween(units & PeriodUnits.Weeks, ref result, end, DatePeriodFields.WeeksField); days = UnitsBetween(units & PeriodUnits.Days, ref result, end, DatePeriodFields.DaysField); int UnitsBetween(PeriodUnits maskedUnits, ref LocalDate startDate, LocalDate endDate, IDatePeriodField dateField) { if (maskedUnits == 0) { return 0; } int value = dateField.UnitsBetween(startDate, endDate); startDate = dateField.Add(startDate, value); return value; } 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, nameof(units), "Units must not be empty"); Preconditions.CheckArgument((units & ~PeriodUnits.AllUnits) == 0, nameof(units), "Units contains an unknown value: {0}", units); CalendarSystem calendar = start.Calendar; Preconditions.CheckArgument(calendar.Equals(end.Calendar), nameof(end), "start and end must use the same calendar system"); if (start == end) { return Zero; } // Adjust for situations like "days between 5th January 10am and 7th Janary 5am" which should be one // day, because if we actually reach 7th January with date fields, we've overshot. // The date adjustment will always be valid, because it's just moving it towards start. // We need this for all date-based period fields. We could potentially optimize by not doing this // in cases where we've only got time fields... LocalDate endDate = end.Date; if (start < end) { if (start.TimeOfDay > end.TimeOfDay) { endDate = endDate.PlusDays(-1); } } else if (start > end && start.TimeOfDay < end.TimeOfDay) { endDate = endDate.PlusDays(1); } // Optimization for single field switch (units) { case PeriodUnits.Years: return FromYears(DatePeriodFields.YearsField.UnitsBetween(start.Date, endDate)); case PeriodUnits.Months: return FromMonths(DatePeriodFields.MonthsField.UnitsBetween(start.Date, endDate)); case PeriodUnits.Weeks: return FromWeeks(DatePeriodFields.WeeksField.UnitsBetween(start.Date, endDate)); case PeriodUnits.Days: return FromDays(DaysBetween(start.Date, endDate)); case PeriodUnits.Hours: return FromHours(TimePeriodField.Hours.UnitsBetween(start, end)); case PeriodUnits.Minutes: return FromMinutes(TimePeriodField.Minutes.UnitsBetween(start, end)); case PeriodUnits.Seconds: return FromSeconds(TimePeriodField.Seconds.UnitsBetween(start, end)); case PeriodUnits.Milliseconds: return FromMilliseconds(TimePeriodField.Milliseconds.UnitsBetween(start, end)); case PeriodUnits.Ticks: return FromTicks(TimePeriodField.Ticks.UnitsBetween(start, end)); case PeriodUnits.Nanoseconds: return FromNanoseconds(TimePeriodField.Nanoseconds.UnitsBetween(start, end)); } // Multiple fields LocalDateTime remaining = start; int years = 0, months = 0, weeks = 0, days = 0; if ((units & PeriodUnits.AllDateUnits) != 0) { LocalDate remainingDate = DateComponentsBetween( start.Date, endDate, units, out years, out months, out weeks, out days); remaining = new LocalDateTime(remainingDate, start.TimeOfDay); } if ((units & PeriodUnits.AllTimeUnits) == 0) { return new Period(years, months, weeks, days); } // The remainder of the computation is with fixed-length units, so we can do it all with // Duration instead of Local* values. We don't know for sure that this is small though - we *could* // be trying to find the difference between 9998 BC and 9999 CE in nanoseconds... // Where we can optimize, do everything with long arithmetic (as we do for Between(LocalTime, LocalTime)). // Otherwise (rare case), use duration arithmetic. long hours, minutes, seconds, milliseconds, ticks, nanoseconds; var duration = end.ToLocalInstant().TimeSinceLocalEpoch - remaining.ToLocalInstant().TimeSinceLocalEpoch; if (duration.IsInt64Representable) { TimeComponentsBetween(duration.ToInt64Nanoseconds(), units, out hours, out minutes, out seconds, out milliseconds, out ticks, out nanoseconds); } else { hours = UnitsBetween(PeriodUnits.Hours, TimePeriodField.Hours); minutes = UnitsBetween(PeriodUnits.Minutes, TimePeriodField.Minutes); seconds = UnitsBetween(PeriodUnits.Seconds, TimePeriodField.Seconds); milliseconds = UnitsBetween(PeriodUnits.Milliseconds, TimePeriodField.Milliseconds); ticks = UnitsBetween(PeriodUnits.Ticks, TimePeriodField.Ticks); nanoseconds = UnitsBetween(PeriodUnits.Ticks, TimePeriodField.Nanoseconds); } return new Period(years, months, weeks, days, hours, minutes, seconds, milliseconds, ticks, nanoseconds); long UnitsBetween(PeriodUnits mask, TimePeriodField timeField) { if ((mask & units) == 0) { return 0; } long value = timeField.GetUnitsInDuration(duration); duration -= timeField.ToDuration(value); return value; } }
public void Between_LocalDateTime_AwkwardTimeOfDayWithSingleUnit(string startText, string endText, PeriodUnits units, int expectedForward, int expectedBackward) { LocalDateTime start = LocalDateTimePattern.ExtendedIso.Parse(startText).Value; LocalDateTime end = LocalDateTimePattern.ExtendedIso.Parse(endText).Value; Period forward = Period.Between(start, end, units); Assert.AreEqual(expectedForward, forward.ToBuilder()[units]); Period backward = Period.Between(end, start, units); Assert.AreEqual(expectedBackward, backward.ToBuilder()[units]); }
public static string GetTimeSinceStart(DetailReadModel d, PeriodUnits pu, bool label) { return(GetTimeBetween(d.StartTime.Value, DateTime.Now, pu, label)); }
public void HasDateComponent_SingleValued(PeriodUnits unit, bool hasDateComponent) { var period = new PeriodBuilder {[unit] = 1 }.Build(); Assert.AreEqual(hasDateComponent, period.HasDateComponent); }
/// <summary> /// Gets or sets the value of a single unit. /// </summary> /// <remarks> /// <para> /// The type of this indexer is <see cref="System.Int64"/> for uniformity, but any date unit (year, month, week, day) will only ever have a value /// in the range of <see cref="System.Int32"/>. /// </para> /// <para> /// For the <see cref="PeriodUnits.Nanoseconds"/> unit, the value is converted to <c>Int64</c> when reading from the indexer, causing it to /// fail if the value is out of range (around 250 years). To access the values of very large numbers of nanoseconds, use the <see cref="Nanoseconds"/> /// property directly. /// </para> /// </remarks> /// <param name="unit">A single value within the <see cref="PeriodUnits"/> enumeration.</param> /// <value>The value of the given unit within this period builder, or zero if the unit is unset.</value> /// <exception cref="ArgumentOutOfRangeException"><paramref name="unit"/> is not a single unit, or a value is provided for a date unit which is outside the range of <see cref="System.Int32"/>.</exception> public long this[PeriodUnits unit] { get { switch (unit) { case PeriodUnits.Years: return Years; case PeriodUnits.Months: return Months; case PeriodUnits.Weeks: return Weeks; case PeriodUnits.Days: return Days; case PeriodUnits.Hours: return Hours; case PeriodUnits.Minutes: return Minutes; case PeriodUnits.Seconds: return Seconds; case PeriodUnits.Milliseconds: return Milliseconds; case PeriodUnits.Ticks: return Ticks; case PeriodUnits.Nanoseconds: return Nanoseconds; default: throw new ArgumentOutOfRangeException(nameof(unit), "Indexer for PeriodBuilder only takes a single unit"); } } set { if ((unit & PeriodUnits.AllDateUnits) != 0) { Preconditions.CheckArgumentRange(nameof(value), value, int.MinValue, int.MaxValue); } switch (unit) { case PeriodUnits.Years: Years = (int) value; return; case PeriodUnits.Months: Months = (int) value; return; case PeriodUnits.Weeks: Weeks = (int) value; return; case PeriodUnits.Days: Days = (int) value; return; case PeriodUnits.Hours: Hours = value; return; case PeriodUnits.Minutes: Minutes = value; return; case PeriodUnits.Seconds: Seconds = value; return; case PeriodUnits.Milliseconds: Milliseconds = value; return; case PeriodUnits.Ticks: Ticks = value; return; case PeriodUnits.Nanoseconds: Nanoseconds = value; return; default: throw new ArgumentOutOfRangeException(nameof(unit), "Indexer for PeriodBuilder only takes a single unit"); } } }
public void Between_LocalDateTime_AwkwardTimeOfDayWithSingleUnit(string startText, string endText, PeriodUnits units, int expectedForward, int expectedBackward) { LocalDateTime start = LocalDateTimePattern.ExtendedIsoPattern.Parse(startText).Value; LocalDateTime end = LocalDateTimePattern.ExtendedIsoPattern.Parse(endText).Value; Period forward = Period.Between(start, end, units); Assert.AreEqual(expectedForward, forward.ToBuilder()[units]); Period backward = Period.Between(end, start, units); Assert.AreEqual(expectedBackward, backward.ToBuilder()[units]); }