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 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); }
public function getValue(DateTimePrintContext $context, $value) { $absValue = Math::abs($value); $baseValue = $this->baseValue; if ($this->baseDate != null) { $chrono = AbstractChronology::from($context->getTemporal()); $baseValue = $chrono->dateFrom($this->baseDate)->get($this->field); } if ($value >= $baseValue && $value < $baseValue + self::$EXCEED_POINTS[$this->minWidth]) { // Use the reduced value if it fits in minWidth return $absValue % self::$EXCEED_POINTS[$this->minWidth]; } // Otherwise truncate to fit in maxWidth return $absValue % self::$EXCEED_POINTS[$this->maxWidth]; }
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; }
/** * 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 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); }
/** * 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); }
/** * Returns a copy of this date with the specified number of weeks added. * <p> * This adds the specified period in weeks to the date. * In some cases, adding weeks can cause the resulting date to become invalid. * If this occurs, then other fields will be adjusted to ensure that the result is valid. * <p> * The default implementation uses {@link #plusDays(long)} using a 7 day week. * <p> * This instance is immutable and unaffected by this method call. * * @param int $weeksToAdd the weeks to add, may be negative * @return static a date based on this one with the weeks added, not null * @throws DateTimeException if the result exceeds the supported date range */ function plusWeeks($weeksToAdd) { return $this->plusDays(Math::multiplyExact($weeksToAdd, 7)); }
public function millis() { $tofd = \gettimeofday(); return $tofd['sec'] * 1000 + Math::floorDiv($tofd['usec'], 1000); }
/** * @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; }
protected function resolveAligned(ChronoLocalDate $base, $months, $weeks, $dow) { $date = $base->plus($months, ChronoUnit::MONTHS())->plus($weeks, ChronoUnit::WEEKS()); if ($dow > 7) { $date = $date->plus(($dow - 1) / 7, ChronoUnit::WEEKS()); $dow = ($dow - 1) % 7 + 1; } else { if ($dow < 1) { $date = $date->plus(Math::subtractExact($dow, 7) / 7, ChronoUnit::WEEKS()); $dow = ($dow + 6) % 7 + 1; } } return $date->adjust(TemporalAdjusters::nextOrSame(DayOfWeek::of((int) $dow))); }
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); }
private function findYear($epochSecond, ZoneOffset $offset) { // inline for performance $localSecond = $epochSecond + $offset->getTotalSeconds(); $localEpochDay = Math::floorDiv($localSecond, 86400); return LocalDate::ofEpochDay($localEpochDay)->getYear(); }
/** * @dataProvider data_weekFields */ public function test_withWeekOfWeekBasedYear(DayOfWeek $firstDayOfWeek, $minDays) { $day = LocalDate::of(2012, 12, 31); $week = WeekFields::of($firstDayOfWeek, $minDays); $dowField = $week->dayOfWeek(); $wowbyField = $week->weekOfWeekBasedYear(); $yowbyField = $week->weekBasedYear(); $dowExpected = ($day->get($dowField) - 1) % 7 + 1; $dowDate = $day->with($dowField, $dowExpected); $dowResult = $dowDate->get($dowField); $this->assertEquals($dowResult, $dowExpected, "Localized DayOfWeek not correct; " . $day . " -->" . $dowDate); $weekExpected = $day->get($wowbyField) + 1; $range = $day->range($wowbyField); $weekExpected = ($weekExpected - 1) % (int) $range->getMaximum() + 1; $weekDate = $day->with($wowbyField, $weekExpected); $weekResult = $weekDate->get($wowbyField); $this->assertEquals($weekResult, $weekExpected, "Localized WeekOfWeekBasedYear not correct; " . $day . " -->" . $weekDate); $yearExpected = $day->get($yowbyField) + 1; $yearDate = $day->with($yowbyField, $yearExpected); $yearResult = $yearDate->get($yowbyField); $this->assertEquals($yearResult, $yearExpected, "Localized WeekBasedYear not correct; " . $day . " --> " . $yearDate); $range = $yearDate->range($wowbyField); $weekExpected = Math::min($day->get($wowbyField), $range->getMaximum()); $weekActual = $yearDate->get($wowbyField); $this->assertEquals($weekActual, $weekExpected, "Localized WeekOfWeekBasedYear week should not change; " . $day . " --> " . $yearDate . ", actual: " . $weekActual . ", weekExpected: " . $weekExpected); }
/** * 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; }
function resolveYMD(FieldValues $fieldValues, ResolverStyle $resolverStyle) { $y = CF::YEAR()->checkValidIntValue($fieldValues->remove(CF::YEAR())); if ($resolverStyle == ResolverStyle::LENIENT()) { $months = Math::subtractExact($fieldValues->remove(CF::MONTH_OF_YEAR()), 1); $days = Math::subtractExact($fieldValues->remove(CF::DAY_OF_MONTH()), 1); return LocalDate::of($y, 1, 1)->plusMonths($months)->plusDays($days); } $moy = CF::MONTH_OF_YEAR()->checkValidIntValue($fieldValues->remove(CF::MONTH_OF_YEAR())); $dom = CF::DAY_OF_MONTH()->checkValidIntValue($fieldValues->remove(CF::DAY_OF_MONTH())); if ($resolverStyle == ResolverStyle::SMART()) { // previous valid if ($moy == 4 || $moy == 6 || $moy == 9 || $moy == 11) { $dom = Math::min($dom, 30); } else { if ($moy == 2) { $dom = Math::min($dom, Month::FEBRUARY()->length(Year::isLeapYear($y))); } } } return LocalDate::of($y, $moy, $dom); }
public function test_periodUntil_LocalDate_max() { $years = Math::toIntExact(Year::MAX_VALUE - Year::MIN_VALUE); $this->assertEquals(LocalDate::MIN()->untilDate(LocalDate::MAX()), Period::of($years, 11, 30)); }
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)); }
/** * Adds rules to make the last rules all start from the same year. * Also add one more year to avoid weird case where penultimate year has odd offset. * * @param int $windowStartYear the window start year * @throws \LogicException if there is only one rule defined as being forever */ function tidy($windowStartYear) { if (count($this->lastRuleList) === 1) { throw new \LogicException("Cannot have only one rule defined as being forever"); } // handle last rules if ($this->windowEnd->equals(LocalDateTime::MAX())) { // setup at least one real rule, which closes off other windows nicely $this->maxLastRuleStartYear = Math::max($this->maxLastRuleStartYear, $windowStartYear) + 1; foreach ($this->lastRuleList as $lastRule) { $this->addRule($lastRule->year, $this->maxLastRuleStartYear, $lastRule->month, $lastRule->dayOfMonthIndicator, $lastRule->dayOfWeek, $lastRule->time, $lastRule->timeEndOfDay, $lastRule->timeDefinition, $lastRule->savingAmountSecs); $lastRule->year = $this->maxLastRuleStartYear + 1; } if ($this->maxLastRuleStartYear == Year::MAX_VALUE) { $this->lastRuleList = []; } else { $this->maxLastRuleStartYear++; } } else { // convert all within the endYear limit $endYear = $this->windowEnd->getYear(); foreach ($this->lastRuleList as $lastRule) { $this->addRule($lastRule->year, $endYear + 1, $lastRule->month, $lastRule->dayOfMonthIndicator, $lastRule->dayOfWeek, $lastRule->time, $lastRule->timeEndOfDay, $lastRule->timeDefinition, $lastRule->savingAmountSecs); } $this->lastRuleList = []; $this->maxLastRuleStartYear = Year::MAX_VALUE; } // ensure lists are sorted usort($this->ruleList, [TZRule::class, 'compareTo']); usort($this->lastRuleList, [TZRule::class, 'compareTo']); // default fixed savings to zero if (count($this->ruleList) === 0 && $this->fixedSavingAmountSecs === null) { $this->fixedSavingAmountSecs = 0; } }
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; }
public function parse(DateTimeParseContext $context, $text, $position) { $effectiveMin = $context->isStrict() ? $this->minWidth : 0; $effectiveMax = $context->isStrict() ? $this->maxWidth : 9; $length = strlen($text); if ($position === $length) { // valid if whole field is optional, invalid if minimum width return $effectiveMin > 0 ? ~$position : $position; } if ($this->decimalPoint) { if ($text[$position] != $context->getDecimalStyle()->getDecimalSeparator()) { // valid if whole field is optional, invalid if minimum width return $effectiveMin > 0 ? ~$position : $position; } $position++; } $minEndPos = $position + $effectiveMin; if ($minEndPos > $length) { return ~$position; // need at least min width digits } $maxEndPos = Math::min($position + $effectiveMax, $length); $total = 0; // can use int because we are only parsing up to 9 digits $pos = $position; while ($pos < $maxEndPos) { $ch = $text[$pos++]; $digit = $context->getDecimalStyle()->convertToDigit($ch); if ($digit < 0) { if ($pos < $minEndPos) { return ~$position; // need at least min width digits } $pos--; break; } $total = $total * 10 + $digit; } $div = 1 . str_repeat('0', 9 - ($pos - $position)); $fraction = gmp_mul($total, $div); $value = $this->convertFromFraction($fraction); return $context->setParsedField($this->field, $value, $position, $pos); }
public function parse(DateTimeParseContext $context, $text, $position) { $length = strlen($text); if ($position === $length) { return ~$position; } if ($position < 0 || $position >= $length) { throw new \OutOfRangeException(); } $sign = $text[$position]; $negative = false; $positive = false; if ($sign === $context->getDecimalStyle()->getPositiveSign()) { if ($this->signStyle->parse(true, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) { return ~$position; } $positive = true; $position++; } else { if ($sign === $context->getDecimalStyle()->getNegativeSign()) { if ($this->signStyle->parse(false, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) { return ~$position; } $negative = true; $position++; } else { if ($this->signStyle == SignStyle::ALWAYS() && $context->isStrict()) { return ~$position; } } } $effMinWidth = $context->isStrict() || $this->isFixedWidth($context) ? $this->minWidth : 1; $minEndPos = $position + $effMinWidth; if ($minEndPos > $length) { return ~$position; } $effMaxWidth = ($context->isStrict() || $this->isFixedWidth($context) ? $this->maxWidth : 9) + Math::max($this->subsequentWidth, 0); $total = 0; $totalBig = null; $pos = $position; for ($pass = 0; $pass < 2; $pass++) { $maxEndPos = Math::min($pos + $effMaxWidth, $length); while ($pos < $maxEndPos) { $ch = $text[$pos++]; $digit = $context->getDecimalStyle()->convertToDigit($ch); if ($digit < 0) { $pos--; if ($pos < $minEndPos) { return ~$position; // need at least min width digits } break; } if ($pos - $position > 18) { if ($totalBig === null) { $totalBig = \gmp_init($total); } $totalBig = \gmp_add(\gmp_mul($totalBig, "10"), \gmp_init($digit)); } else { $total = $total * 10 + $digit; } } if ($this->subsequentWidth > 0 && $pass === 0) { // re-parse now we know the correct width $parseLen = $pos - $position; $effMaxWidth = Math::max($effMinWidth, $parseLen - $this->subsequentWidth); $pos = $position; $total = 0; $totalBig = null; } else { break; } } if ($negative) { if ($totalBig !== null) { if (\gmp_cmp($totalBig, "0") === 0 && $context->isStrict()) { return ~($position - 1); // minus zero not allowed } $totalBig = \gmp_neg($totalBig); } else { if ($total === 0 && $context->isStrict()) { return ~($position - 1); // minus zero not allowed } $total = -$total; } } else { if ($this->signStyle == SignStyle::EXCEEDS_PAD() && $context->isStrict()) { $parseLen = $pos - $position; if ($positive) { if ($parseLen <= $this->minWidth) { return ~($position - 1); // '+' only parsed if minWidth exceeded } } else { if ($parseLen > $this->minWidth) { return ~$position; // '+' must be parsed if minWidth exceeded } } } } if ($totalBig !== null) { if (gmp_cmp($totalBig, "-9223372036854775808") < 0 || gmp_cmp($totalBig, "9223372036854775807") > 0) { // overflow, parse 1 less digit $totalBig = gmp_div($totalBig, "10"); $pos--; } return $this->setValue($context, gmp_intval($totalBig), $position, $pos); } return $this->setValue($context, $total, $position, $pos); }
public function test_now() { $expected = OffsetDateTime::nowOf(Clock::systemDefaultZone()); $test = OffsetDateTime::now(); $diff = Math::abs($test->toLocalTime()->toNanoOfDay() - $expected->toLocalTime()->toNanoOfDay()); if ($diff >= 100000000) { // may be date change $expected = OffsetDateTime::nowOf(Clock::systemDefaultZone()); $test = OffsetDateTime::now(); $diff = Math::abs($test->toLocalTime()->toNanoOfDay() - $expected->toLocalTime()->toNanoOfDay()); } $this->assertTrue($diff < 100000000); // less than 0.1 secs }
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; }
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; }
/** * @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()); } }
/** * 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); }
private function doTestOffset(ZoneOffset $offset, $hours, $minutes, $seconds) { $this->assertEquals($offset->getTotalSeconds(), $hours * 60 * 60 + $minutes * 60 + $seconds); if ($hours == 0 && $minutes == 0 && $seconds == 0) { $id = "Z"; } else { $str = $hours < 0 || $minutes < 0 || $seconds < 0 ? "-" : "+"; $str .= substr(Math::abs($hours) + 100, 1); $str .= ":"; $str .= substr(Math::abs($minutes) + 100, 1); if ($seconds != 0) { $str .= ":"; $str .= substr(Math::abs($seconds) + 100, 1); } $id = $str; } $this->assertEquals($offset->getId(), $id); $this->assertEquals($offset, ZoneOffset::ofHoursMinutesSeconds($hours, $minutes, $seconds)); if ($seconds == 0) { $this->assertEquals($offset, ZoneOffset::ofHoursMinutes($hours, $minutes)); if ($minutes == 0) { $this->assertEquals($offset, ZoneOffset::ofHours($hours)); } } $this->assertEquals(ZoneOffset::of($id), $offset); $this->assertEquals($offset->__toString(), $id); }
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"]]; }