Introduction
Time is central to almost every application — from banking transactions and flight bookings to logging frameworks and distributed systems. Developers often need to extract specific information from temporal objects: Is this date a weekend? Is this timestamp in daylight saving time? Is this the last day of the month?
The java.time
API (JSR-310) introduced in Java 8 provides a powerful interface called TemporalQuery
that allows developers to create custom queries for extracting specialized information from temporal objects like LocalDate
, LocalDateTime
, or ZonedDateTime
.
This tutorial dives deep into using TemporalQuery
for custom queries, exploring best practices, real-world examples, and advanced use cases.
Basics of Java Date & Time
Problems with Legacy APIs
java.util.Date
: Confusing, mutable, no easy querying capabilities.Calendar
: Verbose and error-prone for date extractions.SimpleDateFormat
: Parsing-only, not suitable for reusable queries.
The java.time
Package
Core classes:
LocalDate
,LocalTime
,LocalDateTime
— date/time without zone.Instant
— a timestamp in UTC.ZonedDateTime
— zone-aware date-time.Temporal
— abstraction implemented by all date-time classes.TemporalQuery
— interface for extracting information fromTemporal
objects.
Intermediate Concepts
Creating and Comparing Dates
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
System.out.println(today.isBefore(tomorrow)); // true
Formatting and Parsing
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate parsed = LocalDate.parse("28-08-2025", fmt);
System.out.println(parsed);
Time Zones
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
Advanced Date & Time Handling with TemporalQuery
What is TemporalQuery?
TemporalQuery<R>
is a functional interface that lets you define custom queries on Temporal
objects. It extracts information without modifying the temporal instance.
Built-in Queries
Java provides ready-to-use queries in TemporalQueries
:
TemporalQueries.zone()
→ ExtractsZoneId
.TemporalQueries.offset()
→ ExtractsZoneOffset
.TemporalQueries.localDate()
→ ExtractsLocalDate
.
Example:
ZonedDateTime now = ZonedDateTime.now();
ZoneId zone = now.query(TemporalQueries.zone());
System.out.println("Zone: " + zone);
Writing Custom TemporalQuery
Example 1: Weekend Checker
TemporalQuery<Boolean> isWeekend = temporal -> {
DayOfWeek day = DayOfWeek.from(temporal);
return day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY;
};
System.out.println(LocalDate.now().query(isWeekend));
Example 2: Last Day of Month
TemporalQuery<Boolean> isLastDayOfMonth = temporal -> {
LocalDate date = LocalDate.from(temporal);
return date.equals(date.with(TemporalAdjusters.lastDayOfMonth()));
};
System.out.println(LocalDate.now().query(isLastDayOfMonth));
Example 3: DST Check
TemporalQuery<Boolean> isDST = temporal -> {
ZonedDateTime zdt = ZonedDateTime.from(temporal);
return zdt.getZone().getRules().isDaylightSavings(zdt.toInstant());
};
System.out.println(ZonedDateTime.now().query(isDST));
Example 4: Business Hours Query
TemporalQuery<Boolean> isBusinessHour = temporal -> {
LocalTime time = LocalTime.from(temporal);
return !time.isBefore(LocalTime.of(9, 0)) && !time.isAfter(LocalTime.of(17, 0));
};
System.out.println(LocalTime.now().query(isBusinessHour));
Performance & Best Practices
- Use TemporalQuery for reusability instead of ad-hoc condition checks.
- Keep queries immutable and stateless for thread-safety.
- Leverage built-in queries (
TemporalQueries.zone()
, etc.) before writing custom ones. - Always fallback to ISO-based calculations for storage.
- Cache formatters when combining parsing with queries.
Framework Case Studies
REST APIs
- Example: Validate if a given date is a business day before accepting booking.
Database Integration
- Store as UTC, use queries for reporting.
Spring Boot
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate bookingDate;
Logging & Auditing
- Use queries to filter logs within certain hours or weekends.
Internationalization
- Combine
TemporalQuery
with locale-specific parsing for flexibility.
Real-World Scenarios
- Validate if user’s input falls on a weekend.
- Check if booking time is within business hours.
- Determine if an event occurs during DST.
- Identify last day of the month for billing cycles.
- Reusable queries for payroll or compliance systems.
📌 What's New in Java Versions?
- Java 8: Introduced
TemporalQuery
. - Java 9: Added more factory methods for parsing.
- Java 11:
datesUntil()
for ranges. - Java 16:
Instant.truncatedTo()
improvements. - Java 17: Pattern matching enhancements.
- Java 21: Virtual threads for scheduling, structured concurrency.
FAQ: Expert-Level Q&A
Q1. Difference between LocalDateTime
and ZonedDateTime
?
A: LocalDateTime
has no zone info, while ZonedDateTime
includes zone and offset.
Q2. Why is java.util.Date
considered broken?
A: Mutable, lacks time zone and query support, poor API design.
Q3. How to handle user input across locales?
A: Use DateTimeFormatter
with locale support.
Q4. Best way to calculate age in years, months, days?
A: Use Period.between(start, end)
.
Q5. How to handle leap seconds?
A: Java ignores leap seconds; rely on OS/NTP.
Q6. How to handle DST overlaps?
A: Use ZonedDateTime
with ZoneRules
.
Q7. When to use Instant
vs LocalDateTime
?
A: Instant
for machine timestamps, LocalDateTime
for user context.
Q8. How does immutability ensure thread-safety?
A: No shared mutable state; safe across threads.
Q9. Migration from legacy APIs?
A: Convert Date
→ Instant
→ use TemporalQuery
if needed.
Q10. Performance trade-offs?
A: Custom queries add abstraction but improve readability and reusability.
Conclusion & Key Takeaways
TemporalQuery
allows powerful, reusable ways to extract custom info from date-time objects.- Use built-in queries first, but write custom ones for business-specific rules.
- Keep queries stateless and thread-safe.
- Great for validation, compliance, and reusable checks in global applications.
By mastering
TemporalQuery
, you can write cleaner, reusable, and business-friendly date-time logic in Java applications.