예제 #1
0
 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;
 }
예제 #2
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);
 }
예제 #3
0
 protected function resolveYAD(FieldValues $fieldValues, ResolverStyle $resolverStyle)
 {
     $y = $this->range(ChronoField::YEAR())->checkValidIntValue($fieldValues->remove(ChronoField::YEAR()), ChronoField::YEAR());
     if ($resolverStyle == ResolverStyle::LENIENT()) {
         $weeks = Math::subtractExact($fieldValues->remove(ChronoField::ALIGNED_WEEK_OF_YEAR()), 1);
         $dow = Math::subtractExact($fieldValues->remove(ChronoField::DAY_OF_WEEK()), 1);
         return $this->resolveAligned($this->dateYearDay($y, 1), 0, $weeks, $dow);
     }
     $aw = $this->range(ChronoField::ALIGNED_WEEK_OF_YEAR())->checkValidIntValue($fieldValues->remove(ChronoField::ALIGNED_WEEK_OF_YEAR()), ChronoField::ALIGNED_WEEK_OF_YEAR());
     $dow = $this->range(ChronoField::DAY_OF_WEEK())->checkValidIntValue($fieldValues->remove(ChronoField::DAY_OF_WEEK()), ChronoField::DAY_OF_WEEK());
     $date = $this->dateYearDay($y, 1)->plus(($aw - 1) * 7, ChronoUnit::DAYS())->adjust(TemporalAdjusters::nextOrSame(DayOfWeek::of($dow)));
     if ($resolverStyle == ResolverStyle::STRICT() && $date->get(ChronoField::YEAR()) != $y) {
         throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
     }
     return $date;
 }
예제 #4
0
 public static function RFC_1123_DATE_TIME()
 {
     // manually code maps to ensure correct data always used
     // (locale data can be changed by application code)
     $dow = [1 => "Mon", 2 => "Tue", 3 => "Wed", 4 => "Thu", 5 => "Fri", 6 => "Sat", 7 => "Sun"];
     $moy = [1 => "Jan", 2 => "Feb", 3 => "Mar", 4 => "Apr", 5 => "May", 6 => "Jun", 7 => "Jul", 8 => "Aug", 9 => "Sep", 10 => "Oct", 11 => "Nov", 12 => "Dec"];
     return self::$RFC_1123_DATE_TIME = (new DateTimeFormatterBuilder())->parseCaseInsensitive()->parseLenient()->optionalStart()->appendText3(ChronoField::DAY_OF_WEEK(), $dow)->appendLiteral2(", ")->optionalEnd()->appendValue3(ChronoField::DAY_OF_MONTH(), 1, 2, SignStyle::NOT_NEGATIVE())->appendLiteral(' ')->appendText3(ChronoField::MONTH_OF_YEAR(), $moy)->appendLiteral(' ')->appendValue2(ChronoField::YEAR(), 4)->appendLiteral(' ')->appendValue2(ChronoField::HOUR_OF_DAY(), 2)->appendLiteral(':')->appendValue2(ChronoField::MINUTE_OF_HOUR(), 2)->optionalStart()->appendLiteral(':')->appendValue2(ChronoField::SECOND_OF_MINUTE(), 2)->optionalEnd()->appendLiteral(' ')->appendOffset("+HHMM", "GMT")->toFormatter3(ResolverStyle::SMART(), IsoChronology::INSTANCE());
 }
예제 #5
0
 /**
  * @dataProvider data_parseLenientWeek
  */
 public function test_parse_parseLenientWeek_LENIENT($str, LocalDate $expected, $smart)
 {
     $f = (new DateTimeFormatterBuilder())->appendValue(IsoFields::WEEK_BASED_YEAR())->appendLiteral(':')->appendValue(IsoFields::WEEK_OF_WEEK_BASED_YEAR())->appendLiteral(':')->appendValue(CF::DAY_OF_WEEK())->toFormatter()->withResolverStyle(ResolverStyle::LENIENT());
     $parsed = LocalDate::parseWith($str, $f);
     $this->assertEquals($parsed, $expected);
 }
예제 #6
0
 public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle)
 {
     $value = $fieldValues->remove($this);
     $chrono = AbstractChronology::from($partialTemporal);
     if ($resolverStyle == ResolverStyle::LENIENT()) {
         return $chrono->dateEpochDay(Math::subtractExact($value, $this->offset));
     }
     $this->range()->checkValidValue($value, $this);
     return $chrono->dateEpochDay($value - $this->offset);
 }
