Example #1
0
 /**
  * Converts this instant to the number of milliseconds from the epoch
  * of 1970-01-01T00:00:00Z.
  * <p>
  * If this instant represents a point on the time-line too far in the future
  * or past to fit in a {@code long} milliseconds, then an exception is thrown.
  * <p>
  * If this instant has greater than millisecond precision, then the conversion
  * will drop any excess precision information as though the amount in nanoseconds
  * was subject to integer division by one million.
  *
  * @return int the number of milliseconds since the epoch of 1970-01-01T00:00:00Z
  * @throws ArithmeticException if numeric overflow occurs
  */
 public function toEpochMilli()
 {
     $millis = Math::multiplyExact($this->seconds, 1000);
     return $millis + Math::div($this->nanos, 1000000);
 }
Example #2
0
 /**
  * Returns a copy of this {@code LocalDate} with the specified number of weeks added.
  * <p>
  * This method adds the specified amount in weeks to the days field incrementing
  * the month and year fields as necessary to ensure the result remains valid.
  * The result is only invalid if the maximum/minimum year is exceeded.
  * <p>
  * For example, 2008-12-31 plus one week would result in 2009-01-07.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @param int $weeksToAdd the weeks to add, may be negative
  * @return LocalDate a {@code LocalDate} based on this date with the weeks added, not null
  * @throws DateTimeException if the result exceeds the supported date range
  */
 public function plusWeeks($weeksToAdd)
 {
     return $this->plusDays(Math::multiplyExact($weeksToAdd, 7));
 }
Example #3
0
 /**
  * Returns a copy of this year with the specified amount added.
  * <p>
  * This returns a {@code Year}, based on this one, with the amount
  * in terms of the unit added. If it is not possible to add the amount, because the
  * unit is not supported or for some other reason, an exception is thrown.
  * <p>
  * If the field is a {@link ChronoUnit} then the addition is implemented here.
  * The supported fields behave as follows:
  * <ul>
  * <li>{@code YEARS} -
  *  Returns a {@code Year} with the specified number of years added.
  *  This is equivalent to {@link #plusYears(long)}.
  * <li>{@code DECADES} -
  *  Returns a {@code Year} with the specified number of decades added.
  *  This is equivalent to calling {@link #plusYears(long)} with the amount
  *  multiplied by 10.
  * <li>{@code CENTURIES} -
  *  Returns a {@code Year} with the specified number of centuries added.
  *  This is equivalent to calling {@link #plusYears(long)} with the amount
  *  multiplied by 100.
  * <li>{@code MILLENNIA} -
  *  Returns a {@code Year} with the specified number of millennia added.
  *  This is equivalent to calling {@link #plusYears(long)} with the amount
  *  multiplied by 1,000.
  * <li>{@code ERAS} -
  *  Returns a {@code Year} with the specified number of eras added.
  *  Only two eras are supported so the amount must be one, zero or minus one.
  *  If the amount is non-zero then the year is changed such that the year-of-era
  *  is unchanged.
  * </ul>
  * <p>
  * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
  * <p>
  * If the field is not a {@code ChronoUnit}, then the result of this method
  * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
  * passing {@code this} as the argument. In this case, the unit determines
  * whether and how to perform the addition.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @param int $amountToAdd the amount of the unit to add to the result, may be negative
  * @param TemporalUnit $unit the unit of the amount to add, not null
  * @return Year a {@code Year} based on this year with the specified amount added, not null
  * @throws DateTimeException if the addition cannot be made
  * @throws UnsupportedTemporalTypeException if the unit is not supported
  * @throws ArithmeticException if numeric overflow occurs
  */
 public function plus($amountToAdd, TemporalUnit $unit)
 {
     if ($unit instanceof ChronoUnit) {
         switch ($unit) {
             case ChronoUnit::YEARS():
                 return $this->plusYears($amountToAdd);
             case ChronoUnit::DECADES():
                 return $this->plusYears(Math::multiplyExact($amountToAdd, 10));
             case ChronoUnit::CENTURIES():
                 return $this->plusYears(Math::multiplyExact($amountToAdd, 100));
             case ChronoUnit::MILLENNIA():
                 return $this->plusYears(Math::multiplyExact($amountToAdd, 1000));
             case ChronoUnit::ERAS():
                 return $this->with(ChronoField::ERA(), Math::addExact($this->getLong(ChronoField::ERA()), $amountToAdd));
         }
         throw new UnsupportedTemporalTypeException("Unsupported unit: " . $unit);
     }
     return $unit->addTo($this, $amountToAdd);
 }
Example #4
0
 /**
  * Converts this duration to the total length in nanoseconds expressed as a {@code long}.
  * <p>
  * If this duration is too large to fit in a {@code long} nanoseconds, then an
  * exception is thrown.
  *
  * @return int the total length of the duration in nanoseconds
  * @throws ArithmeticException if numeric overflow occurs
  */
 public function toNanos()
 {
     $totalNanos = Math::multiplyExact($this->seconds, LocalTime::NANOS_PER_SECOND);
     $totalNanos = Math::addExact($totalNanos, $this->nanos);
     return $totalNanos;
 }
