ChronoUnit.between()
Count the whole days, weeks, months or hours between two dates or times as a single number, with truncation you can predict.
public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive)- Added in Java Java 8
Parameters
| Parameter | Type | Description |
|---|---|---|
$temporal1Inclusive | Temporal | The start, included. |
$temporal2Exclusive | Temporal | The end, excluded. If it is a different type it is converted to the type of the start. |
Return value
longThe number of complete units between the two temporals; negative if the second is before the first.
Errors
DateTimeException if the amount cannot be calculated or the end cannot be converted to the start's type; UnsupportedTemporalTypeException if the unit is not supported by the type (such as HOURS on LocalDate); ArithmeticException on overflow.
ChronoUnit.DAYS.between(start, end) returns one long: the number of complete days from start to end. The same call works for every unit in the enum, so WEEKS, MONTHS, YEARS, HOURS, MINUTES and so on. It is the simplest answer to "how many days until...?" and "how many days ago...?".
It truncates
Only complete units count. From 31 January to 15 March is 43 days, 6 weeks and 1 month; from 31 January to 28 February is 0 months, because the 31st of the next month has not been reached. From 09:00 to 10:59 is 1 hour. If you want rounding, compute in a smaller unit and round yourself.
Direction and types
The start is inclusive and the end exclusive. If the end is earlier, the result is negative, which is handy for "overdue by" logic. The call is equivalent to start.until(end, unit), and both read naturally; pick one style per codebase.
The unit must make sense for the type. HOURS on two LocalDate values throws UnsupportedTemporalTypeException, because dates have no hours. If the two arguments have different types, the second is converted to the type of the first, so HOURS.between(instant, zonedDateTime) works but the reverse fails when an Instant cannot become a ZonedDateTime without a zone.
Calendar units on zoned values
With ZonedDateTime, date units such as DAYS count on the local calendar, while time units such as HOURS count real elapsed time. Midnight to midnight across the spring clock change is 1 day but 23 hours. Choose the unit that matches the question your user is asking.
ChronoUnit, Period or Duration?
- One number in one unit:
ChronoUnit.X.between. - Years, months and days together, such as an age:
Period.between. - Exact elapsed time you will format or compare:
Duration.between.
Typical back-end uses are "expires in N days" fields in API responses, days-overdue counts for invoices, and bucket sizes for reports.
Example
When to use it
- Returning expiresInDays for a trial or a password in an account API response.
- Counting how many days an unpaid invoice is overdue for a dunning email.
- Choosing hourly or daily buckets for a metrics report from the size of the requested range.
Frequently asked questions
How do I get the number of days between two dates in Java?
Use ChronoUnit.DAYS.between(start, end). The start is included, the end excluded, and the result is negative if the end is earlier.
Why does ChronoUnit.MONTHS.between return 0 for 31 January to 28 February?
It counts only complete months, and a month from 31 January has not been reached by 28 February. The result is truncated, never rounded.
Is ChronoUnit.DAYS.between the same as start.until(end, DAYS)?
Yes. ChronoUnit.between calls until on the first argument, so the two forms give the same result.
More examples
An expiresInDays field for an API response
DAYS.between returns a negative number once the date has passed, so the field is clamped at zero. The injected clock keeps the response testable.
import java.time.*;
import java.time.temporal.ChronoUnit;
record TrialStatus(String plan, LocalDate endsOn, long expiresInDays) {}
TrialStatus status(String plan, LocalDate endsOn, Clock clock) {
LocalDate today = LocalDate.now(clock);
return new TrialStatus(plan, endsOn, Math.max(0, ChronoUnit.DAYS.between(today, endsOn)));
}
void main() {
Clock clock = Clock.fixed(Instant.parse("2026-10-13T08:00:00Z"), ZoneOffset.UTC);
IO.println(status("team", LocalDate.of(2026, 10, 27), clock));
IO.println(status("solo", LocalDate.of(2026, 10, 13), clock));
IO.println(status("old", LocalDate.of(2026, 9, 1), clock));
}
// Output:
// TrialStatus[plan=team, endsOn=2026-10-27, expiresInDays=14]
// TrialStatus[plan=solo, endsOn=2026-10-13, expiresInDays=0]
// TrialStatus[plan=old, endsOn=2026-09-01, expiresInDays=0]between and until are the same calculation
until(end, unit) is the instance-method form of the same calculation. datesUntil (Java 9) streams each date in the range, and its count matches because the end is exclusive in both.
import java.time.*;
import java.time.temporal.ChronoUnit;
void main() {
LocalDate issued = LocalDate.of(2026, 2, 10);
LocalDate paid = LocalDate.of(2026, 3, 27);
IO.println(ChronoUnit.DAYS.between(issued, paid));
IO.println(issued.until(paid, ChronoUnit.DAYS));
IO.println(issued.datesUntil(paid).count());
IO.println(ChronoUnit.WEEKS.between(issued, paid) + " weeks");
}
// Output:
// 45
// 45
// 45
// 6 weeksDays versus hours across a clock change
Date units follow the local calendar, while time units measure elapsed time, so the day of the UK clock change is one day but 23 hours. With an Instant first, the ZonedDateTime is converted to an Instant automatically.
import java.time.*;
import java.time.temporal.ChronoUnit;
void main() {
ZoneId london = ZoneId.of("Europe/London");
ZonedDateTime from = ZonedDateTime.of(2026, 3, 29, 0, 0, 0, 0, london);
ZonedDateTime to = from.plusDays(1);
IO.println("days: " + ChronoUnit.DAYS.between(from, to));
IO.println("hours: " + ChronoUnit.HOURS.between(from, to));
IO.println("mixed: " + ChronoUnit.HOURS.between(from.toInstant(), to));
}
// Output:
// days: 1
// hours: 23
// mixed: 23
Discussion