Example #1
0
 public function instant()
 {
     if ($this->tickNanos % 1000000 == 0) {
         $millis = $this->baseClock->millis();
         return Instant::ofEpochMilli($millis - Math::floorMod($millis, $this->tickNanos / 1000000));
     }
     $instant = $this->baseClock->instant();
     $nanos = $instant->getNano();
     $adjust = Math::floorMod($nanos, $this->tickNanos);
     return $instant->minusNanos($adjust);
 }
Example #2
0
 /**
  * Obtains the current time from the specified clock.
  * <p>
  * This will query the specified clock to obtain the current time.
  * Using this method allows the use of an alternate clock for testing.
  * The alternate clock may be introduced using {@link Clock dependency injection}.
  *
  * @param Clock $clock the clock to use, not null
  * @return LocalTime the current time, not null
  */
 public static function nowOf(Clock $clock)
 {
     // inline OffsetTime factory to avoid creating object and InstantProvider checks
     $now = $clock->instant();
     // called once
     $offset = $clock->getZone()->getRules()->getOffset($now);
     $localSecond = $now->getEpochSecond() + $offset->getTotalSeconds();
     // overflow caught later
     $secsOfDay = (int) Math::floorMod($localSecond, self::SECONDS_PER_DAY);
     return self::ofNanoOfDay($secsOfDay * self::NANOS_PER_SECOND + $now->getNano());
 }
Example #3
0
 /**
  * Returns a copy of this {@code LocalDate} with the specified number of months added.
  * <p>
  * This method adds the specified amount to the months field in three steps:
  * <ol>
  * <li>Add the input months to the month-of-year field</li>
  * <li>Check if the resulting date would be invalid</li>
  * <li>Adjust the day-of-month to the last valid day if necessary</li>
  * </ol>
  * <p>
  * For example, 2007-03-31 plus one month would result in the invalid date
  * 2007-04-31. Instead of returning an invalid result, the last valid day
  * of the month, 2007-04-30, is selected instead.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @param int $monthsToAdd the months to add, may be negative
  * @return LocalDate a {@code LocalDate} based on this date with the months added, not null
  * @throws DateTimeException if the result exceeds the supported date range
  */
 public function plusMonths($monthsToAdd)
 {
     if ($monthsToAdd === 0) {
         return $this;
     }
     $monthCount = $this->year * 12 + ($this->month - 1);
     $calcMonths = $monthCount + $monthsToAdd;
     // safe overflow
     if (!is_int($calcMonths)) {
         throw new DateTimeException('Overflow');
         // Todo better message
     }
     $newYear = ChronoField::YEAR()->checkValidIntValue(Math::floorDiv($calcMonths, 12));
     $newMonth = Math::floorMod($calcMonths, 12) + 1;
     return self::resolvePreviousValid($newYear, $newMonth, $this->day);
 }
Example #4
0
 /**
  * Obtains an instance of {@code Instant} using milliseconds from the
  * epoch of 1970-01-01T00:00:00Z.
  * <p>
  * The seconds and nanoseconds are extracted from the specified milliseconds.
  *
  * @param int $epochMilli the number of milliseconds from 1970-01-01T00:00:00Z
  * @return Instant an instant, not null
  * @throws DateTimeException if the instant exceeds the maximum or minimum instant
  */
 public static function ofEpochMilli($epochMilli)
 {
     $secs = Math::floorDiv($epochMilli, 1000);
     $mos = (int) Math::floorMod($epochMilli, 1000);
     return self::create($secs, $mos * 1000000);
 }
