public function format(DateTimePrintContext $context, &$buf)
 {
     $value = $context->getValueField($this->field);
     if ($value === null) {
         return false;
     }
     $decimalStyle = $context->getDecimalStyle();
     $fraction = $this->convertToFraction($value);
     if (gmp_cmp($fraction, 0) === 0) {
         // scale is zero if value is zero
         if ($this->minWidth > 0) {
             if ($this->decimalPoint) {
                 $buf .= $decimalStyle->getDecimalSeparator();
             }
             for ($i = 0; $i < $this->minWidth; $i++) {
                 $buf .= $decimalStyle->getZeroDigit();
             }
         }
     } else {
         $outputScale = Math::min(Math::max(9, $this->minWidth), $this->maxWidth);
         if ($outputScale !== 9) {
             $div = 1 . str_repeat('0', 9 - $outputScale);
             $fraction = gmp_div($fraction, $div);
         }
         $str = gmp_strval($fraction);
         $pad = $outputScale - strlen($str);
         $str = str_repeat('0', $pad) . $str;
         // trim trailing zeros
         while (strlen($str) > $this->minWidth && $str[strlen($str) - 1] === '0') {
             $str = substr($str, 0, strlen($str) - 1);
         }
         $str = $decimalStyle->convertNumberToI18N($str);
         if ($this->decimalPoint) {
             $buf .= $decimalStyle->getDecimalSeparator();
         }
         $buf .= $str;
     }
     return true;
 }
Exemplo n.º 2
0
 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);
 }
Exemplo n.º 3
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;
     }
 }