/** * 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); }
public function period($years, $months, $days) { return Period::of($years, $months, $days); }
private static function pymd($y, $m, $d) { return Period::of($y, $m, $d); }
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)); }
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)]]; }