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);
 }
Esempio n. 2
0
 /**
  * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}.
  * <p>
  * The string must represent a valid date and is parsed using
  * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}.
  *
  * @param string $text the text to parse such as "2007-12-03", not null
  * @return LocalDate the parsed local date, not null
  * @throws DateTimeParseException if the text cannot be parsed
  */
 public static function parse($text)
 {
     return self::parseWith($text, DateTimeFormatter::ISO_LOCAL_DATE());
 }
 public function test_isoLocalDate_basics()
 {
     $this->assertEquals(DateTimeFormatter::ISO_LOCAL_DATE()->getChronology(), IsoChronology::INSTANCE());
     $this->assertEquals(DateTimeFormatter::ISO_LOCAL_DATE()->getZone(), null);
     $this->assertEquals(DateTimeFormatter::ISO_LOCAL_DATE()->getResolverStyle(), ResolverStyle::STRICT());
 }