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;
 }
Example #2
0
 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);
 }
Example #3
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);
 }
 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;
 }
Example #6
0
 /**
  * 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);
 }
Example #8
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));
 }
Example #10
0
 public function millis()
 {
     $tofd = \gettimeofday();
     return $tofd['sec'] * 1000 + Math::floorDiv($tofd['usec'], 1000);
 }
Example #11
0
 /**
  * @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)));
 }
Example #13
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 #14
0
 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);
 }
Example #16
0
 /**
  * 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;
 }
Example #17
0
 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));
 }
Example #20
0
 /**
  * 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
 }
Example #25
0
 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());
     }
 }
Example #28
0
 /**
  * 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);
 }
Example #30
0
 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"]];
 }