/** * @dataProvider data_periodUntilUnit */ public function test_until_TemporalUnit_negated(LocalDateTime $dt1, LocalDateTime $dt2, TemporalUnit $unit, $expected) { $amount = $dt2->until($dt1, $unit); $this->assertEquals($amount, -$expected); }
/** * Calculates the amount of time until another date-time in terms of the specified unit. * <p> * This calculates the amount of time between two {@code OffsetDateTime} * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date-time. * The result will be negative if the end is before the start. * For example, the amount in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. * <p> * The {@code Temporal} passed to this method is converted to a * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}. * If the offset differs between the two date-times, the specified * end date-time is normalized to have the same offset as this date-time. * <p> * The calculation returns a whole number, representing the number of * complete units between the two date-times. * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z * will only be one month as it is one minute short of two months. * <p> * There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: * <pre> * // these two lines are equivalent * amount = start.until(end, MONTHS); * amount = MONTHS.between(start, end); * </pre> * The choice should be made based on which makes the code more readable. * <p> * The calculation is implemented in this method for {@link ChronoUnit}. * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS}, * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES}, * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. * Other {@code ChronoUnit} values will throw an exception. * <p> * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} * passing {@code this} as the first argument and the converted input temporal * as the second argument. * <p> * This instance is immutable and unaffected by this method call. * * @param Temporal $endExclusive the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null * @param TemporalUnit $unit the unit to measure the amount in, not null * @return int the amount of time between this date-time and the end date-time * @throws DateTimeException if the amount cannot be calculated, or the end * temporal cannot be converted to an {@code OffsetDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ public function until(Temporal $endExclusive, TemporalUnit $unit) { $end = OffsetDateTime::from($endExclusive); if ($unit instanceof ChronoUnit) { $end = $end->withOffsetSameInstant($this->offset); return $this->dateTime->until($end->dateTime, $unit); } return $unit->between($this, $end); }
/** * Calculates the amount of time until another date-time in terms of the specified unit. * <p> * This calculates the amount of time between two {@code ZonedDateTime} * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date-time. * The result will be negative if the end is before the start. * For example, the amount in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. * <p> * The {@code Temporal} passed to this method is converted to a * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}. * If the time-zone differs between the two zoned date-times, the specified * end date-time is normalized to have the same zone as this date-time. * <p> * The calculation returns a whole number, representing the number of * complete units between the two date-times. * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z * will only be one month as it is one minute short of two months. * <p> * There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: * <pre> * // these two lines are equivalent * amount = start.until(end, MONTHS); * amount = MONTHS.between(start, end); * </pre> * The choice should be made based on which makes the code more readable. * <p> * The calculation is implemented in this method for {@link ChronoUnit}. * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS}, * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES}, * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. * Other {@code ChronoUnit} values will throw an exception. * <p> * The calculation for date and time units differ. * <p> * Date units operate on the local time-line, using the local date-time. * For example, the period from noon on day 1 to noon the following day * in days will always be counted as exactly one day, irrespective of whether * there was a daylight savings change or not. * <p> * Time units operate on the instant time-line. * The calculation effectively converts both zoned date-times to instants * and then calculates the period between the instants. * For example, the period from noon on day 1 to noon the following day * in hours may be 23, 24 or 25 hours (or some other amount) depending on * whether there was a daylight savings change or not. * <p> * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} * passing {@code this} as the first argument and the converted input temporal * as the second argument. * <p> * This instance is immutable and unaffected by this method call. * * @param Temporal $endExclusive the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null * @param TemporalUnit $unit the unit to measure the amount in, not null * @return int the amount of time between this date-time and the end date-time * @throws DateTimeException if the amount cannot be calculated, or the end * temporal cannot be converted to a {@code ZonedDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ public function until(Temporal $endExclusive, TemporalUnit $unit) { $end = ZonedDateTime::from($endExclusive); if ($unit instanceof ChronoUnit) { $end = $end->withZoneSameInstant($this->zone); if ($unit->isDateBased()) { return $this->dateTime->until($end->dateTime, $unit); } else { return $this->toOffsetDateTime()->until($end->toOffsetDateTime(), $unit); } } return $unit->between($this, $end); }