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); } }
/** * 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); }
function data_minus_TemporalAmount() { return [[YearMonth::of(1, 1), Period::ofYears(1), YearMonth::of(0, 1), null], [YearMonth::of(1, 1), Period::ofYears(-12), YearMonth::of(13, 1), null], [YearMonth::of(1, 1), Period::ofYears(0), YearMonth::of(1, 1), null], [YearMonth::of(999999999, 12), Period::ofYears(0), YearMonth::of(999999999, 12), null], [YearMonth::of(-999999999, 1), Period::ofYears(0), YearMonth::of(-999999999, 1), null], [YearMonth::of(0, 1), Period::ofYears(999999999), YearMonth::of(-999999999, 1), null], [YearMonth::of(0, 12), Period::ofYears(-999999999), YearMonth::of(999999999, 12), null], [YearMonth::of(1, 1), Period::ofMonths(1), YearMonth::of(0, 12), null], [YearMonth::of(1, 1), Period::ofMonths(-12), YearMonth::of(2, 1), null], [YearMonth::of(1, 1), Period::ofMonths(121), YearMonth::of(-10, 12), null], [YearMonth::of(1, 1), Period::ofMonths(0), YearMonth::of(1, 1), null], [YearMonth::of(999999999, 12), Period::ofMonths(0), YearMonth::of(999999999, 12), null], [YearMonth::of(-999999999, 1), Period::ofMonths(0), YearMonth::of(-999999999, 1), null], [YearMonth::of(-999999999, 2), Period::ofMonths(1), YearMonth::of(-999999999, 1), null], [YearMonth::of(999999999, 11), Period::ofMonths(-1), YearMonth::of(999999999, 12), null], [YearMonth::of(1, 1), Period::ofYears(1)->withMonths(2), YearMonth::of(-1, 11), null], [YearMonth::of(1, 1), Period::ofYears(-12)->withMonths(-1), YearMonth::of(13, 2), null], [YearMonth::of(1, 1), Period::ofMonths(2)->withYears(1), YearMonth::of(-1, 11), null], [YearMonth::of(1, 1), Period::ofMonths(-1)->withYears(-12), YearMonth::of(13, 2), null], [YearMonth::of(1, 1), Period::ofDays(365), null, DateTimeException::class], [YearMonth::of(1, 1), Duration::ofDays(365), null, DateTimeException::class], [YearMonth::of(1, 1), Duration::ofHours(365 * 24), null, DateTimeException::class], [YearMonth::of(1, 1), Duration::ofMinutes(365 * 24 * 60), null, DateTimeException::class], [YearMonth::of(1, 1), Duration::ofSeconds(365 * 24 * 3600), null, DateTimeException::class], [YearMonth::of(1, 1), Duration::ofNanos(365 * 24 * 3600 * 1000000000), null, DateTimeException::class]]; }
/** * @dataProvider data_plusDays */ public function test_minus_TemporalAmount_Period_days(ZonedDateTime $base, $amount, ZonedDateTime $expected) { $this->assertEquals($base->minusAmount(Period::ofDays(-$amount)), $expected); }
/** * @expectedException \Celest\DateTimeException */ public function test_factory_from_TemporalAmount_Period() { Duration::from(Period::ZERO()); }
public function period($years, $months, $days) { return Period::of($years, $months, $days); }
/** * A query that provides access to the excess days that were parsed. * <p> * This returns a singleton {@linkplain TemporalQuery query} that provides * access to additional information from the parse. The query always returns * a non-null period, with a zero period returned instead of null. * <p> * There are two situations where this query may return a non-zero period. * <ul> * <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed * without a date, then the complete result of the parse consists of a * {@code LocalTime} and an excess {@code Period} in days. * * <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed * without a date where the time is 24:00:00, then the complete result of * the parse consists of a {@code LocalTime} of 00:00:00 and an excess * {@code Period} of one day. * </ul> * <p> * In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant} * is parsed, then the excess days are added to the date part. * As a result, this query will return a zero period. * <p> * The {@code SMART} behaviour handles the common "end of day" 24:00 value. * Processing in {@code LENIENT} mode also produces the same result: * <pre> * Text to parse Parsed object Excess days * "2012-12-03T00:00" LocalDateTime.of(2012, 12, 3, 0, 0) ZERO * "2012-12-03T24:00" LocalDateTime.of(2012, 12, 4, 0, 0) ZERO * "00:00" LocalTime.of(0, 0) ZERO * "24:00" LocalTime.of(0, 0) Period.ofDays(1) * </pre> * The query can be used as follows: * <pre> * TemporalAccessor parsed = formatter.parse(str); * LocalTime time = parsed.query(LocalTime::from); * Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays()); * </pre> * @return TemporalQuery a query that provides access to the excess days that were parsed */ public static function parsedExcessDays() { return self::$PARSED_EXCESS_DAYS = new FuncTemporalQuery(function (TemporalAccessor $t) { if ($t instanceof Parsed) { return $t->excessDays; } else { return Period::ZERO(); } }); }
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)); }
private static function pymd($y, $m, $d) { return Period::of($y, $m, $d); }
private function updateCheckConflict(LocalTime $timeToSet, Period $periodToSet) { if ($this->time != null) { if ($this->time->equals($timeToSet) == false) { throw new DateTimeException("Conflict found: Fields resolved to different times: " . $this->time . " " . $timeToSet); } if ($this->excessDays->isZero() == false && $periodToSet->isZero() == false && $this->excessDays->equals($periodToSet) == false) { throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " . $this->excessDays . " " . $periodToSet); } else { $this->excessDays = $periodToSet; } } else { $this->time = $timeToSet; $this->excessDays = $periodToSet; } }
/** * @dataProvider data_resolveClockHourOfDay */ public function test_resolveClockHourOfDay(ResolverStyle $style, $value, $expectedHour, $expectedDays) { $str = strval($value); $f = (new DateTimeFormatterBuilder())->appendValue(ChronoField::CLOCK_HOUR_OF_DAY())->toFormatter(); if ($expectedHour !== null) { $accessor = $f->withResolverStyle($style)->parse($str); $this->assertEquals($accessor->query(TemporalQueries::localDate()), null); $this->assertEquals($accessor->query(TemporalQueries::localTime()), LocalTime::of($expectedHour, 0)); $this->assertEquals($accessor->query(DateTimeFormatter::parsedExcessDays()), Period::ofDays($expectedDays)); } else { try { $f->withResolverStyle($style)->parse($str); $this->fail(); } catch (DateTimeParseException $ex) { // $expected } } }
function data_minusInvalidUnit() { return [[Period::of(0, 1, 0)], [Period::of(0, 0, 1)], [Period::of(0, 1, 1)], [Period::of(1, 1, 1)], [Duration::ofDays(1)], [Duration::ofHours(1)], [Duration::ofMinutes(1)], [Duration::ofSeconds(1)]]; }
public function test_minus_TemporalAmount_zero() { $period = Period::ZERO(); $t = self::TEST_123040987654321()->minusAmount($period); $this->assertEquals($t, self::TEST_123040987654321()); }
public function test_minus_MinusAdjuster_zero() { $t = self::TEST_11_30_59_500_PONE()->minusAmount(Period::ZERO()); $this->assertEquals($t, self::TEST_11_30_59_500_PONE()); }
/** * Returns a copy of this period with the specified period subtracted. * <p> * This operates separately on the years, months and days. * No normalization is performed. * <p> * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days" * returns "-1 years, 4 months and 1 day". * <p> * The specified amount is typically an instance of {@code Period}. * Other types are interpreted using {@link Period#from(TemporalAmount)}. * <p> * This instance is immutable and unaffected by this method call. * * @param TemporalAmount $amountToSubtract the amount to subtract, not null * @return Period a {@code Period} based on this period with the requested period subtracted, not null * @throws DateTimeException if the specified amount has a non-ISO chronology or * contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ public function minusAmount(TemporalAmount $amountToSubtract) { $isoAmount = Period::from($amountToSubtract); return $this->create(Math::subtractExact($this->years, $isoAmount->years), Math::subtractExact($this->months, $isoAmount->months), Math::subtractExact($this->days, $isoAmount->days)); }