예제 #7
0
 /**
  * @dataProvider data_weekFields
  * @group long
  */
 public function test_parse_resolve_localizedWoWBYDow_lenient(DayOfWeek $firstDayOfWeek, $minDays)
 {
     $date = LocalDate::of(2012, 12, 31);
     $week = WeekFields::of($firstDayOfWeek, $minDays);
     $dowField = $week->dayOfWeek();
     $wowbyField = $week->weekOfWeekBasedYear();
     $yowbyField = $week->weekBasedYear();
     for ($i = 1; $i <= 60; $i++) {
         $f = (new DateTimeFormatterBuilder())->appendValue($yowbyField)->appendLiteral(':')->appendValue($wowbyField)->appendLiteral(':')->appendValue($dowField)->toFormatter()->withResolverStyle(ResolverStyle::LENIENT());
         $wowby = $date->get($wowbyField);
         $dow = $date->get($dowField);
         for ($j = $wowby - 60; $j < $wowby + 60; $j++) {
             $str = $date->get($yowbyField) . ":" . $j . ":" . $dow;
             $parsed = LocalDate::parseWith($str, $f);
             $this->assertEquals($parsed, $date->plusWeeks($j - $wowby), " ::" . $str . ": :" . $i . "::" . $j);
         }
         $date = $date->plusDays(1);
     }
 }
예제 #8
0
            case 'STRICT':
                return self::STRICT();
            case 'SMART':
                return self::SMART();
            case 'LENIENT':
                return self::LENIENT();
        }
        throw new IllegalArgumentException();
    }
    /**
     * @return string
     */
    public function name()
    {
        switch ($this->ordinal) {
            case 0:
                return 'STRICT';
            case 1:
                return 'SMART';
            case 2:
                return 'LENIENT';
        }
        return '';
    }
    public function __toString()
    {
        return $this->name();
    }
}
ResolverStyle::init();
 /**
  * @dataProvider data_resolve_ymaa
  */
 public function test_resolve_ymaa_strict($y, $m, $w, $d, $expected, $smar, $strict)
 {
     $fieldValues = new FieldValues();
     $fieldValues->put(ChronoField::YEAR(), $y);
     $fieldValues->put(ChronoField::MONTH_OF_YEAR(), $m);
     $fieldValues->put(ChronoField::ALIGNED_WEEK_OF_MONTH(), $w);
     $fieldValues->put(ChronoField::ALIGNED_DAY_OF_WEEK_IN_MONTH(), $d);
     if ($strict) {
         $date = IsoChronology::INSTANCE()->resolveDate($fieldValues, ResolverStyle::STRICT());
         $this->assertEquals($date, $expected);
         $this->assertEquals($fieldValues->size(), 0);
     } else {
         try {
             IsoChronology::INSTANCE()->resolveDate($fieldValues, ResolverStyle::STRICT());
             $this->fail("Should have failed");
         } catch (DateTimeException $ex) {
             // $expected
         }
     }
 }
예제 #10
0
 private function resolveWBY(FieldValues $fieldValues, Chronology $chrono, $localDow, ResolverStyle $resolverStyle)
 {
     $yowby = $this->weekDef->weekBasedYear->range()->checkValidIntValue($fieldValues->get($this->weekDef->weekBasedYear), $this->weekDef->weekBasedYear);
     if ($resolverStyle == ResolverStyle::LENIENT()) {
         $date = $this->ofWeekBasedYear($chrono, $yowby, 1, $localDow);
         $wowby = $fieldValues->get($this->weekDef->weekOfWeekBasedYear);
         $weeks = Math::subtractExact($wowby, 1);
         $date = $date->plus($weeks, ChronoUnit::WEEKS());
     } else {
         $wowby = $this->weekDef->weekOfWeekBasedYear->range()->checkValidIntValue($fieldValues->get($this->weekDef->weekOfWeekBasedYear), $this->weekDef->weekOfWeekBasedYear);
         // validate
         $date = $this->ofWeekBasedYear($chrono, $yowby, $wowby, $localDow);
         if ($resolverStyle == ResolverStyle::STRICT() && $this->localizedWeekBasedYear($date) != $yowby) {
             throw new DateTimeException("Strict mode rejected resolved date as it is in a different week-based-year");
         }
     }
     $fieldValues->remove($this);
     $fieldValues->remove($this->weekDef->weekBasedYear);
     $fieldValues->remove($this->weekDef->weekOfWeekBasedYear);
     $fieldValues->remove(CF::DAY_OF_WEEK());
     return $date;
 }
 function data_resolveAmPm()
 {
     return [[ResolverStyle::STRICT(), 0, 0], [ResolverStyle::STRICT(), 1, 1], [ResolverStyle::STRICT(), -1, null], [ResolverStyle::STRICT(), 2, null], [ResolverStyle::SMART(), 0, 0], [ResolverStyle::SMART(), 1, 1], [ResolverStyle::SMART(), -1, null], [ResolverStyle::SMART(), 2, null], [ResolverStyle::LENIENT(), 0, 0], [ResolverStyle::LENIENT(), 1, 1], [ResolverStyle::LENIENT(), -1, -1], [ResolverStyle::LENIENT(), 2, 2]];
 }
