public function format(DateTimePrintContext $context, &$buf) { $offsetSecs = $context->getValueField(ChronoField::OFFSET_SECONDS()); if ($offsetSecs === null) { return false; } $totalSecs = $offsetSecs; if ($totalSecs === 0) { $buf .= $this->noOffsetText; } else { $absHours = Math::abs($totalSecs / 3600 % 100); // anything larger than 99 silently dropped $absMinutes = Math::abs($totalSecs / 60 % 60); $absSeconds = Math::abs($totalSecs % 60); $bufPos = strlen($buf); $output = $absHours; $buf .= ($totalSecs < 0 ? "-" : "+") . Math::div($absHours, 10) . $absHours % 10; if ($this->type >= 3 || $this->type >= 1 && $absMinutes > 0) { $buf .= ($this->type % 2 === 0 ? ":" : "") . Math::div($absMinutes, 10) . $absMinutes % 10; $output += $absMinutes; if ($this->type >= 7 || $this->type >= 5 && $absSeconds > 0) { $buf .= ($this->type % 2 === 0 ? ":" : "") . Math::div($absSeconds, 10) . $absSeconds % 10; $output += $absSeconds; } } if ($output === 0) { $buf = substr($buf, 0, $bufPos); $buf .= $this->noOffsetText; } } return true; }
public function getFrom(TemporalAccessor $temporal) { if ($this->isSupportedBy($temporal) == false) { throw new UnsupportedTemporalTypeException("Unsupported field: QuarterOfYear"); } $moy = $temporal->getLong(ChronoField::MONTH_OF_YEAR()); return Math::div($moy + 2, 3); }
public function getFrom(TemporalAccessor $temporal) { if ($this->isSupportedBy($temporal) == false) { throw new UnsupportedTemporalTypeException("Unsupported field: DayOfQuarter"); } $doy = $temporal->get(ChronoField::DAY_OF_YEAR()); $moy = $temporal->get(ChronoField::MONTH_OF_YEAR()); $year = $temporal->getLong(ChronoField::YEAR()); $quarterDays = [0, 90, 181, 273, 0, 91, 182, 274]; return $doy - $quarterDays[Math::div($moy - 1, 3) + (IsoChronology::INSTANCE()->isLeapYear($year) ? 4 : 0)]; }
public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle) { $wbyLong = $fieldValues->get(IsoFields::WEEK_BASED_YEAR()); $dowLong = $fieldValues->get(ChronoField::DAY_OF_WEEK()); if ($wbyLong === null || $dowLong === null) { return null; } $wby = IsoFields::WEEK_BASED_YEAR()->range()->checkValidIntValue($wbyLong, IsoFields::WEEK_BASED_YEAR()); // always validate $wowby = $fieldValues->get(IsoFields::WEEK_OF_WEEK_BASED_YEAR()); IsoFields::ensureIso($partialTemporal); $date = LocalDate::of($wby, 1, 4); if ($resolverStyle == ResolverStyle::LENIENT()) { $dow = $dowLong; // unvalidated if ($dow > 7) { $date = $date->plusWeeks(Math::div($dow - 1, 7)); $dow = ($dow - 1) % 7 + 1; } else { if ($dow < 1) { $date = $date->plusWeeks(Math::div(Math::subtractExact($dow, 7), 7)); $dow = ($dow + 6) % 7 + 1; } } $date = $date->plusWeeks(Math::subtractExact($wowby, 1))->with(ChronoField::DAY_OF_WEEK(), $dow); } else { $dow = ChronoField::DAY_OF_WEEK()->checkValidIntValue($dowLong); // validated if ($wowby < 1 || $wowby > 52) { if ($resolverStyle == ResolverStyle::STRICT()) { IsoFields::getWeekRange($date)->checkValidValue($wowby, $this); // only allow exact range } else { // SMART $this->range()->checkValidValue($wowby, $this); // allow 1-53 rolling into next year } } $date = $date->plusWeeks($wowby - 1)->with(ChronoField::DAY_OF_WEEK(), $dow); } $fieldValues->remove($this); $fieldValues->remove(IsoFields::WEEK_BASED_YEAR()); $fieldValues->remove(ChronoField::DAY_OF_WEEK()); return $date; }
public function format(DateTimePrintContext $context, &$buf) { $offsetSecs = $context->getValueField(ChronoField::OFFSET_SECONDS()); if ($offsetSecs === null) { return false; } $gmtText = "GMT"; // TODO: get localized version of 'GMT' if ($gmtText !== null) { $buf .= $gmtText; } $totalSecs = Math::toIntExact($offsetSecs); if ($totalSecs !== 0) { $absHours = Math::abs($totalSecs / 3600 % 100); // anything larger than 99 silently dropped $absMinutes = Math::abs($totalSecs / 60 % 60); $absSeconds = Math::abs($totalSecs % 60); $buf .= $totalSecs < 0 ? "-" : "+"; if ($this->style == TextStyle::FULL()) { $this->appendHMS($buf, $absHours); $buf .= ':'; $this->appendHMS($buf, $absMinutes); if ($absSeconds != 0) { $buf .= ':'; $this->appendHMS($buf, $absSeconds); } } else { if ($absHours >= 10) { $buf .= Math::div($absHours, 10); } $buf .= $absHours % 10; if ($absMinutes != 0 || $absSeconds != 0) { $buf .= ':'; $this->appendHMS($buf, $absMinutes); if ($absSeconds != 0) { $buf .= ':'; self::appendHMS($buf, $absSeconds); } } } } return true; }
/** * A string representation of this duration using ISO-8601 seconds * based representation, such as {@code PT8H6M12.345S}. * <p> * The format of the returned string will be {@code PTnHnMnS}, where n is * the relevant hours, minutes or seconds part of the duration. * Any fractional seconds are placed after a decimal point i the seconds section. * If a section has a zero value, it is omitted. * The hours, minutes and seconds will all have the same sign. * <p> * Examples: * <pre> * "20.345 seconds" -- "PT20.345S * "15 minutes" (15 * 60 seconds) -- "PT15M" * "10 hours" (10 * 3600 seconds) -- "PT10H" * "2 days" (2 * 86400 seconds) -- "PT48H" * </pre> * Note that multiples of 24 hours are not output as days to avoid confusion * with {@code Period}. * * @return string an ISO-8601 representation of this duration, not null */ public function __toString() { if ($this === self::$ZERO) { return "PT0S"; } $hours = Math::div($this->seconds, LocalTime::SECONDS_PER_HOUR); $minutes = Math::div($this->seconds % LocalTime::SECONDS_PER_HOUR, LocalTime::SECONDS_PER_MINUTE); $secs = $this->seconds % LocalTime::SECONDS_PER_MINUTE; $buf = "PT"; if ($hours !== 0) { $buf .= $hours . 'H'; } if ($minutes !== 0) { $buf .= $minutes . 'M'; } if ($secs === 0 && $this->nanos === 0 && strlen($buf) > 2) { return $buf; } if ($secs < 0 && $this->nanos > 0) { if ($secs === -1) { $buf .= "-0"; } else { $buf .= $secs + 1; } } else { $buf .= $secs; } if ($this->nanos > 0) { $pos = strlen($buf); if ($secs < 0) { $buf .= 2 * LocalTime::NANOS_PER_SECOND - $this->nanos; } else { $buf .= $this->nanos + LocalTime::NANOS_PER_SECOND; } $buf = rtrim($buf, "0"); $buf[$pos] = '.'; } $buf .= 'S'; return $buf; }
/** * Calculates the amount of time until another year in terms of the specified unit. * <p> * This calculates the amount of time between two {@code Year} * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified year. * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method is converted to a * {@code Year} using {@link #from(TemporalAccessor)}. * For example, the amount in decades between two year can be calculated * using {@code startYear.until(endYear, DECADES)}. * <p> * The calculation returns a whole number, representing the number of * complete units between the two years. * For example, the amount in decades between 2012 and 2031 * will only be one decade as it is one year short of two decades. * <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, YEARS); * amount = YEARS.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 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 Year}, not null * @param TemporalUnit $unit the unit to measure the amount in, not null * @return int the amount of time between this year and the end year * @throws DateTimeException if the amount cannot be calculated, or the end * temporal cannot be converted to a {@code Year} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ public function until(Temporal $endExclusive, TemporalUnit $unit) { $end = Year::from($endExclusive); if ($unit instanceof ChronoUnit) { $yearsUntil = $end->year - $this->year; // no overflow switch ($unit) { case ChronoUnit::YEARS(): return $yearsUntil; case ChronoUnit::DECADES(): return Math::div($yearsUntil, 10); case ChronoUnit::CENTURIES(): return Math::div($yearsUntil, 100); case ChronoUnit::MILLENNIA(): return Math::div($yearsUntil, 1000); case ChronoUnit::ERAS(): return $end->getLong(ChronoField::ERA()) - $this->getLong(ChronoField::ERA()); } throw new UnsupportedTemporalTypeException("Unsupported unit: " . $unit); } return $unit->between($this, $end); }
function provider_toString() { return [[0, 0, "PT0S"], [0, 1, "PT0.000000001S"], [0, 10, "PT0.00000001S"], [0, 100, "PT0.0000001S"], [0, 1000, "PT0.000001S"], [0, 10000, "PT0.00001S"], [0, 100000, "PT0.0001S"], [0, 1000000, "PT0.001S"], [0, 10000000, "PT0.01S"], [0, 100000000, "PT0.1S"], [0, 120000000, "PT0.12S"], [0, 123000000, "PT0.123S"], [0, 123400000, "PT0.1234S"], [0, 123450000, "PT0.12345S"], [0, 123456000, "PT0.123456S"], [0, 123456700, "PT0.1234567S"], [0, 123456780, "PT0.12345678S"], [0, 123456789, "PT0.123456789S"], [1, 0, "PT1S"], [59, 0, "PT59S"], [60, 0, "PT1M"], [61, 0, "PT1M1S"], [3599, 0, "PT59M59S"], [3600, 0, "PT1H"], [3601, 0, "PT1H1S"], [3661, 0, "PT1H1M1S"], [86399, 0, "PT23H59M59S"], [86400, 0, "PT24H"], [59, 0, "PT59S"], [59, 0, "PT59S"], [-1, 0, "PT-1S"], [-1, 1000, "PT-0.999999S"], [-1, 900000000, "PT-0.1S"], [Long::MAX_VALUE, 0, "PT" . Math::div(Long::MAX_VALUE, 3600) . "H" . Math::div(Long::MAX_VALUE % 3600, 60) . "M" . Long::MAX_VALUE % 60 . "S"], [Long::MIN_VALUE, 0, "PT" . Math::div(Long::MIN_VALUE, 3600) . "H" . Math::div(Long::MIN_VALUE % 3600, 60) . "M" . Long::MIN_VALUE % 60 . "S"]]; }
/** * @group long */ public function test_tick_ClockDuration_20nanos() { for ($i = 0; $i < 1000; $i++) { $test = Clock::tick(Clock::fixed(self::ZDT()->withNano($i)->toInstant(), self::PARIS()), Duration::ofNanos(20)); $this->assertEquals($test->instant(), self::ZDT()->withNano(Math::div($i, 20) * 20)->toInstant()); $this->assertEquals($test->getZone(), self::PARIS()); } }
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); }
/** * 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); }
public function toEpochDay() { $y = $this->year; $m = $this->month; $total = 0; $total += 365 * $y; if ($y >= 0) { $total += Math::div($y + 3, 4) - Math::div($y + 99, 100) + Math::div($y + 399, 400); } else { $total -= Math::div($y, -4) - Math::div($y, -100) + Math::div($y, -400); } $total += Math::div(367 * $m - 362, 12); $total += $this->day - 1; if ($m > 2) { $total--; if ($this->isLeapYear() == false) { $total--; } } return $total - self::DAYS_0000_TO_1970; }
private function resolveFractional() { // ensure fractional seconds available as CF requires // resolveTimeLenient() will have merged CF::MICRO_OF_SECOND()/MILLI_OF_SECOND to NANO_OF_SECOND if ($this->time == null && ($this->fieldValues->has(CF::INSTANT_SECONDS()) || $this->fieldValues->has(CF::SECOND_OF_DAY()) || $this->fieldValues->has(CF::SECOND_OF_MINUTE()))) { if ($this->fieldValues->has(CF::NANO_OF_SECOND())) { $nos = $this->fieldValues->get(CF::NANO_OF_SECOND()); $this->fieldValues->put(CF::MICRO_OF_SECOND(), Math::div($nos, 1000)); $this->fieldValues->put(CF::MILLI_OF_SECOND(), Math::div($nos, 1000000)); } else { $this->fieldValues->put(CF::NANO_OF_SECOND(), 0); $this->fieldValues->put(CF::MICRO_OF_SECOND(), 0); $this->fieldValues->put(CF::MILLI_OF_SECOND(), 0); } } }
private static function buildId($totalSeconds) { if ($totalSeconds === 0) { return "Z"; } else { $absTotalSeconds = Math::abs($totalSeconds); $buf = ''; $absHours = Math::div($absTotalSeconds, LocalTime::SECONDS_PER_HOUR); $absMinutes = Math::div($absTotalSeconds, LocalTime::SECONDS_PER_MINUTE) % LocalTime::MINUTES_PER_HOUR; $buf .= ($totalSeconds < 0 ? "-" : "+") . ($absHours < 10 ? "0" : "") . $absHours . ($absMinutes < 10 ? ":0" : ":") . $absMinutes; $absSeconds = $absTotalSeconds % LocalTime::SECONDS_PER_MINUTE; if ($absSeconds !== 0) { $buf .= ($absSeconds < 10 ? ":0" : ":") . $absSeconds; } return $buf; } }
/** * 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); }
/** * @expectedException \Celest\ArithmeticException */ public function test_multipliedBy_overflowTooSmall() { $test = Period::ofYears(Math::div(Long::MIN_VALUE, 2) - 1); $test->multipliedBy(2); }
function minusNanos_fromZero() { $delta = 7500000000; $hour = 22; $min = 59; $sec = 0; $nanos = 0; $ret = []; for ($i = 3660 * 1000000000; $i >= -3660 * 1000000000;) { $ret[] = [$i, $hour, $min, $sec, $nanos]; $i -= $delta; $nanos += $delta; if ($nanos >= 1000000000) { $sec += Math::div($nanos, 1000000000); $nanos %= 1000000000; if ($sec >= 60) { $min++; $sec %= 60; if ($min == 60) { $hour++; $min = 0; if ($hour == 24) { $hour = 0; } } } } } return $ret; }
/** * @param int $dividend * @param int $divisor * @return int */ public static function floorDiv($dividend, $divisor) { if (\function_exists('\\intdiv')) { $r = \intdiv($dividend, $divisor); } else { $r = Math::div($dividend, $divisor); } if (($dividend ^ $divisor) < 0 && $r * $divisor !== $dividend) { $r--; } return $r; }
/** * Returns the week number computed from the reference day and reference dayOfWeek. * * @param int $offset the offset to align a date with the start of week * from {@link #startOfWeekOffset}. * @param int $day the day for which to compute the week number * @return int the week number where zero is used for a partial week and 1 for the first full week */ private function computeWeek($offset, $day) { return Math::div(7 + $offset + ($day - 1), 7); }
public function test_minusMonths_long_big() { $test = YearMonth::of(40, 6); $months = 20 + Integer::MAX_VALUE; $this->assertEquals($test->minusMonths($months), YearMonth::of(40 - Math::div($months, 12), 6 - $months % 12)); }
/** * @expectedException \Celest\ArithmeticException */ public function test_toEpochMilli_tooSmall() { Instant::ofEpochSecond(Math::div(Long::MIN_VALUE, 1000) - 1)->toEpochMilli(); }
function minusNanos_fromZero() { $delta = 7500000000; $date = self::TEST_200707_15_12_30_40_987654321()->toLocalDate()->minusDays(1); $hour = 22; $min = 59; $sec = 0; $nanos = 0; $ret = []; for ($i = 3660 * 1000000000; $i >= -3660 * 1000000000;) { $ret[] = [$i, $date, $hour, $min, $sec, $nanos]; $nanos += $delta; $i -= $delta; if ($nanos >= 1000000000) { $sec += Math::div($nanos, 1000000000); $nanos %= 1000000000; if ($sec >= 60) { $min++; $sec %= 60; if ($min == 60) { $hour++; $min = 0; if ($hour == 24) { $hour = 0; $date = $date->plusDays(1); } } } } } return $ret; }
/** * @internal * @param LocalDate $date * @return bool|int */ public static function getWeek(LocalDate $date) { $dow0 = $date->getDayOfWeek()->getValue() - 1; $doy0 = $date->getDayOfYear() - 1; $doyThu0 = $doy0 + (3 - $dow0); // adjust to mid-week Thursday (which is 3 indexed from zero) $alignedWeek = Math::div($doyThu0, 7); $firstThuDoy0 = $doyThu0 - $alignedWeek * 7; $firstMonDoy0 = $firstThuDoy0 - 3; if ($firstMonDoy0 < -3) { $firstMonDoy0 += 7; } if ($doy0 < $firstMonDoy0) { return self::getWeekRange($date->withDayOfYear(180)->minusYears(1))->getMaximum(); } $week = Math::div($doy0 - $firstMonDoy0, 7) + 1; if ($week == 53) { if (($firstMonDoy0 == -3 || $firstMonDoy0 == -2 && $date->isLeapYear()) == false) { $week = 1; } } return $week; }
public function test_factory_ofInstant_maxWithMaxOffset() { $days_0000_to_1970 = 146097 * 5 - (30 * 365 + 7); $year = Year::MAX_VALUE; $days = $year * 365 + (Math::div($year, 4) - Math::div($year, 100) + Math::div($year, 400)) + 365 - $days_0000_to_1970; $instant = Instant::ofEpochSecond(($days + 1) * 24 * 60 * 60 - 1 - self::OFFSET_MAX()->getTotalSeconds()); $test = ZonedDateTime::ofInstant($instant, self::OFFSET_MAX()); $this->assertEquals($test->getYear(), Year::MAX_VALUE); $this->assertEquals($test->getMonth()->getValue(), 12); $this->assertEquals($test->getDayOfMonth(), 31); $this->assertEquals($test->getOffset(), self::OFFSET_MAX()); $this->assertEquals($test->getHour(), 23); $this->assertEquals($test->getMinute(), 59); $this->assertEquals($test->getSecond(), 59); $this->assertEquals($test->getNano(), 0); }
public function test_plusMonths_long_big() { $months = 20 + Integer::MAX_VALUE; $test = LocalDate::of(-40, 6, 1)->plusMonths($months); $this->assertEquals($test, LocalDate::of(-40 + Math::div($months, 12), 6 + $months % 12, 1)); }
/** * Outputs this time as a {@code String}, such as {@code 10:15}. * <p> * The output will be one of the following ISO-8601 formats: * <ul> * <li>{@code HH:mm}</li> * <li>{@code HH:mm:ss}</li> * <li>{@code HH:mm:ss.SSS}</li> * <li>{@code HH:mm:ss.SSSSSS}</li> * <li>{@code HH:mm:ss.SSSSSSSSS}</li> * </ul> * The format used will be the shortest that outputs the full value of * the time where the omitted parts are implied to be zero. * * @return string a string representation of this time, not null */ public function __toString() { $buf = ""; $hourValue = $this->hour; $minuteValue = $this->minute; $secondValue = $this->second; $nanoValue = $this->nano; $buf .= ($hourValue < 10 ? "0" : "") . $hourValue . ($minuteValue < 10 ? ":0" : ":") . $minuteValue; if ($secondValue > 0 || $nanoValue > 0) { $buf .= ($secondValue < 10 ? ":0" : ":") . $secondValue; if ($nanoValue > 0) { $buf .= '.'; if ($nanoValue % 1000000 == 0) { $buf .= substr(Math::div($nanoValue, 1000000) + 1000, 1); } else { if ($nanoValue % 1000 == 0) { $buf .= substr(Math::div($nanoValue, 1000) + 1000000, 1); } else { $buf .= substr($nanoValue + 1000000000, 1); } } } } return $buf; }
public function between(Temporal $temporal1Inclusive, Temporal $temporal2Exclusive) { if (get_class($temporal1Inclusive) !== get_class($temporal2Exclusive)) { return $temporal1Inclusive->until($temporal2Exclusive, $this); } switch ($this) { case self::WEEK_BASED_YEARS(): return Math::subtractExact($temporal2Exclusive->getLong(IsoFields::WEEK_BASED_YEAR()), $temporal1Inclusive->getLong(IsoFields::WEEK_BASED_YEAR())); case self::QUARTER_YEARS(): return Math::div($temporal1Inclusive->until($temporal2Exclusive, ChronoUnit::MONTHS()), 3); default: throw new IllegalStateException("Unreachable"); } }
/** * Returns a copy of this period with the years and months normalized. * <p> * This normalizes the years and months units, leaving the days unit unchanged. * The months unit is adjusted to have an absolute value less than 11, * with the years unit being adjusted to compensate. For example, a period of * "1 Year and 15 months" will be normalized to "2 years and 3 months". * <p> * The sign of the years and months units will be the same after normalization. * For example, a period of "1 year and -25 months" will be normalized to * "-1 year and -1 month". * <p> * This instance is immutable and unaffected by this method call. * * @return Period a {@code Period} based on this period with excess months normalized to years, not null * @throws ArithmeticException if numeric overflow occurs */ public function normalized() { $totalMonths = $this->toTotalMonths(); $splitYears = Math::div($totalMonths, 12); $splitMonths = $totalMonths % 12; // no overflow if ($splitYears === $this->years && $splitMonths === $this->months) { return $this; } return $this->create(Math::toIntExact($splitYears), $splitMonths, $this->days); }
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); }