🔴 The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
// CAPTURED — OpenJDK 25 Temurin: LocalDate.parse("2026-08-22").get(ChronoField.HOUR_OF_DAY)
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
at java.base/java.time.LocalDate.get0(LocalDate.java:700)
at java.base/java.time.LocalDate.get(LocalDate.java:643)⚡ Quick Fix Works 80% of the time
Widen to a type that owns time before reading it: date.atStartOfDay() or date.atTime(hour, minute).
LocalDate d = LocalDate.parse("2026-08-22");
int hour = d.atStartOfDay().get(ChronoField.HOUR_OF_DAY); // 0
LocalDateTime meeting = d.atTime(14, 30);
int h2 = meeting.getHour(); // 14🧠 Why this Happens
Tap to expand the deep technical explanation
JSR-310 models fields as CAPABILITIES: each TemporalAccessor answers isSupported(field) based on what it physically stores. LocalDate derives everything from a single epoch-day value — year, month, day — but HOUR_OF_DAY (range 0-23) simply has no storage slot inside it, so get() refuses with this exception naming the exact field. The design deliberately separates three failures: capability gaps throw UnsupportedTemporalTypeException (wrong TYPE for the question), impossible values throw DateTimeException subclasses (right type, bad data), and text mismatches throw DateTimeParseException (parse layer). Java's old java.util.Date blurred all three into one mutable blob; the new hierarchy makes you pick the right question for the right object.
The HITEC City Parking Spot Analogy:
Asking a wall calendar what time the meeting starts: it holds dates only — there is no clock hand anywhere on that page.
🔁 How to Reproduce Confirm this is your error
LocalDate.parse("2026-08-22").get(ChronoField.HOUR_OF_DAY). (Lab capture: OpenJDK 25.)
🛠️ Solutions (5 Ways to Fix)
Widen the temporal type before reading time fields
👉 Use this when/if you hold a LocalDate/LocalTime where business logic legitimately needs the combined view.
atStartOfDay(), atTime(h, m), or atDate(d) compose the missing half explicitly — the resulting LocalDateTime supports both date and time fields, so get()/getHour() work without exceptions and intent becomes visible in code.
LocalDateTime stamp = orderDate.atStartOfDay();
int hour = stamp.getHour(); // always legal now
ZonedDateTime zoned = stamp.atZone(ZoneId.of("Asia/Kolkata"));Guard polymorphic code with isSupported(field)
👉 Use this when/if generic utilities accept arbitrary TemporalAccessor instances (serializers, UI binders, formatters).
Code that cannot know the concrete type should ask first: isSupported(field) returns false cleanly instead of throwing mid-render. Combine with a sensible default or an explicit 'not applicable' marker in output.
static String show(TemporalAccessor t, ChronoField f) {
return t.isSupported(f)
? String.valueOf(t.get(f))
: "n/a"; // LocalDate + HOUR_OF_DAY -> "n/a"
}Split date-only vs datetime DTO fields
👉 Use this when/if one lossy type keeps attracting wrong-field reads across the codebase.
Model birthdays and deadlines as LocalDate, timestamps as Instant or LocalDateTime. Distinct types make the compiler prevent this exception entirely — the bug becomes unrepresentable rather than guarded.
record Subscription(LocalDate start, Instant renewedAt) { }
// nobody can call start.get(HOUR_OF_DAY) — type says date-onlyFix formatter-side traps: parse into the right type first
👉 Use this when/if the exception fires while FORMATTING because the pattern contains time sections.
A pattern like yyyy-MM-dd HH:mm thrown at a parsed LocalDate fails when the formatter queries HOUR_OF_DAY during formatting. Parse with DateTimeFormatter.toLocalDate() OR include matching pattern sections — pattern and type must agree.
LocalDate d = LocalDate.parse("2026-08-22");
d.format(DateTimeFormatter.ISO_LOCAL_DATE); // OK
d.format(DateTimeFormatter.ISO_DATE_TIME); // throws here!
d.atStartOfDay().format(DateTimeFormatter.ISO_DATE_TIME); // fixedConvert zone-aware values through ZonedDateTime
👉 Use this when/if business timezone semantics matter and naive widening loses meaning.
atZone(zoneId) produces ZonedDateTime, supporting offset/zone fields AND instant math — the right widening when 'what hour was it in Hyderabad' is the actual question rather than a bare clock reading.
ZonedDateTime ist = utcInstant.atZone(ZoneId.of("Asia/Kolkata"));
int localHour = ist.getHour(); // zone-adjusted, supported, correct📋 Version Notes
JSR-310 introduces the capability-based field model behind this exception.
Unchanged; most occurrences stem from Date→LocalDate migrations dropping time halves.
Same; Jackson java.time modules surface it in REST payloads.
Unchanged — check isSupported before get() in generic code.
🛡️ How to Prevent This Next Time
Choose the narrowest sufficient temporal type in APIs, keep formatters paired with the types they target, run migration reviews when replacing java.util.Date (the classic regression source), and centralize temporal conversions in one utility class.