예제 #12
0
 /**
  * @dataProvider data_samples
  */
 public function test_samples_parse_LENIENT(TemporalField $field, LocalDate $date, $value)
 {
     $f = (new DateTimeFormatterBuilder())->appendValue($field)->toFormatter()->withResolverStyle(ResolverStyle::LENIENT());
     $parsed = LocalDate::parseWith(strval($value), $f);
     $this->assertEquals($parsed, $date);
 }
예제 #13
0
 public function data_resolverStyle()
 {
     return [["2000/15/30", ResolverStyle::LENIENT(), null, 2001, 3, 30], ["2000/02/30", ResolverStyle::SMART(), null, 2000, 2, 29], ["2000/02/29", ResolverStyle::STRICT(), null, 2000, 2, 29], ["2000/15/30 CE", ResolverStyle::LENIENT(), null, 2001, 3, 30], ["2000/02/30 CE", ResolverStyle::SMART(), null, 2000, 2, 29], ["5/02/29 BCE", ResolverStyle::STRICT(), null, 5, 2, 29], ["4/02/29 BCE", ResolverStyle::STRICT(), DateTimeException::class, -1, -1, -1], ["2000/02/30 CE", ResolverStyle::STRICT(), DateTimeException::class, -1, -1, -1]];
 }
 public function test_rfc1123_basics()
 {
     $this->assertEquals(DateTimeFormatter::RFC_1123_DATE_TIME()->getChronology(), IsoChronology::INSTANCE());
     $this->assertEquals(DateTimeFormatter::RFC_1123_DATE_TIME()->getZone(), null);
     $this->assertEquals(DateTimeFormatter::RFC_1123_DATE_TIME()->getResolverStyle(), ResolverStyle::SMART());
 }
예제 #15
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);
 }
예제 #16
0
 private function resolveTime($hod, $moh, $som, $nos)
 {
     if ($this->resolverStyle == ResolverStyle::LENIENT()) {
         $totalNanos = Math::multiplyExact($hod, 3600000000000);
         $totalNanos = Math::addExact($totalNanos, Math::multiplyExact($moh, 60000000000));
         $totalNanos = Math::addExact($totalNanos, Math::multiplyExact($som, 1000000000));
         $totalNanos = Math::addExact($totalNanos, $nos);
         $excessDays = (int) Math::floorDiv($totalNanos, 86400000000000);
         // safe int cast
         $nod = Math::floorMod($totalNanos, 86400000000000);
         $this->updateCheckConflict(LocalTime::ofNanoOfDay($nod), Period::ofDays($excessDays));
     } else {
         // STRICT or SMART
         $mohVal = CF::MINUTE_OF_HOUR()->checkValidIntValue($moh);
         $nosVal = CF::NANO_OF_SECOND()->checkValidIntValue($nos);
         // handle 24:00 end of day
         if ($this->resolverStyle == ResolverStyle::SMART() && $hod == 24 && $mohVal == 0 && $som == 0 && $nosVal == 0) {
             $this->updateCheckConflict(LocalTime::MIDNIGHT(), Period::ofDays(1));
         } else {
             $hodVal = CF::HOUR_OF_DAY()->checkValidIntValue($hod);
             $somVal = CF::SECOND_OF_MINUTE()->checkValidIntValue($som);
             $this->updateCheckConflict(LocalTime::of($hodVal, $mohVal, $somVal, $nosVal), Period::ZERO());
         }
     }
 }
 public function test_parse_leapSecond()
 {
     $expected = OffsetDateTime::of(1970, 2, 3, 23, 59, 59, 123456789, ZoneOffset::UTC())->toInstant();
     $f = (new DateTimeFormatterBuilder())->appendInstant4(-1)->toFormatter();
     foreach (ResolverStyle::values() as $style) {
         $pared = $f->withResolverStyle($style)->parse("1970-02-03T23:59:60.123456789Z");
         $this->assertEquals($pared->query(Instant::fromQuery()), $expected);
         $this->assertEquals($pared->query(DateTimeFormatter::parsedExcessDays()), Period::ZERO());
         $this->assertEquals($pared->query(DateTimeFormatter::parsedLeapSecond()), true);
     }
 }
 /**
  * Completes this builder by creating the {@code DateTimeFormatter}
  * using the specified locale.
  * <p>
  * This will create a formatter with the specified locale.
  * Numbers will be printed and parsed using the standard DecimalStyle.
  * The resolver style will be {@link ResolverStyle#SMART SMART}.
  * <p>
  * Calling this method will end any open optional sections by repeatedly
  * calling {@link #optionalEnd()} before creating the formatter.
  * <p>
  * This builder can still be used after creating the formatter if desired,
  * although the state may have been changed by calls to {@code optionalEnd}.
  *
  * @param Locale $locale the locale to use for formatting, not null
  * @return DateTimeFormatter the created formatter, not null
  */
 public function toFormatter2(Locale $locale)
 {
     return $this->toFormatter4($locale, ResolverStyle::SMART(), null);
 }