Example #5
0
 protected function resolveProlepticMonth(FieldValues $fieldValues, ResolverStyle $resolverStyle)
 {
     $pMonth = $fieldValues->remove(CF::PROLEPTIC_MONTH());
     if ($pMonth !== null) {
         if ($resolverStyle != ResolverStyle::LENIENT()) {
             CF::PROLEPTIC_MONTH()->checkValidValue($pMonth);
         }
         $this->addFieldValue($fieldValues, CF::MONTH_OF_YEAR(), Math::floorMod($pMonth, 12) + 1);
         $this->addFieldValue($fieldValues, CF::YEAR(), Math::floorDiv($pMonth, 12));
     }
 }
 /**
  * @dataProvider data_weekFields
  */
 public function test_weekOfWeekBasedYearField(DayOfWeek $firstDayOfWeek, $minDays)
 {
     $day = LocalDate::of(2012, 12, 31);
     // Known to be ISO Monday
     $weekDef = WeekFields::of($firstDayOfWeek, $minDays);
     $dowField = $weekDef->dayOfWeek();
     $wowbyField = $weekDef->weekOfWeekBasedYear();
     $yowbyField = $weekDef->weekBasedYear();
     for ($i = 1; $i <= 15; $i++) {
         $actualDOW = $day->get($dowField);
         $actualWOWBY = $day->get($wowbyField);
         $actualYOWBY = $day->get($yowbyField);
         // Verify that the combination of $day of $week and $week of month can be used
         // to reconstruct the same $date.
         $day1 = LocalDate::of($actualYOWBY, 1, 1);
         $isoDOW = $day1->getDayOfWeek();
         $dow = (7 + $isoDOW->getValue() - $firstDayOfWeek->getValue()) % 7 + 1;
         $weekStart = Math::floorMod(1 - $dow, 7);
         if ($weekStart + 1 > $weekDef->getMinimalDaysInFirstWeek()) {
             // The previous $week has the minimum days in the current month to be a '$week'
             $weekStart -= 7;
         }
         $weekStart += $actualDOW - 1;
         $weekStart += ($actualWOWBY - 1) * 7;
         $result = $day1->plusDays($weekStart);
         $this->assertEquals($result, $day, "Incorrect dayOfWeek or weekOfYear " . sprintf("%s, ISO Dow: %s, weekStart: %s, actualDOW: %s, actualWOWBY: %s, YearOfWBY: %d, expected day: %s, result: %s\n", $weekDef, $day->getDayOfWeek(), $weekStart, $actualDOW, $actualWOWBY, $actualYOWBY, $day, $result));
         $day = $day->plusDays(1);
     }
 }
Example #7
0
 /**
  * Obtains a {@code Duration} representing a number of seconds and an
  * adjustment in nanoseconds.
  * <p>
  * This method allows an arbitrary number of nanoseconds to be passed in.
  * The factory will alter the values of the second and nanosecond in order
  * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
  * For example, the following will result in the exactly the same duration:
  * <pre>
  *  Duration.ofSeconds(3, 1);
  *  Duration.ofSeconds(4, -999_999_999);
  *  Duration.ofSeconds(2, 1000_000_001);
  * </pre>
  *
  * @param int $seconds the number of seconds, positive or negative
  * @param int $nanoAdjustment the nanosecond adjustment to the number of seconds, positive or negative
  * @return Duration a {@code Duration}, not null
  * @throws ArithmeticException if the adjustment causes the seconds to exceed the capacity of {@code Duration}
  */
 public static function ofSeconds($seconds, $nanoAdjustment = 0)
 {
     $secs = Math::addExact($seconds, Math::floorDiv($nanoAdjustment, LocalTime::NANOS_PER_SECOND));
     $nos = Math::floorMod($nanoAdjustment, LocalTime::NANOS_PER_SECOND);
     return self::create($secs, $nos);
 }
