Date/Time API (JSR-310) practice questions

From OCP Java SE 25 (1Z0-831) · 14 questions on this topic

Date/Time API (JSR-310) practice questions from OCP Java SE 25 (1Z0-831). This pack has 14 questions tagged Date/Time API (JSR-310), drawn from its timed mock exams. 8 of them are worked through in full below — the question, every option, why each is right or wrong, and the explanation.

Worked examples for Date/Time API (JSR-310)

  1. Question 1

    What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2026, 6, 15); LocalDate d2 = d.plusMonths(2).minusDays(5); System.out.println(d + " " + d2); } } ```

    1. A. 2026-08-10 2026-08-10

      Assumes plusMonths mutated the original date in place; java.time types never mutate, so the original reference is left untouched at its starting value.

    2. B. 2026-06-15 2026-08-20

      Reads minusDays(5) as adding five days (Aug 15 + 5); the method subtracts, not adds.

    3. C. 2026-06-15 2026-06-10

      Applies only the minusDays(5) and drops the plusMonths(2), ignoring that both calls chain on the same expression.

    4. D. 2026-06-15 2026-08-10Correct answer

      The original date is immutable so it still holds 2026-06-15, while the chained plusMonths(2) then minusDays(5) computes Aug 15 and then Aug 10.

    Explanation

    `java.time` date types are immutable, so a method call never changes the receiver; the original reference still holds its starting value when printed. The second value comes from a chain in which each call operates on the previous call's return value, left to right: advancing two months to reach Aug 15, then subtracting five days from that intermediate result to reach Aug 10. Reading the two outputs separately — the unchanged original versus the freshly computed chain — is the key to tracing this correctly.

  2. Question 2

    Local clocks in Europe/Paris jump forward from 02:00 to 03:00 on March 29, 2026. What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { ZonedDateTime z = ZonedDateTime.of( LocalDateTime.of(2026, 3, 28, 12, 0), ZoneId.of("Europe/Paris")); ZonedDateTime byDays = z.plusDays(1); ZonedDateTime byDuration = z.plus(Duration.ofDays(1)); System.out.println(byDays.toLocalTime() + " " + byDuration.toLocalTime()); } } ```

    1. A. 12:00 13:00Correct answer

      Correct: plusDays(1) is date-based and preserves the local 12:00 across the spring-forward, while plus(Duration.ofDays(1)) adds an exact 86400 seconds on the timeline, landing on a 13:00 wall-clock reading.

    2. B. 11:00 12:00

      Assumes a spring-forward moves the local clock reading backward by an hour; spring-forward moves clocks forward, and plusDays preserves the local time-of-day regardless.

    3. C. 12:00 12:00

      Assumes Duration.ofDays(1) and plusDays(1) are interchangeable; a Duration is exact elapsed seconds and never consults the calendar, so it shifts the wall clock across a DST gap.

    4. D. 13:00 12:00

      Swaps the two operations, assuming plusDays is the exact-24-hours arithmetic and adding a Duration is the calendar-aware one; it is the other way round.

    Explanation

    Trace: the two ways of adding "a day" to a ZonedDateTime are not the same operation. `plusDays(1)` is date-based: it adds one calendar day to the LOCAL date-time, keeping the local clock reading at 12:00, and then re-resolves the offset (which has become +02:00 after the spring-forward). `plus(Duration.ofDays(1))` is time-based: a Duration is an exact elapsed amount, 86400 seconds, added to the instant on the timeline. Because the Paris clocks skipped an hour overnight, 24 hours of real elapsed time from 2026-03-28T12:00+01:00 lands on a local clock reading of 13:00 (at +02:00). So the local times differ by an hour. Why the others are wrong: `12:00 12:00` encodes the belief that Duration.ofDays(1) and plusDays(1) are interchangeable — it ignores that a Duration is exact elapsed seconds and never consults the calendar. `13:00 12:00` swaps the two: it assumes plusDays is the exact-24-hours operation and that adding a Duration is the calendar-aware one. It is the other way round. `11:00 12:00` assumes a spring-forward makes the local clock reading go BACKWARD by an hour. Spring-forward moves clocks forward, and in any case plusDays preserves the local time-of-day. Exam tip: on ZonedDateTime, Period/plusDays/plusMonths are date-based and preserve the local wall-clock time across a DST transition; Duration/plusHours/plus(Duration) are time-based and preserve the exact elapsed instant, so the wall clock shifts. The reverse trap is a fall-back day, where exact-24-hours arithmetic lands an hour EARLIER on the local clock instead of an hour later.

  3. Question 3

    A date-time on the last day of January is advanced by one month and then by two hours, and the elapsed `Duration` is reported in whole days. (2026 is not a leap year.) What is printed? ```java import java.time.Duration; import java.time.LocalDateTime; public class Main { public static void main(String[] args) { LocalDateTime start = LocalDateTime.of(2026, 1, 31, 23, 0); LocalDateTime end = start.plusMonths(1).plusHours(2); System.out.println(end + " " + Duration.between(start, end).toDays()); } } ```

    1. A. 2026-02-28T01:00 28

      Correctly clamps the date but forgets the added hours; adding two hours to 23:00 rolls the date forward to March 1 at 01:00.

    2. B. 2026-03-03T01:00 31

      Assumes plusMonths overflows the 31st into early March like legacy Calendar leniency; java.time clamps to the last valid day, February 28.

    3. C. 2026-03-01T01:00 28Correct answer

      plusMonths clamps January 31 to February 28, then adding two hours rolls to March 1 at 01:00; toDays truncates the twenty-eight-day-and-two-hour gap to 28.

    4. D. 2026-03-01T01:00 29

      Rounds the Duration up; toDays truncates toward zero, so twenty-eight days and two hours is 28, not 29.

    Explanation

    Calendar-based plusMonths keeps the day-of-month but clamps to the last valid day of the target month, so the end of January maps to February 28 in a non-leap year; adding hours can then roll the date across the month boundary. Duration is time-based and measures exact elapsed time, and toDays truncates toward zero. This is the classic Period-versus-Duration distinction.

  4. Question 4

    What does this print? (2026 is not a leap year, so February 2026 has 28 days.) ```java import java.time.*; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2026, 1, 30); Period p = Period.ofMonths(1).plusDays(1); LocalDate viaPeriod = d.plus(p); LocalDate viaChain = d.plusDays(1).plusMonths(1); System.out.println(viaPeriod + " " + viaChain); } } ```

    1. A. 2026-02-28 2026-03-01

      Swaps the two results by assuming Period.plus applies the days before the months; Period addition goes largest unit to smallest — years, then months, then days.

    2. B. 2026-03-01 2026-02-28Correct answer

      Adding a Period applies larger units first with clamping: d.plus(p) does Jan 30 + 1 month = Feb 28 (clamped), then + 1 day = Mar 1; the chain plusDays(1).plusMonths(1) does Jan 31 first, then + 1 month clamps to Feb 28 — same amounts, different order, different answer.

    3. C. 2026-03-01 2026-03-01

      Assumes the order of adding months and days never matters, so both routes agree; month-end clamping is exactly what breaks commutativity here.

    4. D. 2026-02-28 2026-02-28

      Assumes any month-end clamp is final and the trailing day-add is absorbed; in the Period route the day is really added after the clamp, so it carries into March.

    Explanation

    Trace: adding a Period is defined to apply the larger units first — years, then months, then days — and each step clamps to a valid date on its own. `d.plus(p)` therefore does Jan 30 + 1 month = Feb 28 (Feb 30 does not exist, so the month-add clamps to the last day of February), and only then adds 1 day, giving Mar 1. The chained call reverses the order: Jan 30 + 1 day = Jan 31 first, then + 1 month clamps Feb 31 down to Feb 28. Same two amounts, different order, different answer — date arithmetic with clamping is not commutative. Why the others are wrong: `2026-03-01 2026-03-01` encodes the belief that the order of adding months and days never matters, so both routes must agree. Clamping is what breaks commutativity. `2026-02-28 2026-02-28` assumes that any month-end clamp is final and the trailing day-add is somehow absorbed. The day is really added after the clamp in the Period route, which carries into March. `2026-02-28 2026-03-01` swaps the two results: it assumes Period.plus applies the DAYS before the months. Period addition goes largest unit to smallest. Exam tip: LocalDate.plus(Period) applies years, then months, then days, clamping at each step; a chain like plusDays(...).plusMonths(...) applies them in the order you wrote. When a month-end clamp is in play, the two orders can differ by a day. The reverse trap is a start date such as Jan 31, where both orders happen to converge on the same answer and the difference is invisible.

  5. Question 5

    What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { System.out.println(Year.of(2000).isLeap() + " " + Year.of(2100).isLeap()); } } ```

    1. A. true falseCorrect answer

      2000 is divisible by 400 so it is a leap year (true), while 2100 is a century divisible by 100 but not 400 so it is not a leap year (false).

    2. B. true true

      Treats every year divisible by four as leap, forgetting that 2100 is a century not divisible by 400 and therefore not a leap year.

    3. C. false false

      Denies 2000's leap status, but the divisible-by-400 exception makes 2000 a leap year.

    4. D. false true

      Inverts both cases entirely, contradicting the Gregorian rule for each of the two years.

    Explanation

    The proleptic Gregorian rule makes a year a leap year when it is divisible by four, except for century years, which must additionally be divisible by 400. A century divisible by 400 keeps its leap status, while a century divisible only by 100 loses it. Applying that exception separates the two years: one century survives the rule and the other does not. Only the divisible-by-400 rule saves a century year — 1600 and 2000 are leap, but 1700, 1800, 1900 and 2100 are not.

  6. Question 6

    March 29, 2026 is the spring-forward day in Europe/Paris (local clocks jump from 02:00 to 03:00). What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { ZonedDateTime z = ZonedDateTime.of( LocalDateTime.of(2026, 3, 29, 2, 30), ZoneId.of("Europe/Paris")); System.out.println(z); } } ```

    1. A. 2026-03-29T02:30+01:00[Europe/Paris]

      Keeps the requested local time with the winter offset, but that instant is exactly what the gap removed; the API never yields a time inside the gap.

    2. B. 2026-03-29T02:30+02:00[Europe/Paris]

      Keeps the local time but swaps to the summer offset, which still names a non-existent local time inside the gap.

    3. C. 2026-03-29T03:30+02:00[Europe/Paris]Correct answer

      The requested 02:30 falls in the spring-forward gap, so ZonedDateTime.of pushes the local time forward by the one-hour gap and applies the after-transition offset, giving 03:30 at +02:00.

    4. D. Throws DateTimeException

      A gap time does not throw; ZonedDateTime.of resolves it by shifting forward rather than raising an exception.

    Explanation

    When a requested local time falls inside a spring-forward gap — an hour that never occurs on that date — `ZonedDateTime.of` does not reject it. Instead it pushes the local time forward by the length of the gap and applies the offset in effect after the transition, so the result lands just past the gap at the summer offset. This resolution is silent: gap times shift forward and overlap times default to the earlier offset, and neither case throws. Use `withEarlierOffsetAtOverlap` or `withLaterOffsetAtOverlap` to control the overlap case.

  7. Question 7

    What does this print? (`Instant.until(Instant)` was added in Java 23.) ```java import java.time.*; public class Main { public static void main(String[] args) { Instant start = Instant.ofEpochSecond(0); Instant end = Instant.ofEpochSecond(5400); System.out.println(start.until(end)); } } ```

    1. A. 5400

      5400 is what the other overload until(Temporal, ChronoUnit.SECONDS) returns as a long; the single-argument form returns a Duration, whose toString never prints a bare number.

    2. B. PT5400S

      Assumes the Duration keeps raw seconds; toString normalizes into the largest whole units instead of printing PT5400S.

    3. C. PT90M

      Stops at minutes, but normalization rolls 90 minutes up into one hour and thirty minutes.

    4. D. PT1H30MCorrect answer

      The single-argument Instant.until(Instant) overload (added in Java 23) returns a Duration; 5400 seconds normalizes to one hour and thirty minutes, printing PT1H30M.

    Explanation

    The single-argument until overload added in Java 23 returns a `Duration` rather than a long count, so the result is printed through `Duration.toString`. That renderer normalizes the span into the largest whole units — hours, then minutes, then seconds — so a gap of 5400 seconds becomes one hour and thirty minutes rather than a raw second count or an un-normalized larger unit. This contrasts with the two-argument until overload, which returns a `long` in the requested unit.

  8. Question 8

    Given two `LocalDate` values `a` and `b` with `a` before `b`, which two statements are correct? (Choose two.)

    1. A. ChronoUnit.DAYS.between(a, b) returns the total number of whole days, whereas Period.between(a, b) splits the gap into a years/months/days component formCorrect answer

      ChronoUnit.DAYS.between returns a single whole-day total from start inclusive to end exclusive, whereas Period.between decomposes the same gap into years, months and days components.

    2. B. Period.between(a, b).getDays() always equals ChronoUnit.DAYS.between(a, b)

      getDays() is only the leftover days component after whole months are removed, not the total; for Jan 31 to Mar 1 it is 1 while ChronoUnit.DAYS.between is 29.

    3. C. Across a spring-forward daylight-saving transition, adding Duration.ofHours(24) to a ZonedDateTime can produce a different local time than adding Period.ofDays(1)Correct answer

      A Period is date-based, so adding Period.ofDays(1) keeps the wall-clock time and lets zone rules decide the day length, while Duration.ofHours(24) adds exactly 24 physical hours; across a spring-forward gap the two land on different local times.

    4. D. Duration is date-based and Period is time-based, so Duration.between is the correct way to count the number of days between two LocalDate values

      The labels are reversed — Period is date-based and Duration is time-based — and Duration.between over two LocalDate values throws because a LocalDate has no seconds field.

    Explanation

    Period and ChronoUnit both work on calendar dates but report differently: ChronoUnit gives a single total in one unit, while Period splits a gap into calendar components, so a component such as leftover days is not the same as the total. Period is date-based and Duration is time-based — a distinction that matters on zoned types, where adding a calendar day preserves wall-clock time across a daylight-saving transition while adding a fixed span of hours does not. Matching the tool to the job means using Period or ChronoUnit for dates and Duration for instants and times, since Duration.between cannot even measure two dates that carry no seconds field.

Practise all 14 Date/Time API (JSR-310) questions

OCP Java SE 25 has the full set, inside timed mock exams that mirror real exam conditions — every question with a worked explanation.

Open OCP Java SE 25

Other topics in this pack