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;
 }
Ejemplo n.º 2
0
 /**
  * Calculates the period between this date and another date as a {@code Period}.
  * <p>
  * This calculates the period between two dates in terms of years, months and days.
  * The start and end points are {@code this} and the specified date.
  * The result will be negative if the end is before the start.
  * The negative sign will be the same in each of year, month and day.
  * <p>
  * The calculation is performed using the ISO calendar system.
  * If necessary, the input date will be converted to ISO.
  * <p>
  * The start date is included, but the end date is not.
  * The period is calculated by removing complete months, then calculating
  * the remaining number of days, adjusting to ensure that both have the same sign.
  * The number of months is then normalized into years and months based on a 12 month year.
  * A month is considered to be complete if the end day-of-month is greater
  * than or equal to the start day-of-month.
  * For example, from {@code 2010-01-15} to {@code 2011-03-18} is "1 year, 2 months and 3 days".
  * <p>
  * There are two equivalent ways of using this method.
  * The first is to invoke this method.
  * The second is to use {@link Period#between(LocalDate, LocalDate)}:
  * <pre>
  *   // these two lines are equivalent
  *   period = start.until(end);
  *   period = Period.between(start, end);
  * </pre>
  * The choice should be made based on which makes the code more readable.
  *
  * @param ChronoLocalDate $endDateExclusive the end date, exclusive, which may be in any chronology, not null
  * @return Period the period between this date and the end date, not null
  */
 public function untilDate(ChronoLocalDate $endDateExclusive)
 {
     $end = LocalDate::from($endDateExclusive);
     $totalMonths = $end->getProlepticMonth() - $this->getProlepticMonth();
     // safe
     $days = $end->day - $this->day;
     if ($totalMonths > 0 && $days < 0) {
         $totalMonths--;
         $calcDate = $this->plusMonths($totalMonths);
         $days = (int) ($end->toEpochDay() - $calcDate->toEpochDay());
         // safe
     } else {
         if ($totalMonths < 0 && $days > 0) {
             $totalMonths++;
             $days -= $end->lengthOfMonth();
         }
     }
     $years = Math::div($totalMonths, 12);
     // safe
     $months = (int) ($totalMonths % 12);
     // safe
     return Period::of(Math::toIntExact($years), $months, $days);
 }
Ejemplo n.º 3
0
 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));
 }
Ejemplo n.º 4
0
 protected function resolveYearOfEra(FieldValues $fieldValues, ResolverStyle $resolverStyle)
 {
     $yoeLong = $fieldValues->remove(ChronoField::YEAR_OF_ERA());
     if ($yoeLong != null) {
         $eraLong = $fieldValues->remove(ChronoField::ERA());
         if ($resolverStyle != ResolverStyle::LENIENT()) {
             $yoe = $this->range(ChronoField::YEAR_OF_ERA())->checkValidIntValue($yoeLong, ChronoField::YEAR_OF_ERA());
         } else {
             $yoe = Math::toIntExact($yoeLong);
         }
         if ($eraLong != null) {
             $eraObj = $this->eraOf($this->range(ChronoField::ERA())->checkValidIntValue($eraLong, ChronoField::ERA()));
             self::addFieldValue($fieldValues, ChronoField::YEAR(), $this->prolepticYear($eraObj, $yoe));
         } else {
             if ($fieldValues->has(ChronoField::YEAR())) {
                 $year = $this->range(ChronoField::YEAR())->checkValidIntValue($fieldValues[ChronoField::YEAR()->__toString()][1], ChronoField::YEAR());
                 $chronoDate = $this->dateYearDay($year, 1);
                 self::addFieldValue($fieldValues, ChronoField::YEAR(), $this->prolepticYear($chronoDate->getEra(), $yoe));
             } else {
                 if ($resolverStyle == ResolverStyle::STRICT()) {
                     // do not invent era if strict
                     // reinstate the field removed earlier, no cross-check issues
                     $fieldValues[ChronoField::YEAR_OF_ERA()->__toString()][1] = $yoeLong;
                 } else {
                     $eras = $this->eras();
                     if (empty($eras)) {
                         self::addFieldValue($fieldValues, ChronoField::YEAR(), $yoe);
                     } else {
                         $eraObj = $eras[count($eras) - 1];
                         $this->addFieldValue($fieldValues, ChronoField::YEAR(), $this->prolepticYear($eraObj, $yoe));
                     }
                 }
             }
         }
     } else {
         if ($fieldValues->has(ChronoField::ERA())) {
             $this->range(ChronoField::ERA())->checkValidValue($fieldValues[ChronoField::ERA()->__toString()][1], ChronoField::ERA());
             // always validated
         }
     }
     return null;
 }
