Date/Time API (JSR-310) practice questions

From OCP Java SE 17 (1Z0-829) · 16 questions on this topic

Date/Time API (JSR-310) practice questions from OCP Java SE 17 (1Z0-829). This pack has 16 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) { ZonedDateTime ny = ZonedDateTime.of(2026, 1, 15, 9, 0, 0, 0, ZoneId.of("America/New_York")); ZonedDateTime tokyo = ny.withZoneSameInstant(ZoneId.of("Asia/Tokyo")); System.out.println(tokyo.toLocalTime()); } } ```

    1. A. 09:00

      09:00 is what withZoneSameLocal would keep - the same wall-clock reading at a different instant; withZoneSameInstant instead preserves the instant.

    2. B. 23:00Correct answer

      On January 15 New York is on standard time (UTC-5), so 09:00 there is 14:00 UTC; Tokyo is UTC+9 year-round, making the same instant 23:00, which withZoneSameInstant recomputes. (Javadoc 17 - ZonedDateTime.withZoneSameInstant.)

    3. C. 19:00

      19:00 assumes New York is on daylight time (UTC-4), but mid-January is standard time.

    4. D. 22:00

      22:00 uses a 13-hour offset; the gap from EST (-5) to JST (+9) is 14 hours.

    Explanation

    withZoneSameInstant keeps the same moment in time and recomputes the wall-clock fields for the new zone. In mid-January New York observes standard time at UTC-5, so 9 a.m. there is 14:00 UTC, and Tokyo's year-round UTC+9 offset places that same instant at 23:00. The fourteen-hour separation, and the fact that no daylight saving applies in January, are what drive the result.

  2. Question 2

    2026-06-01 is a Monday. What does this print? ```java import java.time.*; import java.time.temporal.TemporalAdjusters; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2026, 6, 1); LocalDate a = d.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); LocalDate b = d.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY)); System.out.println(a + " " + b); } } ```

    1. A. 2026-06-08 2026-06-08

      Wrong: this assumes nextOrSame always advances by at least one day, i.e. that both adjusters are the strict flavour. The OrSame variant returns the input unchanged when it already matches.

    2. B. 2026-06-01 2026-06-08

      Wrong: this swaps the two definitions - reading next as 'including today' and nextOrSame as 'move on'. It is the reverse.

    3. C. 2026-06-08 2026-06-01Correct answer

      Correct: the start date is already a Monday, so strict next(MONDAY) skips it and returns 2026-06-08, while nextOrSame(MONDAY) returns the input 2026-06-01 unchanged.

    4. D. 2026-06-01 2026-06-01

      Wrong: this assumes next also returns the same day when it already matches, i.e. that both adjusters are the OrSame flavour. Plain next is strict and never returns the input date.

    Explanation

    Trace: the start date is itself a Monday, which is exactly where the two adjusters part company. `next(MONDAY)` is *strictly* after the input, so it skips the current Monday and returns 2026-06-08. `nextOrSame(MONDAY)` returns the input unchanged when it already matches, so it returns 2026-06-01. `with` returns a new `LocalDate`; `d` is untouched. Output: `2026-06-08 2026-06-01`. Why the others are wrong: `2026-06-01 2026-06-08` swaps the two definitions — the classic mix-up, reading `next` as 'the next one, including today' and `nextOrSame` as 'move on'. `2026-06-01 2026-06-01` assumes `next` also returns the same day when it already matches, i.e. that both adjusters are the 'or same' flavour. `2026-06-08 2026-06-08` assumes `nextOrSame` always advances by at least one day, i.e. that both adjusters are the strict flavour. Exam tip: in `TemporalAdjusters`, the plain `next`/`previous` are strict (never return the input date), and only the `...OrSame` variants can return it. Everything hinges on whether the start date is already the wanted day-of-week — if a stem hands you a start date and helpfully tells you its day-of-week, that is the point of the question. `firstInMonth(MONDAY)` and `lastInMonth(MONDAY)` ignore the input's day entirely and jump to the month boundary.

  3. Question 3

    What does this print? (2026-03-08 is the date US clocks spring forward.) ```java import java.time.*; public class Main { public static void main(String[] args) { Instant start = Instant.parse("2026-03-08T06:45:30Z"); Instant end = start.plus(Duration.ofHours(2)).minusSeconds(45); System.out.println(Duration.between(start, end) + " " + end); } } ```

    1. A. PT119M15S 2026-03-08T08:44:45Z

      Wrong: this assumes Duration.toString prints whatever unit you constructed it in and never rolls minutes up into hours. It always normalizes into hours, minutes and seconds, so 119M becomes 1H59M.

    2. B. PT1H59M15S 2026-03-08T08:44:45

      Wrong: this drops the Z designator. Instant.toString always appends Z; without it the text would not round-trip through Instant.parse.

    3. C. PT1H59M15S 2026-03-08T09:44:45Z

      Wrong: this applies the US spring-forward hour to the arithmetic. An Instant is a point on the UTC timeline with no zone, so DST rules can never affect it - the date is decoration.

    4. D. PT1H59M15S 2026-03-08T08:44:45ZCorrect answer

      Correct: 06:45:30Z plus two hours minus 45 seconds is 08:44:45Z, and the gap of 1 hour 59 minutes 15 seconds renders as the ISO-8601 PT1H59M15S with the UTC Z designator.

    Explanation

    Trace: 06:45:30Z plus two hours is 08:45:30Z; minus 45 seconds is 08:44:45Z. The gap from start to end is 2 hours minus 45 seconds = 1 hour 59 minutes 15 seconds, and `Duration.toString` emits ISO-8601, breaking the total down into hours, minutes and seconds: `PT1H59M15S`. `Instant.toString` emits ISO-8601 in UTC with the `Z` designator. Output: `PT1H59M15S 2026-03-08T08:44:45Z`. Why the others are wrong: `PT119M15S 2026-03-08T08:44:45Z` assumes `Duration.toString` prints whatever unit you constructed it in and never rolls minutes up into hours. It always normalizes into hours/minutes/seconds. `PT1H59M15S 2026-03-08T09:44:45Z` applies the US spring-forward hour to the arithmetic. An `Instant` is a point on the UTC timeline with no zone at all, so DST rules can never affect it — only a zoned type reacts to a transition. `PT1H59M15S 2026-03-08T08:44:45` drops the `Z`. `Instant.toString` always appends it; without a zone designator the text would not round-trip through `Instant.parse`. Exam tip: `Instant` = machine time (UTC, no zone, no DST, no calendar fields); `LocalDateTime` = human time with no zone; `ZonedDateTime` = both. Watch for a stem that dangles a DST date in front of an `Instant` calculation — the date is decoration. The reverse trap is doing the same two-hour addition on a `ZonedDateTime` in America/New_York, where the wall clock genuinely does jump.

  4. Question 4

    Which two statements about the java.time API are correct? (Choose two.)

    1. A. Core types such as LocalDate and Duration are immutable; methods like plusDays return a new object instead of modifying the receiverCorrect answer

      The core JSR-310 types are immutable, so arithmetic and with-methods return a new instance instead of mutating the receiver, which is also what makes them thread-safe. (Javadoc 17 - java.time package design.)

    2. B. LocalDate.plusMonths throws DateTimeException when the target month is shorter than the current day-of-month

      plusMonths does not throw for a short target month; it adjusts to that month's last valid day, e.g. January 31 plus one month becomes February 28 in a non-leap year.

    3. C. Period is a date-based amount of years, months and days, while Duration is a time-based amount of seconds and nanosecondsCorrect answer

      Period models a date-based amount of years, months, and days that pairs with LocalDate, while Duration models a time-based amount of seconds and nanoseconds that pairs with Instant and time-based types.

    4. D. A DateTimeFormatter pattern using MMM prints the same month text in every locale

      MMM produces a localized month name (Jul vs juil. vs the Japanese form), not the same text in every locale, which is why deterministic code passes an explicit Locale to ofPattern.

    Explanation

    Two design facts anchor JSR-310. First, its core types are immutable, so every arithmetic or with-operation yields a new object and leaves the original untouched, which also makes them thread-safe. Second, the API separates calendar amounts from clock amounts: Period models human years, months, and days for date types, while Duration models exact seconds and nanoseconds for instant and time-based types. By contrast, plusMonths clamps rather than throwing on a short month, and text pattern letters such as the abbreviated month are locale-dependent.

  5. Question 5

    What does this print? ```java import java.time.*; import java.time.format.*; import java.util.Locale; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2026, 7, 4); DateTimeFormatter f = DateTimeFormatter.ofPattern("dd MMM uuuu", Locale.US); System.out.println(d.format(f)); } } ```

    1. A. 4 Jul 2026

      Using a single pattern letter d would allow the unpadded 4; the pattern uses dd, which always pads the day to two digits.

    2. B. 04 Jul 2026Correct answer

      With Locale.US, dd is the zero-padded two-digit day (04), MMM is the abbreviated month name (Jul), and uuuu is the four-digit year (2026), giving 04 Jul 2026. (Javadoc 17 - DateTimeFormatter.ofPattern letter counts.)

    3. C. 04 July 2026

      The full month name July requires four M's (MMMM); three M's produce the abbreviation.

    4. D. 04 07 2026

      The numeric month 07 comes from MM; MMM switches the month to its text form.

    Explanation

    In a DateTimeFormatter pattern the number of repeated letters selects each field's form: dd forces two-digit zero-padded days, uuuu gives the four-digit year, and for the month MM is numeric, MMM is the abbreviated name, and MMMM is the full name. So the pattern dd MMM uuuu renders the padded day, the abbreviated month, and the year. Because text forms like the month abbreviation are locale-sensitive, the explicit Locale.US pins the output to English.

  6. Question 6

    What is the result of running this code? ```java import java.time.*; import java.time.format.*; public class Main { public static void main(String[] args) { LocalDate d = LocalDate.of(2026, 6, 1); DateTimeFormatter f = DateTimeFormatter.ofPattern("dd/MM/uuuu HH:mm"); System.out.println(d.format(f)); } } ```

    1. A. 01/06/2026 00:00

      Wrong: this assumes an absent time defaults to midnight. That is what LocalDate.atStartOfDay() does when asked explicitly; formatting never invents field values.

    2. B. The code does not compile, because format() on a LocalDate rejects a pattern containing time fields

      Wrong: this assumes the compiler can see inside the pattern string. ofPattern is an ordinary method call, so a LocalDate accepts any formatter at compile time and the mismatch surfaces only at run time.

    3. C. It compiles, then throws an UnsupportedTemporalTypeException at runtimeCorrect answer

      Correct: the formatter asks the LocalDate for the HourOfDay field, which a LocalDate does not carry, so it throws UnsupportedTemporalTypeException at run time.

    4. D. 01/06/2026

      Wrong: this assumes the formatter silently skips fields the temporal cannot supply. A field it cannot resolve is an error, not a no-op.

    Explanation

    Trace: the pattern is built at runtime from a string, so nothing about the time fields is visible to the compiler — `LocalDate.format(DateTimeFormatter)` type-checks with any formatter. When the formatter runs, it asks the `LocalDate` for the `HourOfDay` field. A `LocalDate` carries no time fields, so it throws `java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay`. Why the others are wrong: `01/06/2026 00:00` assumes an absent time defaults to midnight. That is what `LocalDate.atStartOfDay()` does when you ask for it explicitly; formatting never invents field values. `01/06/2026` assumes the formatter silently skips fields the temporal cannot supply. It does not — a field it cannot resolve is an error, not a no-op. `The code does not compile, because format() on a LocalDate rejects a pattern containing time fields` assumes the compiler can see inside the pattern string. `ofPattern` is an ordinary method call; the mismatch can only be discovered at runtime. Exam tip: pair the temporal type with the pattern's fields. `LocalDate` supports only date fields, `LocalTime` only time fields, and a formatter with a zone or offset letter (`z`, `VV`, `X`) applied to a `LocalDateTime` throws the same exception. The reverse trap is `LocalDate.parse("2026-06-01", DateTimeFormatter.ofPattern("dd/MM/uuuu"))`, which throws `DateTimeParseException` instead — a parse mismatch and a format mismatch have different exception types.

  7. Question 7

    What does this print? ```java import java.time.*; import java.time.temporal.*; public class Main { public static void main(String[] args) { LocalDate a = LocalDate.of(2026, 1, 1); LocalDate b = LocalDate.of(2026, 3, 1); System.out.println(ChronoUnit.DAYS.between(a, b)); } } ```

    1. A. 2

      2 is the count ChronoUnit.MONTHS.between would return, not DAYS.

    2. B. 60

      60 assumes a 29-day leap-year February or counts the end date inclusively; February 2026 has 28 days and the end is exclusive.

    3. C. 58

      58 shortchanges January or February by one day.

    4. D. 59Correct answer

      between is start-inclusive and end-exclusive, so it sums January's 31 days and February's 28 (2026 is not a leap year) to give 59. (Javadoc - ChronoUnit.between.)

    Explanation

    ChronoUnit.DAYS.between measures the elapsed amount in whole days, counting the start date but not the end date. From January 1 to March 1 that is all of January (31 days) plus all of February, and because 2026 is not a leap year February contributes 28, totalling 59. Choosing the wrong temporal unit or misjudging the leap year is what shifts the count.

  8. Question 8

    Which two statements about `Period` and `Duration` are correct? (Choose two.)

    1. A. `Period.of(0, 0, 45).normalized()` returns a period of 1 month and 15 days

      normalized() only rolls months into years and never touches the days field, so Period.of(0, 0, 45).normalized() stays P45D, not 1 month and 15 days.

    2. B. `Duration.between(LocalDate.of(2026, 1, 1), LocalDate.of(2026, 1, 5))` compiles, but throws at runtime because LocalDate supports no time-based unitsCorrect answer

      Duration.between accepts any Temporal so it compiles, but it measures in seconds/nanos, which LocalDate does not support, so it throws UnsupportedTemporalTypeException at run time.

    3. C. `Period.ofMonths(1).get(ChronoUnit.DAYS)` returns 30, because a month is normalized to 30 days

      A Period stores its three fields independently and converts nothing, so get(ChronoUnit.DAYS) reads the days field (0 here), not a 30-day-month equivalent.

    4. D. Adding `Duration.ofDays(1)` to a ZonedDateTime the day before a spring-forward transition gives a different local time than adding `Period.ofDays(1)`Correct answer

      Duration.ofDays(1) adds exactly 86400 seconds on the instant timeline while Period.ofDays(1) keeps the wall-clock time, so across a spring-forward transition the two land on different local times.

    Explanation

    Why `Duration.between(LocalDate.of(2026, 1, 1), LocalDate.of(2026, 1, 5))` compiles, but throws...` is correct: `Duration.between` takes two `Temporal` arguments, so any `Temporal` type type-checks. At runtime it measures the gap in SECONDS/NANOS, and `LocalDate` supports neither, so it throws `UnsupportedTemporalTypeException: Unsupported unit: Seconds`. Why `Adding \`Duration.ofDays(1)\` to a ZonedDateTime the day before a spring-forward...` is correct: a `Duration` is an exact amount of elapsed time (24 hours = 86400 seconds) added on the instant timeline, while a `Period` of 1 day is a calendar amount added to the local date, keeping the wall-clock time. From 2026-03-07T12:00-05:00[America/New_York], the Duration lands on 2026-03-08T13:00-04:00 (the clocks moved forward an hour during those 86400 seconds) and the Period lands on 2026-03-08T12:00-04:00. Same start, one hour apart. Why the others are wrong: `Period.of(0, 0, 45).normalized()` returns a period of 1 month and 15 days` — `normalized()` only rolls months into years (it splits total months by 12). Days are never touched, because the number of days in a month is not fixed. `Period.of(0, 0, 45).normalized()` is still `P45D` and `getMonths()` is 0. `Period.ofMonths(1).get(ChronoUnit.DAYS)` returns 30...` — a `Period` stores its three fields independently and converts nothing. `get(ChronoUnit.DAYS)` reads the days field, which is 0 here; there is no 30-day month assumption anywhere in `Period`. Exam tip: `Period` is date-based (years/months/days, calendar-aware, DST-aware when added to a zoned value); `Duration` is time-based (seconds/nanos, exact elapsed time). The reverse trap also shows up: `LocalDate.of(2026, 1, 1).plus(Duration.ofDays(1))` compiles as well, and throws the same `UnsupportedTemporalTypeException: Unsupported unit: Seconds`.

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

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

Open OCP Java SE 17

Other topics in this pack