Java's java.time package separates calendar dates, local clock times, time-zone-aware values, and timeline instants. That separation prevents a common mistake: treating every value that looks like a date as the same kind of information. A birthday needs LocalDate; an event occurring worldwide needs an Instant or a zoned representation. The API is available from Java 8, and its principal classes are immutable. The examples use fixed values so the output does not depend on today's date or the machine's time zone.
Choose the type that matches the question
LocalDate stores a year, month, and day without a time or zone. LocalTime stores a clock time without a date. LocalDateTime combines those local parts but still does not identify a unique moment worldwide. Instant represents a point on the UTC timeline. ZonedDateTime combines a local date-time with a ZoneId and an offset. Ask whether the application is storing a calendar fact, a local appointment, or a definite moment before choosing the class.
Create and parse valid values
Factory methods such as LocalDate.of reject invalid dates, including a nonexistent day for the selected month. LocalDate.parse uses the ISO year-month-day form by default. A DateTimeFormatter supports other documented representations. Parsing failure produces DateTimeParseException rather than a partially valid date. Catch that error at an input boundary when a user can correct it. Do not silently substitute the current date, because that changes the meaning of the supplied data.
Perform arithmetic without mutation
Calling plusDays, minusMonths, or withDayOfMonth returns a new object; it does not edit the original. Assign the returned value when you need the adjusted date. Date arithmetic understands month lengths and leap years. Moving January thirty-first one month forward resolves to the last valid day of February. This behavior is useful, but recurring billing rules may require a more specific policy, such as always retaining the original intended day.
Distinguish Period from Duration
Period describes date-based amounts in years, months, and days. Duration describes time-based amounts in seconds and nanoseconds. A one-month Period is not a fixed number of hours because months differ in length. Likewise, a local calendar day across a daylight-saving transition can differ from twenty-four elapsed hours. Use Period for a calendar schedule and Duration for elapsed time. State that distinction when storing intervals or comparing application deadlines.
Convert a known instant between zones
An Instant identifies the same moment regardless of its displayed local time. atZone applies a region's rules to display that moment locally. ZoneId values such as Europe/Paris represent historical and daylight-saving rules, while a fixed ZoneOffset is simply an offset. Never assume a region has the same offset all year. The example uses a winter instant with known offsets and converts it to Paris and Tokyo without changing the underlying event.
Format values and make time testable
DateTimeFormatter can format a value for display and parse input using a compatible pattern. Month uses uppercase M; lowercase m means minute. Prefer explicit Locale when names of months or days matter. For code that depends on now, accept a Clock and use a fixed clock in tests. This keeps a deadline test reliable at midnight and in different environments, unlike hard-coding assumptions about the machine's current date.
Practice tasks and checks
Create a booking arriving on December thirtieth and departing three days later. Predict the year as well as the month and day before running plusDays. Add a second booking starting on January thirty-first and use plusMonths to observe end-of-month adjustment. Explain whether that policy matches your imagined booking rules. Next, display one fixed Instant in two ZoneIds without storing either local display as the authoritative event identity. For renewal testing, move the fixed Clock to the day before a leap day and verify a two-day deadline. Avoid LocalDate.now without the supplied clock, because that would make the exercise's outcome depend on when someone runs it.
Java Summary
- Choose date, local time, zoned time, or instant according to the stored meaning.
- Date-time arithmetic returns new immutable values.
- A fixed Clock makes time-dependent tests reproducible.
- Continue with date-time foundations when these examples are clear.
Java Examples
Each example shows the code, the output it produces and what each part does.
Adjust a calendar date
Save this program as BookingDates.java. Compile it with javac BookingDates.java and run it with java BookingDates.
Expected output:
The initial value is February twenty-eighth in a leap year. Adding two days passes February twenty-ninth and reaches March first. arrival remains unchanged because LocalDate is immutable. isBefore compares the dates and returns true. This example counts calendar days, not hours between zoned timestamps, so no daylight-saving rules participate in the calculation.
import java.time.LocalDate;
public class BookingDates {
public static void main(String[] args) {
LocalDate arrival = LocalDate.of(2024, 2, 28);
LocalDate departure = arrival.plusDays(2);
System.out.println(arrival);
System.out.println(departure);
System.out.println(arrival.isBefore(departure));
}
}2024-02-28
2024-03-01
trueDisplay one instant in two regions
Save this program as EventZones.java. Compile it with javac EventZones.java and run it with java EventZones.
Expected output:
The Z in the parsed text means UTC. Paris is one hour ahead for this winter date, while Tokyo is nine hours ahead, giving the two displayed clock times. Both values describe the same start instant. Calling toLocalTime deliberately removes the date and zone for this display; retain the ZonedDateTime when those details are needed for storage, comparison, or user-facing context.
import java.time.Instant;
import java.time.ZoneId;
public class EventZones {
public static void main(String[] args) {
Instant start = Instant.parse("2024-01-15T12:00:00Z");
System.out.println(start.atZone(ZoneId.of("Europe/Paris")).toLocalTime());
System.out.println(start.atZone(ZoneId.of("Asia/Tokyo")).toLocalTime());
}
}13:00
21:00Use a fixed clock for a reproducible result
Save this program as RenewalClock.java. Compile it with javac RenewalClock.java and run it with java RenewalClock.
Expected output:
Clock.fixed always supplies the chosen instant with the specified zone. LocalDate.now(clock) therefore resolves to May tenth rather than the date on the computer running the program. Adding seven days gives May seventeenth. Passing a Clock into a renewal service lets production code use a real clock while tests exercise exact dates, including month-end and leap-year cases, without changing the service's calculation.
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
public class RenewalClock {
public static void main(String[] args) {
Clock clock = Clock.fixed(
Instant.parse("2024-05-10T08:00:00Z"), ZoneOffset.UTC);
LocalDate today = LocalDate.now(clock);
System.out.println(today.plusDays(7));
}
}2024-05-17Java FAQ
Does LocalDateTime include a time zone?
No. It stores local calendar and clock fields. To identify an instant, combine it with an appropriate zone or offset and decide how the application handles daylight-saving gaps or overlaps.
Should a birthday be stored as an Instant?
Usually not. A birthday is a calendar date, so LocalDate expresses it directly. Turning it into an instant introduces a time and zone that may move the displayed date for users elsewhere.
How do I find the last day of a month?
Use a temporal adjuster: date.with(TemporalAdjusters.lastDayOfMonth()), which gives 29 February for a date in February 2028. YearMonth.of(2026, 2).atEndOfMonth() gives the same kind of answer when you only have a year and month.
How do I get the day of the week for a date?
Call getDayOfWeek(), which returns a DayOfWeek enum such as SUNDAY. Compare it with ==, use it in a switch, or display it in a language of your choice with getDisplayName(TextStyle.FULL, Locale.UK).
How do I test code that uses the current date or time?
Don't call LocalDate.now() directly deep inside your logic. Pass in a Clock, or the date itself, and use Clock.systemDefaultZone() in production. Tests can then use Clock.fixed(...), so "today" is the same every time the test runs.
Java Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Which type fits an ordinary birthday?
What happens to arrival after arrival.plusDays(2)?
Java Quiz
2 questions to check what you learned.
Which amount is suitable for a three-month calendar interval?
- Period
- Duration.ofHours(2160)
- ZoneOffset
Why inject a Clock into date-dependent code?
- Tests can control the current instant and zone
- It makes all dates mutable
- It removes leap years