Ejemplo n.º 5
0
 public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle)
 {
     $value = $fieldValues->get($this);
     $newValue = Math::toIntExact($value);
     // broad limit makes overflow checking lighter
     // first convert localized day-of-week to ISO day-of-week
     // doing this first handles case where both ISO and localized were parsed and might mismatch
     // day-of-week is always strict as two different day-of-week values makes lenient complex
     if ($this->rangeUnit == ChronoUnit::WEEKS()) {
         // day-of-week
         $checkedValue = $this->range->checkValidIntValue($value, $this);
         // no leniency as too complex
         $startDow = $this->weekDef->getFirstDayOfWeek()->getValue();
         $isoDow = Math::floorMod($startDow - 1 + ($checkedValue - 1), 7) + 1;
         $fieldValues->remove($this);
         $fieldValues->put(CF::DAY_OF_WEEK(), $isoDow);
         return null;
     }
     // can only build date if ISO day-of-week is present
     if (!$fieldValues->has(CF::DAY_OF_WEEK())) {
         return null;
     }
     $isoDow = CF::DAY_OF_WEEK()->checkValidIntValue($fieldValues->get(CF::DAY_OF_WEEK()));
     $dow = $this->localizedDayOfWeekNumerical($isoDow);
     // build date
     $chrono = AbstractChronology::from($partialTemporal);
     if ($fieldValues->has(CF::YEAR())) {
         $year = CF::YEAR()->checkValidIntValue($fieldValues->get(CF::YEAR()));
         // validate
         if ($this->rangeUnit == ChronoUnit::MONTHS() && $fieldValues->has(CF::MONTH_OF_YEAR())) {
             // week-of-month
             $month = $fieldValues->get(CF::MONTH_OF_YEAR());
             // not validated yet
             return $this->resolveWoM($fieldValues, $chrono, $year, $month, $newValue, $dow, $resolverStyle);
         }
         if ($this->rangeUnit == ChronoUnit::YEARS()) {
             // week-of-year
             return $this->resolveWoY($fieldValues, $chrono, $year, $newValue, $dow, $resolverStyle);
         }
     } else {
         if (($this->rangeUnit == IsoFields::WEEK_BASED_YEARS() || $this->rangeUnit == ChronoUnit::FOREVER()) && $fieldValues->has($this->weekDef->weekBasedYear) && $fieldValues->has($this->weekDef->weekOfWeekBasedYear)) {
             // week-of-week-based-year and year-of-week-based-year
             return $this->resolveWBY($fieldValues, $chrono, $dow, $resolverStyle);
         }
     }
     return null;
 }
Ejemplo n.º 6
0
 /**
  * Returns a copy of this period with the years and months normalized.
  * <p>
  * This normalizes the years and months units, leaving the days unit unchanged.
  * The months unit is adjusted to have an absolute value less than 11,
  * with the years unit being adjusted to compensate. For example, a period of
  * "1 Year and 15 months" will be normalized to "2 years and 3 months".
  * <p>
  * The sign of the years and months units will be the same after normalization.
  * For example, a period of "1 year and -25 months" will be normalized to
  * "-1 year and -1 month".
  * <p>
  * This instance is immutable and unaffected by this method call.
  *
  * @return Period a {@code Period} based on this period with excess months normalized to years, not null
  * @throws ArithmeticException if numeric overflow occurs
  */
 public function normalized()
 {
     $totalMonths = $this->toTotalMonths();
     $splitYears = Math::div($totalMonths, 12);
     $splitMonths = $totalMonths % 12;
     // no overflow
     if ($splitYears === $this->years && $splitMonths === $this->months) {
         return $this;
     }
     return $this->create(Math::toIntExact($splitYears), $splitMonths, $this->days);
 }