Example #5
0
 private function resolveTime($hod, $moh, $som, $nos)
 {
     if ($this->resolverStyle == ResolverStyle::LENIENT()) {
         $totalNanos = Math::multiplyExact($hod, 3600000000000);
         $totalNanos = Math::addExact($totalNanos, Math::multiplyExact($moh, 60000000000));
         $totalNanos = Math::addExact($totalNanos, Math::multiplyExact($som, 1000000000));
         $totalNanos = Math::addExact($totalNanos, $nos);
         $excessDays = (int) Math::floorDiv($totalNanos, 86400000000000);
         // safe int cast
         $nod = Math::floorMod($totalNanos, 86400000000000);
         $this->updateCheckConflict(LocalTime::ofNanoOfDay($nod), Period::ofDays($excessDays));
     } else {
         // STRICT or SMART
         $mohVal = CF::MINUTE_OF_HOUR()->checkValidIntValue($moh);
         $nosVal = CF::NANO_OF_SECOND()->checkValidIntValue($nos);
         // handle 24:00 end of day
         if ($this->resolverStyle == ResolverStyle::SMART() && $hod == 24 && $mohVal == 0 && $som == 0 && $nosVal == 0) {
             $this->updateCheckConflict(LocalTime::MIDNIGHT(), Period::ofDays(1));
         } else {
             $hodVal = CF::HOUR_OF_DAY()->checkValidIntValue($hod);
             $somVal = CF::SECOND_OF_MINUTE()->checkValidIntValue($som);
             $this->updateCheckConflict(LocalTime::of($hodVal, $mohVal, $somVal, $nosVal), Period::ZERO());
         }
     }
 }
Example #6
0
 public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle)
 {
     $yearLong = $fieldValues->get(ChronoField::YEAR());
     $qoyLong = $fieldValues->get(IsoFields::QUARTER_OF_YEAR());
     if ($yearLong === null || $qoyLong === null) {
         return null;
     }
     $y = ChronoField::YEAR()->checkValidIntValue($yearLong);
     // always validate
     $doq = $fieldValues->get(IsoFields::DAY_OF_QUARTER());
     IsoFields::ensureIso($partialTemporal);
     if ($resolverStyle == ResolverStyle::LENIENT()) {
         $date = LocalDate::of($y, 1, 1)->plusMonths(Math::multiplyExact(Math::subtractExact($qoyLong, 1), 3));
         $doq = Math::subtractExact($doq, 1);
     } else {
         $qoy = IsoFields::QUARTER_OF_YEAR()->range()->checkValidIntValue($qoyLong, IsoFields::QUARTER_OF_YEAR());
         // validated
         $date = LocalDate::of($y, ($qoy - 1) * 3 + 1, 1);
         if ($doq < 1 || $doq > 90) {
             if ($resolverStyle == ResolverStyle::STRICT()) {
                 $this->rangeRefinedBy($date)->checkValidValue($doq, $this);
                 // only allow exact range
             } else {
                 // SMART
                 $this->range()->checkValidValue($doq, $this);
                 // allow 1-92 rolling into next quarter
             }
         }
         $doq--;
     }
     $fieldValues->remove($this);
     $fieldValues->remove(ChronoField::YEAR());
     $fieldValues->remove(IsoFields::QUARTER_OF_YEAR());
     return $date->plusDays($doq);
 }
