Date/Time API (JSR-310) practice questions

From OCP Java SE 21 (1Z0-830) · 14 questions on this topic

Date/Time API (JSR-310) practice questions from OCP Java SE 21 (1Z0-830). 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 is the output of the following program? ```java import java.time.*; public class Main { public static void main(String[] args) { Period p = Period.of(1, 15, 40); Period n = p.normalized(); System.out.println(n.getYears() + " " + n.getMonths() + " " + n.getDays()); } } ```

    1. A. 1 15 40

      This is the raw un-normalized Period as stored by `Period.of(1, 15, 40)`. The candidate may believe `normalized()` is a no-op or that `Period.of` itself normalizes on construction. Neither is true: `Period.of` stores the given values as-is, and `normalized()` does adjust months, so the output differs from the original.

    2. B. 2 4 10

      Assumes `normalized()` also normalizes days using a 30-day month: 40 days would become 1 extra month plus 10 days, pushing months to 4 and days to 10. The Javadoc is unambiguous: 'The days unit is not normalized' — only the years and months components are adjusted.

    3. C. Throws DateTimeException

      Neither `Period.of` nor `normalized()` validates or restricts the magnitude of any field. Any integer is accepted for years, months, or days; months greater than 11 or days greater than 30 cause no exception — they are simply stored and then adjusted as needed by `normalized()`.

    4. D. 2 3 40Correct answer

      `normalized()` adjusts months so their absolute value is less than 12, carrying the overflow into years: 15 months becomes 1 additional year plus 3 remaining months, so years = 1 + 1 = 2 and months = 3. The Javadoc explicitly states that the days component is left unchanged, so 40 days passes through as-is.

    Explanation

    `Period.normalized()` adjusts only the years and months components so that the absolute value of months is less than 12, carrying surplus months into years; the days component is explicitly excluded from normalization. `Period.of` accepts any integer value for any component without restriction, and neither method throws. Carrying 15 months as 1 extra year and 3 remaining months, then adding to the initial 1 year, gives 2 years and 3 months — with 40 days left exactly as stored.

  2. Question 2

    What is the output of the following program? ```java import java.time.*; public class Main { public static void main(String[] args) { Duration d = Duration.ofDays(1).plusHours(2).plusMinutes(30); System.out.println(d.toHours() + " " + d.toMinutesPart()); } } ```

    1. A. 2 30

      Confuses toHours() with toHoursPart(). toHoursPart() returns the hours component modulo 24 (26 % 24 = 2) — the hours field when the duration is expressed as days, hours, minutes, and seconds. toHours() returns the total whole-hour count of the entire duration, which is 26.

    2. B. 26 1590

      Confuses toMinutesPart() with toMinutes(). toMinutes() converts the entire duration to whole minutes (95400 / 60 = 1590). toMinutesPart() returns only the sub-hour minutes component (30), following the naming convention shared by toHoursPart(), toMinutesPart(), and toSecondsPart().

    3. C. 26 30Correct answer

      Duration.ofDays(1).plusHours(2).plusMinutes(30) produces PT26H30M stored internally as 95400 seconds. toHours() divides total seconds by 3600 and truncates: 95400 / 3600 = 26. toMinutesPart() extracts the sub-hour minutes component: (95400 % 3600) / 60 = 1800 / 60 = 30.

    4. D. 1 30

      Misreads toHours() as though it returns the number of whole days in the duration (1). That value would come from toDays(); toHours() converts the entire duration to whole hours, yielding 26 for a span of one day, two hours, and thirty minutes.

    Explanation

    Duration stores time internally as a total of seconds and nanoseconds with no separate day or hour fields. The methods toHours() and toMinutes() express that total converted to the named unit, truncated toward zero. The 'Part' variants — toHoursPart(), toMinutesPart(), toSecondsPart() — instead extract the component remaining after dividing out the next larger unit, analogous to individual fields on a clock display. For a duration of one day, two hours, and thirty minutes (95400 seconds), toHours() yields the total whole hours (26) and toMinutesPart() yields the sub-hour minutes remainder (30).

  3. Question 3

    Adding one month twice is compared with adding two months in a single step, starting from the last day of January in a leap year. Select the output. ```java import java.time.*; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2024, 1, 31); LocalDate a = d.plusMonths(1).plusMonths(1); LocalDate b = d.plusMonths(2); Period p = Period.between(a, b); System.out.println(a + " " + b + " " + p); } } ```

    1. A. 2024-03-31 2024-03-31 P0D

      Assumes stepping month-by-month round-trips back to the 31st; the first clamp to February 29 is lossy, so the two-step path lands on March 29, not March 31.

    2. B. 2024-03-29 2024-03-29 P0D

      Assumes the single two-month step also clamps through February; adding two months at once never visits February's length, so it stays on the 31st.

    3. C. 2024-03-29 2024-03-31 P2DCorrect answer

      The step-by-step path clamps January 31 to February 29 then advances to March 29, while the single two-month add lands on March 31, and the calendar gap between them is reported as P2D.

    4. D. 2024-03-28 2024-03-31 P3D

      Uses February 28 as the clamp target; 2024 is a leap year, so January 31 plus one month clamps to February 29, making the later dates and the period different.

    Explanation

    When adding months lands on a day the target month does not have, the date is clamped to that month's last valid day, and this clamping loses information. Applying the addition in two separate steps can therefore pass through a short month and yield a different result than adding the whole span at once, so month arithmetic is not associative; the calendar gap between two dates is a date-based amount.

  4. Question 4

    In the America/New_York zone, clocks spring forward one hour at 02:00 on 2026-03-08. What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { ZoneId ny = ZoneId.of("America/New_York"); ZonedDateTime start = ZonedDateTime.of(2026, 3, 7, 12, 0, 0, 0, ny); ZonedDateTime a = start.plus(Period.ofDays(1)); ZonedDateTime b = start.plus(Duration.ofDays(1)); System.out.println(a.toLocalTime() + " " + b.toLocalTime()); } } ```

    1. A. 13:00 13:00

      Applies the elapsed-time rule to both, as if Period were also converted to fixed hours. Period is date-based and keeps the local clock time, so it gives 12:00, not 13:00.

    2. B. 12:00 12:00

      Assumes Duration.ofDays(1) and Period.ofDays(1) are interchangeable, the belief that a day is always 24 hours, which the DST spring-forward falsifies for the elapsed-time Duration.

    3. C. 12:00 11:00

      Gets the direction of the shift backwards, treating spring-forward as if it lengthened the day; the civil day is only 23 hours, so 24 elapsed hours lands one hour later, at 13:00.

    4. D. 12:00 13:00Correct answer

      Period.ofDays(1) is date-based and keeps the local time (12:00), while Duration.ofDays(1) adds exactly 86,400 seconds; the 23-hour spring-forward day pushes that to 13:00.

    Explanation

    Trace: both operands say "one day", but they are different kinds of amount. `Period.ofDays(1)` is *date-based*: it adds one calendar day to the local date and keeps the local time, then re-resolves the offset — so noon on the 7th becomes noon on the 8th, `12:00`. `Duration.ofDays(1)` is *time-based*: it is exactly 86 400 seconds on the timeline. Because the spring-forward removes an hour from 2026-03-08 in New York, that civil day is only 23 hours long, so 24 elapsed hours lands one hour past noon, `13:00`. Output: `12:00 13:00`. Why the others are wrong: `12:00 12:00` assumes `Duration.ofDays(1)` and `Period.ofDays(1)` are interchangeable — the belief that a day is always 24 hours, which is exactly what a DST zone falsifies. `13:00 13:00` applies the elapsed-time rule to both, as if `Period` were also converted to a fixed number of hours. `Period` never touches the clock time. `12:00 11:00` gets the direction of the shift backwards, treating spring-forward as if it lengthened the day. Exam tip: `Period` is conceptual/calendar time, `Duration` is machine/elapsed time, and on a `ZonedDateTime` they diverge on exactly the two DST days per year. `ChronoUnit.DAYS.between` behaves like `Period` here (it counts whole calendar days), while `ChronoUnit.HOURS.between` counts elapsed hours and will report 23 for that civil day. On a `LocalDateTime`, which has no zone, the two agree — the trap only fires once a zone is attached.

  5. Question 5

    What is the output of the following program? ```java import java.time.*; public class Main { public static void main(String[] args) { LocalTime t = LocalTime.of(23, 30); LocalTime t2 = t.plusMinutes(60); System.out.println(t2); } } ```

    1. A. 00:30Correct answer

      `LocalTime.plusMinutes` wraps around the 24-hour clock: 23:30 plus 60 minutes equals 00:30. `LocalTime.toString()` uses the shortest ISO-8601 form that fully represents the value; because seconds and sub-seconds are zero only the HH:mm pattern is needed, and the hour is always rendered with two digits, producing `00:30`.

    2. B. 0:30

      `LocalTime.toString()` always formats the hour with two digits (the HH component of HH:mm). A single-digit rendering such as `0:30` would require an explicit `DateTimeFormatter.ofPattern("H:mm")`; the implicit `toString()` never produces it.

    3. C. 24:30

      `LocalTime` stores values only in the range 00:00:00 to 23:59:59.999999999. Adding minutes that push the result past midnight wraps modulo 24 hours rather than extending the hour beyond 23; the value 24:30 is not a representable `LocalTime` and can never appear in output.

    4. D. Throws DateTimeException

      `LocalTime.plusMinutes()` is defined to wrap around midnight silently using modular arithmetic. Only factory methods such as `LocalTime.of(int, int)` throw `DateTimeException` when a field value is out of its valid range at construction; arithmetic methods never throw for overflow.

    Explanation

    `LocalTime` arithmetic methods apply modular arithmetic around the 24-hour clock rather than throwing when a result would exceed 23:59:59, so adding minutes past midnight is well-defined and produces no exception. Factory methods such as `LocalTime.of` do throw `DateTimeException` for an out-of-range field, but arithmetic methods do not. `LocalTime.toString()` emits the shortest ISO-8601 form sufficient to represent the value and always uses two digits for the hour (HH), so a wrapped result of zero hours is rendered `00`, never as `0` or as the invalid `24`.

  6. Question 6

    In the America/New_York zone, clocks spring forward one hour at 02:00 on 2026-03-08, so the local times from 02:00 up to 02:59 never occur on that date. What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { ZoneId ny = ZoneId.of("America/New_York"); ZonedDateTime z = ZonedDateTime.of(2026, 3, 8, 2, 30, 0, 0, ny); System.out.println(z); } } ```

    1. A. 2026-03-08T03:30-04:00[America/New_York]Correct answer

      The requested 02:30 falls in the DST GAP; ZonedDateTime.of shifts the local time later by the one-hour gap to 03:30 and uses the post-transition offset -04:00 (EDT).

    2. B. 2026-03-08T02:30-05:00[America/New_York]

      Assumes the requested local time is preserved and only the offset is chosen. That instant would map back to a wall time the zone SKIPPED; ZonedDateTime never returns a local time inside its own gap.

    3. C. A DateTimeException is thrown because 02:30 does not exist on that date

      Assumes a non-existent local time is an error. ZonedDateTime.of is LENIENT and resolves the gap by shifting forward; ZonedDateTime.ofStrict is the one that throws.

    4. D. 2026-03-08T01:30-05:00[America/New_York]

      Shifts BACKWARDS out of the gap. The gap rule moves the time forward by the gap length, not backwards, so 02:30 becomes 03:30, not 01:30.

    Explanation

    Trace: the requested local time falls in the DST *gap*. `ZonedDateTime.of` does not reject it. Its documented rule for a gap is to shift the local date-time *later* by the length of the gap and use the offset *after* the transition. The gap is one hour, so 02:30 becomes 03:30, and the offset in force after the spring-forward is -04:00 (EDT). The result prints as `2026-03-08T03:30-04:00[America/New_York]`. Why the others are wrong: `2026-03-08T02:30-05:00[...]` assumes the requested local time is preserved and only the offset is chosen — that would name an instant that maps back to 02:30 EST, a wall time the zone skipped. `ZonedDateTime` never returns a local time inside its own gap. `2026-03-08T01:30-05:00[...]` shifts *backwards* out of the gap. The rule moves forward by the gap length, not backwards. `A DateTimeException is thrown because...` is the most tempting misconception: that a non-existent local time is an error. `ZonedDateTime.of` is lenient — it resolves gaps and overlaps rather than throwing. (`ZonedDateTime.ofStrict` is the one that throws.) Exam tip: two DST rules, and they are not symmetric. In a *gap*, the time is pushed forward by the gap length and takes the post-transition offset. In an *overlap* (fall back), the local time is valid twice and `of` keeps the *earlier* offset — use `withLaterOffsetAtOverlap` for the other one. Neither case throws.

  7. Question 7

    What is the output of the following program? ```java import java.time.*; public class Main { public static void main(String[] args) { LocalDate d1 = LocalDate.of(2024, 1, 15); LocalDate d2 = LocalDate.of(2024, 4, 10); Period p = Period.between(d1, d2); System.out.println(p.getMonths() + " " + p.getDays()); } } ```

    1. A. 2 26Correct answer

      Period.between counts complete month transitions anchored on the start day-of-month. The end day (10) is less than the start day (15), so the third calendar month is incomplete: getMonths() returns 2. The remaining days are the epoch-day gap from 2024-03-15 (start plus those 2 complete months) to 2024-04-10: 16 days remaining in March plus 10 days in April equals 26.

    2. B. 3 26

      Counts months as the raw calendar-month difference (April minus January = 3) without applying the day-of-month adjustment. When the end day is less than the start day, Period.between reduces the month count by one and rolls the residual into the days component.

    3. C. 2 10

      Correctly adjusts the month count to 2 but misreads getDays() as the day-of-month of the end date (April 10 → 10). getDays() returns the days component of the normalised period — computed from epoch-day arithmetic — not the day-of-month field of the end date.

    4. D. 3 10

      Applies both mistakes simultaneously: uses the raw calendar-month difference (3) and reads getDays() as the end day-of-month (10), ignoring the day-of-month adjustment that Period.between performs entirely.

    Explanation

    Period.between normalises an interval into years, months, and days by counting complete month transitions relative to the start day-of-month. A month transition is complete only when the end day-of-month is at least the start day-of-month. Because 10 is less than 15, the third month is not yet complete, so getMonths() is 2 rather than 3. The remaining days are then the epoch-day distance between the start date advanced by those 2 months (2024-03-15) and the end date (2024-04-10): 16 remaining days in March plus 10 days in April equals 26.

  8. Question 8

    What does this print? ```java import java.time.*; public class Main { public static void main(String[] args) { LocalTime t = LocalTime.of(23, 45); LocalTime r = t.plusMinutes(30); System.out.println(r); } } ```

    1. A. 00:15Correct answer

      LocalTime has no date, so its arithmetic wraps within a 24-hour cycle; 23:45 + 30 min is 24:15 on a naive clock, reduced modulo one day to 00:15, and the excess day is silently discarded.

    2. B. 24:15

      Assumes the hour field can hold 24. LocalTime hours run 0–23; 24 is never a valid value and is never printed.

    3. C. 23:75

      Assumes the minutes accumulate without carrying into the hour — arithmetic on a raw int field rather than on a time. The minutes carry, giving 00:15.

    4. D. A DateTimeException is thrown because the result rolls past midnight

      Assumes overflowing midnight is an error. Wrap-around is the defined behaviour; only CONSTRUCTING an out-of-range value like LocalTime.of(24, 15) throws.

    Explanation

    Trace: `LocalTime` is a wall-clock time with no date attached, so its arithmetic wraps within a 24-hour cycle rather than overflowing. 23:45 plus 30 minutes is 24:15 on a naive clock, and `plusMinutes` reduces that modulo one day to 00:15. The excess day is silently discarded — `LocalTime` has nowhere to put it. `toString` then emits the two-digit hour and minute, giving `00:15`. Why the others are wrong: `24:15` assumes the hour field can hold 24. `LocalTime` hours run 0-23; 24 is never a valid value and never printed. `23:75` assumes the minutes just accumulate without carrying into the hour — arithmetic on a raw int field rather than on a time. `A DateTimeException is thrown because...` encodes the belief that overflowing midnight is an error. It is not: wrap-around is the defined behaviour. Only *constructing* an out-of-range value, as in `LocalTime.of(24, 15)`, throws. Exam tip: `LocalTime` and `LocalDateTime` differ exactly here — `LocalTime.plusMinutes` wraps around midnight and loses the day, while `LocalDateTime.plusMinutes` carries into the date. The reverse trap is the same wrap on subtraction: `LocalTime.of(0, 10).minusMinutes(20)` gives `23:50`, not a negative time.

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

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

Open OCP Java SE 21

Other topics in this pack