private function plusWithOverflow(ChronoLocalDate $newDate, $hours, $minutes, $seconds, $nanos)
 {
     // 9223372036854775808 long, 2147483648 int
     if (($hours | $minutes | $seconds | $nanos) === 0) {
         return $this->_with($newDate, $this->time);
     }
     $totDays = Math::div($nanos, self::NANOS_PER_DAY) + Math::div($seconds, self::SECONDS_PER_DAY) + Math::div($minutes, self::MINUTES_PER_DAY) + Math::div($hours, self::HOURS_PER_DAY);
     //   max/24
     $totNanos = ${$nanos} % self::NANOS_PER_DAY + $seconds % self::SECONDS_PER_DAY * self::NANOS_PER_SECOND + $minutes % self::MINUTES_PER_DAY * self::NANOS_PER_MINUTE + $hours % self::HOURS_PER_DAY * self::NANOS_PER_HOUR;
     //   max  86400000000000
     $curNoD = $this->time->toNanoOfDay();
     //   max  86400000000000
     $totNanos = $totNanos + $curNoD;
     // total 432000000000000
     $totDays += Math::floorDiv($totNanos, self::NANOS_PER_DAY);
     $newNoD = Math::floorMod($totNanos, self::NANOS_PER_DAY);
     $newTime = $newNoD === $curNoD ? $this->time : LocalTime::ofNanoOfDay($newNoD);
     return $this->_with($newDate->plus($totDays, ChronoUnit::DAYS()), $newTime);
 }
예제 #2
0
 /**
  * Calculates the amount of time until another date-time in terms of the specified unit.
  * <p>
  * This calculates the amount of time between two {@code LocalDateTime}
  * objects in terms of a single {@code TemporalUnit}.
  * The start and end points are {@code this} and the specified date-time.
  * The result will be negative if the end is before the start.
  * The {@code Temporal} passed to this method is converted to a
  * {@code LocalDateTime} using {@link #from(TemporalAccessor)}.
  * For example, the amount in days between two date-times can be calculated
  * using {@code startDateTime.until(endDateTime, DAYS)}.
  * <p>
  * The calculation returns a whole number, representing the number of
  * complete units between the two date-times.
  * For example, the amount in months between 2012-06-15T00:00 and 2012-08-14T23:59
  * will only be one month as it is one minute short of two months.
  * <p>
  * There are two equivalent ways of using this method.
  * The first is to invoke this method.
  * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
  * <pre>
  *   // these two lines are equivalent
  *   amount = start.until(end, MONTHS);
  *   amount = MONTHS.between(start, end);
  * </pre>
  * The choice should be made based on which makes the code more readable.
  * <p>
  * The calculation is implemented in this method for {@link ChronoUnit}.
  * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
  * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
  * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
  * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
  * Other {@code ChronoUnit} values will throw an exception.
  * <p>
  * If the unit is not a {@code ChronoUnit}, then the result of this method
  * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
  * passing {@code this} as the first argument and the converted input temporal
  * as the second argument.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @param Temporal $endExclusive the end date, exclusive, which is converted to a {@code LocalDateTime}, not null
  * @param TemporalUnit $unit the unit to measure the amount in, not null
  * @return int the amount of time between this date-time and the end date-time
  * @throws DateTimeException if the amount cannot be calculated, or the end
  *  temporal cannot be converted to a {@code LocalDateTime}
  * @throws UnsupportedTemporalTypeException if the unit is not supported
  * @throws ArithmeticException if numeric overflow occurs
  */
 public function until(Temporal $endExclusive, TemporalUnit $unit)
 {
     $end = LocalDateTime::from($endExclusive);
     if ($unit instanceof ChronoUnit) {
         if ($unit->isTimeBased()) {
             $amount = $this->date->daysUntil($end->date);
             if ($amount === 0) {
                 return $this->time->until($end->time, $unit);
             }
             $timePart = $end->time->toNanoOfDay() - $this->time->toNanoOfDay();
             if ($amount > 0) {
                 $amount--;
                 // safe
                 $timePart += LocalTime::NANOS_PER_DAY;
                 // safe
             } else {
                 $amount++;
                 // safe
                 $timePart -= LocalTime::NANOS_PER_DAY;
                 // safe
             }
             switch ($unit) {
                 case ChronoUnit::NANOS():
                     $amount = Math::multiplyExact($amount, LocalTime::NANOS_PER_DAY);
                     break;
                 case ChronoUnit::MICROS():
                     $amount = Math::multiplyExact($amount, LocalTime::MICROS_PER_DAY);
                     $timePart = Math::div($timePart, 1000);
                     break;
                 case ChronoUnit::MILLIS():
                     $amount = Math::multiplyExact($amount, LocalTime::MILLIS_PER_DAY);
                     $timePart = Math::div($timePart, 1000000);
                     break;
                 case ChronoUnit::SECONDS():
                     $amount = Math::multiplyExact($amount, LocalTime::SECONDS_PER_DAY);
                     $timePart = Math::div($timePart, LocalTime::NANOS_PER_SECOND);
                     break;
                 case ChronoUnit::MINUTES():
                     $amount = Math::multiplyExact($amount, LocalTime::MINUTES_PER_DAY);
                     $timePart = Math::div($timePart, LocalTime::NANOS_PER_MINUTE);
                     break;
                 case ChronoUnit::HOURS():
                     $amount = Math::multiplyExact($amount, LocalTime::HOURS_PER_DAY);
                     $timePart = Math::div($timePart, LocalTime::NANOS_PER_HOUR);
                     break;
                 case ChronoUnit::HALF_DAYS():
                     $amount = Math::multiplyExact($amount, 2);
                     $timePart = Math::div($timePart, LocalTime::NANOS_PER_HOUR * 12);
                     break;
             }
             return Math::addExact($amount, $timePart);
         }
         $endDate = $end->date;
         if ($endDate->isAfter($this->date) && $end->time->isBefore($this->time)) {
             $endDate = $endDate->minusDays(1);
         } else {
             if ($endDate->isBefore($this->date) && $end->time->isAfter($this->time)) {
                 $endDate = $endDate->plusDays(1);
             }
         }
         return $this->date->until($endDate, $unit);
     }
     return $unit->between($this, $end);
 }
예제 #3
0
 /**
  * Converts this time to epoch nanos based on 1970-01-01Z.
  *
  * @return int the epoch nanos value
  */
 private function toEpochNano()
 {
     $nod = $this->time->toNanoOfDay();
     $offsetNanos = $this->offset->getTotalSeconds() * LocalTime::NANOS_PER_SECOND;
     return $nod - $offsetNanos;
 }