Ejemplo n.º 1
0
 /**
  * Parse an offset following a prefix and set the ZoneId if it is valid.
  * To matching the parsing of ZoneId.of the values are not normalized
  * to ZoneOffsets.
  *
  * @param DateTimeParseContext $context the parse context
  * @param string $text the input text
  * @param int $prefixPos start of the prefix
  * @param int $position start of text after the prefix
  * @param OffsetIdPrinterParser $parser parser for the value after the prefix
  * @return int the position after the parse
  */
 private function parseOffsetBased(DateTimeParseContext $context, $text, $prefixPos, $position, OffsetIdPrinterParser $parser)
 {
     $prefix = strtoupper(substr($text, $prefixPos, $position - $prefixPos));
     if ($position >= strlen($text)) {
         $context->setParsedZone(ZoneId::of($prefix));
         return $position;
     }
     // '0' or 'Z' after prefix is not part of a valid ZoneId; use bare prefix
     if ($text[$position] === '0' || $context->charEquals($text[$position], 'Z')) {
         $context->setParsedZone(ZoneId::of($prefix));
         return $position;
     }
     $newContext = $context->copy();
     $endPos = $parser->parse($newContext, $text, $position);
     try {
         if ($endPos < 0) {
             if ($parser == OffsetIdPrinterParser::INSTANCE_ID_Z()) {
                 return ~$prefixPos;
             }
             $context->setParsedZone(ZoneId::of($prefix));
             return $position;
         }
         $offset = $newContext->getParsed(ChronoField::OFFSET_SECONDS());
         $zoneOffset = ZoneOffset::ofTotalSeconds($offset);
         $context->setParsedZone(ZoneId::ofOffset($prefix, $zoneOffset));
         return $endPos;
     } catch (DateTimeException $dte) {
         return ~$prefixPos;
     }
 }
Ejemplo n.º 2
0
 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);
 }