normalize method

Period normalize()

Returns a normalized version of this period, such that equivalent (but potentially non-equal) periods are changed to the same representation.

Months and years are unchanged (as they can vary in length), but weeks are multiplied by 7 and added to the Days property, and all time properties are normalized to their natural range. Subsecond values are normalized to millisecond and 'nanosecond within millisecond' values. So for example, a period of 25 hours becomes a period of 1 day and 1 hour. A period of 1,500,750,000 nanoseconds becomes 1 second, 500 milliseconds and 750,000 nanoseconds. Aside from months and years, either all the properties end up positive, or they all end up negative. 'Week' and "tick" units in the returned period are always 0.

OverflowException: The period doesn't have years or months, but it contains more than Int.maxValue nanoseconds when the combined weeks/days/time portions are considered. This is over 292 years, so unlikely to be a problem in normal usage. In some cases this may occur even though the theoretical result would be valid due to balancing positive and negative values, but for simplicity there is no attempt to work around this.

Returns: The normalized period.

see: NormalizingEqualityComparer

Implementation

Period normalize() {
  // Simplest way to normalize: grab all the fields up to 'week' and
  // sum them.
  int totalNanoseconds = _totalNanoseconds;
  int days = (totalNanoseconds ~/ TimeConstants.nanosecondsPerDay);

  int hours, minutes, seconds, milliseconds, nanoseconds;

  if (totalNanoseconds >= 0) {
    hours = (totalNanoseconds ~/ TimeConstants.nanosecondsPerHour) % TimeConstants.hoursPerDay;
    minutes = (totalNanoseconds ~/ TimeConstants.nanosecondsPerMinute) % TimeConstants.minutesPerHour;
    seconds = (totalNanoseconds ~/ TimeConstants.nanosecondsPerSecond) % TimeConstants.secondsPerMinute;
    milliseconds = (totalNanoseconds ~/ TimeConstants.nanosecondsPerMillisecond) % TimeConstants.millisecondsPerSecond;
    nanoseconds = totalNanoseconds % TimeConstants.nanosecondsPerMillisecond;
  }
  else {
    hours = arithmeticMod((totalNanoseconds ~/ TimeConstants.nanosecondsPerHour), TimeConstants.hoursPerDay);
    minutes = arithmeticMod((totalNanoseconds ~/ TimeConstants.nanosecondsPerMinute), TimeConstants.minutesPerHour);
    seconds = arithmeticMod((totalNanoseconds ~/ TimeConstants.nanosecondsPerSecond), TimeConstants.secondsPerMinute);
    milliseconds = arithmeticMod((totalNanoseconds ~/ TimeConstants.nanosecondsPerMillisecond), TimeConstants.millisecondsPerSecond);
    nanoseconds = arithmeticMod(totalNanoseconds, TimeConstants.nanosecondsPerMillisecond);
  }

  return Period(years: years,
      months: months,
      weeks: 0 /* weeks */,
      days: days,
      hours: hours,
      minutes: minutes,
      seconds: seconds,
      milliseconds: milliseconds,
      microseconds: 0 /* ticks */,
      nanoseconds: nanoseconds);
}