Example #8
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 #9
0
 /**
  * Returns a copy of this {@code LocalDateTime} with the specified period added.
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @param LocalDate $newDate the new date to base the calculation on, not null
  * @param int $hours the hours to add, may be negative
  * @param int $minutes the minutes to add, may be negative
  * @param int $seconds the seconds to add, may be negative
  * @param int $nanos the nanos to add, may be negative
  * @param int $sign the sign to determine add or subtract
  * @return LocalDateTime the combined result, not null
  */
 private function plusWithOverflow(LocalDate $newDate, $hours, $minutes, $seconds, $nanos, $sign)
 {
     // 9223372036854775808 long, 2147483648 int
     if (($hours | $minutes | $seconds | $nanos) == 0) {
         return $this->_with($newDate, $this->time);
     }
     $totDays = Math::div($nanos, LocalTime::NANOS_PER_DAY) + Math::div($seconds, LocalTime::SECONDS_PER_DAY) + Math::div($minutes, LocalTime::MINUTES_PER_DAY) + Math::div($hours, LocalTime::HOURS_PER_DAY);
     //   max/24
     $totDays *= $sign;
     // total max*0.4237...
     $totNanos = $nanos % LocalTime::NANOS_PER_DAY + $seconds % LocalTime::SECONDS_PER_DAY * LocalTime::NANOS_PER_SECOND + $minutes % LocalTime::MINUTES_PER_DAY * LocalTime::NANOS_PER_MINUTE + $hours % LocalTime::HOURS_PER_DAY * LocalTime::NANOS_PER_HOUR;
     //   max  86400000000000
     $curNoD = $this->time->toNanoOfDay();
     //   max  86400000000000
     $totNanos = $totNanos * $sign + $curNoD;
     // total 432000000000000
     $totDays += Math::floorDiv($totNanos, LocalTime::NANOS_PER_DAY);
     $newNoD = Math::floorMod($totNanos, LocalTime::NANOS_PER_DAY);
     $newTime = $newNoD === $curNoD ? $this->time : LocalTime::ofNanoOfDay($newNoD);
     return $this->_with($newDate->plusDays($totDays), $newTime);
 }
 public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle)
 {
     $value = $fieldValues->get($this);
     $newValue = Math::toIntExact($value);
     // broad limit makes overflow checking lighter
     // first convert localized day-of-week to ISO day-of-week
     // doing this first handles case where both ISO and localized were parsed and might mismatch
     // day-of-week is always strict as two different day-of-week values makes lenient complex
     if ($this->rangeUnit == ChronoUnit::WEEKS()) {
         // day-of-week
         $checkedValue = $this->range->checkValidIntValue($value, $this);
         // no leniency as too complex
         $startDow = $this->weekDef->getFirstDayOfWeek()->getValue();
         $isoDow = Math::floorMod($startDow - 1 + ($checkedValue - 1), 7) + 1;
         $fieldValues->remove($this);
         $fieldValues->put(CF::DAY_OF_WEEK(), $isoDow);
         return null;
     }
     // can only build date if ISO day-of-week is present
     if (!$fieldValues->has(CF::DAY_OF_WEEK())) {
         return null;
     }
     $isoDow = CF::DAY_OF_WEEK()->checkValidIntValue($fieldValues->get(CF::DAY_OF_WEEK()));
     $dow = $this->localizedDayOfWeekNumerical($isoDow);
     // build date
     $chrono = AbstractChronology::from($partialTemporal);
     if ($fieldValues->has(CF::YEAR())) {
         $year = CF::YEAR()->checkValidIntValue($fieldValues->get(CF::YEAR()));
         // validate
         if ($this->rangeUnit == ChronoUnit::MONTHS() && $fieldValues->has(CF::MONTH_OF_YEAR())) {
             // week-of-month
             $month = $fieldValues->get(CF::MONTH_OF_YEAR());
             // not validated yet
             return $this->resolveWoM($fieldValues, $chrono, $year, $month, $newValue, $dow, $resolverStyle);
         }
         if ($this->rangeUnit == ChronoUnit::YEARS()) {
             // week-of-year
             return $this->resolveWoY($fieldValues, $chrono, $year, $newValue, $dow, $resolverStyle);
         }
     } else {
         if (($this->rangeUnit == IsoFields::WEEK_BASED_YEARS() || $this->rangeUnit == ChronoUnit::FOREVER()) && $fieldValues->has($this->weekDef->weekBasedYear) && $fieldValues->has($this->weekDef->weekOfWeekBasedYear)) {
             // week-of-week-based-year and year-of-week-based-year
             return $this->resolveWBY($fieldValues, $chrono, $dow, $resolverStyle);
         }
     }
     return null;
 }
 public function format(DateTimePrintContext $context, &$buf)
 {
     // use INSTANT_SECONDS, thus this code is not bound by Instant.MAX
     $inSecs = $context->getValueField(ChronoField::INSTANT_SECONDS());
     $inNanos = null;
     if ($context->getTemporal()->isSupported(ChronoField::NANO_OF_SECOND())) {
         $inNanos = $context->getTemporal()->getLong(ChronoField::NANO_OF_SECOND());
     }
     if ($inSecs === null) {
         return false;
     }
     $inSec = $inSecs;
     $inNano = ChronoField::NANO_OF_SECOND()->checkValidIntValue($inNanos !== null ? $inNanos : 0);
     // format mostly using LocalDateTime.toString
     if ($inSec >= -self::SECONDS_0000_TO_1970) {
         // current era
         $zeroSecs = $inSec - self::SECONDS_PER_10000_YEARS + self::SECONDS_0000_TO_1970;
         $hi = Math::floorDiv($zeroSecs, self::SECONDS_PER_10000_YEARS) + 1;
         $lo = Math::floorMod($zeroSecs, self::SECONDS_PER_10000_YEARS);
         $ldt = LocalDateTime::ofEpochSecond($lo - self::SECONDS_0000_TO_1970, 0, ZoneOffset::UTC());
         if ($hi > 0) {
             $buf .= '+' . $hi;
         }
         $buf .= $ldt;
         if ($ldt->getSecond() === 0) {
             $buf .= ":00";
         }
     } else {
         // before current era
         $zeroSecs = $inSec + self::SECONDS_0000_TO_1970;
         $hi = Math::div($zeroSecs, self::SECONDS_PER_10000_YEARS);
         $lo = $zeroSecs % self::SECONDS_PER_10000_YEARS;
         $ldt = LocalDateTime::ofEpochSecond($lo - self::SECONDS_0000_TO_1970, 0, ZoneOffset::UTC());
         $pos = strlen($buf);
         $buf .= $ldt;
         if ($ldt->getSecond() === 0) {
             $buf .= ":00";
         }
         if ($hi < 0) {
             if ($ldt->getYear() === -10000) {
                 $buf = substr_replace($buf, $hi - 1, $pos, 2);
             } else {
                 if ($lo === 0) {
                     $buf = substr_replace($buf, $hi, $pos, 0);
                 } else {
                     $buf = substr_replace($buf, Math::abs($hi), $pos + 1, 0);
                 }
             }
         }
     }
     // add fraction
     if ($this->fractionalDigits < 0 && $inNano > 0 || $this->fractionalDigits > 0) {
         $buf .= '.';
         $div = 100000000;
         for ($i = 0; $this->fractionalDigits === -1 && $inNano > 0 || $this->fractionalDigits === -2 && ($inNano > 0 || $i % 3 !== 0) || $i < $this->fractionalDigits; $i++) {
             $digit = Math::div($inNano, $div);
             $buf .= $digit;
             $inNano = $inNano - $digit * $div;
             $div = Math::div($div, 10);
         }
     }
     $buf .= 'Z';
     return true;
 }
Example #12
0
 /**
  * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
  * <p>
  * This creates an offset time with the same instant as that specified.
  * Finding the offset from UTC/Greenwich is simple as there is only one valid
  * offset for each instant.
  * <p>
  * The date component of the instant is dropped during the conversion.
  * This means that the conversion can never fail due to the instant being
  * out of the valid range of dates.
  *
  * @param Instant $instant the instant to create the time from, not null
  * @param ZoneId $zone the time-zone, which may be an offset, not null
  * @return OffsetTime the offset time, not null
  */
 public static function ofInstant(Instant $instant, ZoneId $zone)
 {
     $rules = $zone->getRules();
     $offset = $rules->getOffset($instant);
     $localSecond = $instant->getEpochSecond() + $offset->getTotalSeconds();
     // overflow caught later
     $secsOfDay = (int) Math::floorMod($localSecond, LocalTime::SECONDS_PER_DAY);
     $time = LocalTime::ofNanoOfDay($secsOfDay * LocalTime::NANOS_PER_SECOND + $instant->getNano());
     return new OffsetTime($time, $offset);
 }