Example #7
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);
 }
 private function resolveWoY(FieldValues $fieldValues, Chronology $chrono, $year, $woy, $localDow, ResolverStyle $resolverStyle)
 {
     $date = $chrono->date($year, 1, 1);
     if ($resolverStyle == ResolverStyle::LENIENT()) {
         $weeks = Math::subtractExact($woy, $this->localizedWeekOfYear($date));
         $days = $localDow - $this->localizedDayOfWeek($date);
         // safe from overflow
         $date = $date->plus(Math::addExact(Math::multiplyExact($weeks, 7), $days), ChronoUnit::DAYS());
     } else {
         $womInt = $this->range->checkValidIntValue($woy, $this);
         // validate
         $weeks = (int) ($womInt - $this->localizedWeekOfYear($date));
         // safe from overflow
         $days = $localDow - $this->localizedDayOfWeek($date);
         // safe from overflow
         $date = $date->plus($weeks * 7 + $days, ChronoUnit::DAYS());
         if ($resolverStyle == ResolverStyle::STRICT() && $date->getLong(CF::YEAR()) !== $year) {
             throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
         }
     }
     $fieldValues->remove($this);
     $fieldValues->remove(CF::YEAR());
     $fieldValues->remove(CF::DAY_OF_WEEK());
     return $date;
 }
 public function parse(DateTimeParseContext $context, $text, $position)
 {
     // TODO cache formatter
     // new context to avoid overwriting fields like year/month/day
     $minDigits = $this->fractionalDigits < 0 ? 0 : $this->fractionalDigits;
     $maxDigits = $this->fractionalDigits < 0 ? 9 : $this->fractionalDigits;
     $parser = (new DateTimeFormatterBuilder())->append(DateTimeFormatter::ISO_LOCAL_DATE())->appendLiteral('T')->appendValue2(ChronoField::HOUR_OF_DAY(), 2)->appendLiteral(':')->appendValue2(ChronoField::MINUTE_OF_HOUR(), 2)->appendLiteral(':')->appendValue2(ChronoField::SECOND_OF_MINUTE(), 2)->appendFraction(ChronoField::NANO_OF_SECOND(), $minDigits, $maxDigits, true)->appendLiteral('Z')->toFormatter()->toPrinterParser(false);
     $newContext = $context->copy();
     $pos = $parser->parse($newContext, $text, $position);
     if ($pos < 0) {
         return $pos;
     }
     // parser restricts most fields to 2 digits, so definitely int
     // correctly parsed nano is also guaranteed to be valid
     $yearParsed = $newContext->getParsed(ChronoField::YEAR());
     $month = $newContext->getParsed(ChronoField::MONTH_OF_YEAR());
     $day = $newContext->getParsed(ChronoField::DAY_OF_MONTH());
     $hour = $newContext->getParsed(ChronoField::HOUR_OF_DAY());
     $min = $newContext->getParsed(ChronoField::MINUTE_OF_HOUR());
     $secVal = $newContext->getParsed(ChronoField::SECOND_OF_MINUTE());
     $nanoVal = $newContext->getParsed(ChronoField::NANO_OF_SECOND());
     $sec = $secVal !== null ? $secVal : 0;
     $nano = $nanoVal !== null ? $nanoVal : 0;
     $days = 0;
     if ($hour === 24 && $min === 0 && $sec === 0 && $nano === 0) {
         $hour = 0;
         $days = 1;
     } else {
         if ($hour === 23 && $min === 59 && $sec === 60) {
             $context->setParsedLeapSecond();
             $sec = 59;
         }
     }
     $year = $yearParsed % 10000;
     try {
         $ldt = LocalDateTime::of($year, $month, $day, $hour, $min, $sec, 0)->plusDays($days);
         $instantSecs = $ldt->toEpochSecond(ZoneOffset::UTC());
         $instantSecs += Math::multiplyExact(Math::div($yearParsed, 10000), self::SECONDS_PER_10000_YEARS);
     } catch (RuntimeException $ex) {
         // TODO What do we actually catch here and why
         return ~$position;
     }
     $successPos = $pos;
     $successPos = $context->setParsedField(ChronoField::INSTANT_SECONDS(), $instantSecs, $position, $successPos);
     return $context->setParsedField(ChronoField::NANO_OF_SECOND(), $nano, $position, $successPos);
 }
 public function until(Temporal $endExclusive, TemporalUnit $unit)
 {
     $end = $this->getChronology()->localDateTime($endExclusive);
     if ($unit instanceof ChronoUnit) {
         if ($unit->isTimeBased()) {
             $amount = $end->getLong(ChronoField::EPOCH_DAY()) - $this->date->getLong(ChronoField::EPOCH_DAY());
             switch ($unit) {
                 case ChronoUnit::NANOS():
                     $amount = Math::multiplyExact($amount, self::NANOS_PER_DAY);
                     break;
                 case ChronoUnit::MICROS():
                     $amount = Math::multiplyExact($amount, self::MICROS_PER_DAY);
                     break;
                 case ChronoUnit::MILLIS():
                     $amount = Math::multiplyExact($amount, self::MILLIS_PER_DAY);
                     break;
                 case ChronoUnit::SECONDS():
                     $amount = Math::multiplyExact($amount, self::SECONDS_PER_DAY);
                     break;
                 case ChronoUnit::MINUTES():
                     $amount = Math::multiplyExact($amount, self::MINUTES_PER_DAY);
                     break;
                 case ChronoUnit::HOURS():
                     $amount = Math::multiplyExact($amount, self::HOURS_PER_DAY);
                     break;
                 case ChronoUnit::HALF_DAYS():
                     $amount = Math::multiplyExact($amount, 2);
                     break;
             }
             return Math::addExact($amount, $this->time->until($end->toLocalTime(), $unit));
         }
         $endDate = $end->toLocalDate();
         if ($end->toLocalTime()->isBefore($this->time)) {
             $endDate = $endDate->minus(1, ChronoUnit::DAYS());
         }
         return $this->date->until($endDate, $unit);
     }
     return $unit->between($this, $end);
 }
Example #11
0
 /**
  * Gets the total number of months in this period.
  * <p>
  * This returns the total number of months in the period by multiplying the
  * number of years by 12 and adding the number of months.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @return int the total number of months in the period, may be negative
  */
 public function toTotalMonths()
 {
     return Math::addExact(Math::multiplyExact($this->years, 12), $this->months);
 }