Java Date and Time Tutorial with java.time Examples

How to work with dates and times in Java using java.time: a tested quick example, a table of which class to use when, and every date-time tutorial grouped by task.

Guides

In Java, we handle dates and times with the classes of the java.time package, which has one class for each kind of value, such as a date, a time of day, a moment in a time zone or an amount of time. The package came with Java 8, through the specification JSR-310, and replaced the old java.util.Date and Calendar classes, which caused many bugs.

We use java.time whenever our code stores, compares or shows a date, for example a due date on an invoice or a meeting time across two offices.

The following example covers the common tasks in five steps, with the result of each line as a comment.

// 1. Current date and simple arithmetic
LocalDate today = LocalDate.now();                         // 2026-10-04
LocalDate due = today.plusDays(30);                        // 2026-11-03
boolean before = today.isBefore(due);                      // true

// 2. Parse a string and format it back
LocalDateTime meeting = LocalDateTime.parse("2026-10-15T10:30");    // 2026-10-15T10:30
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a", Locale.US);
String text = meeting.format(fmt);                         // 15 Oct 2026, 10:30 AM

// 3. Time zones
ZonedDateTime inNewYork = meeting.atZone(ZoneId.of("America/New_York"));
                                                           // 2026-10-15T10:30-04:00[America/New_York]
ZonedDateTime inKolkata = inNewYork.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
                                                           // 2026-10-15T20:00+05:30[Asia/Kolkata]
Instant moment = inNewYork.toInstant();                    // 2026-10-15T14:30:00Z

// 4. Amounts of time
Duration length = Duration.between(LocalTime.of(10, 30), LocalTime.of(12, 15));   // PT1H45M
long minutes = length.toMinutes();                         // 105
Period age = Period.between(LocalDate.of(1990, 5, 20), today);                    // P36Y4M14D
int years = age.getYears();                                // 36

// 5. Bridge to legacy code
Date legacy = Date.from(moment);                           // java.util.Date for an old API
Instant back = legacy.toInstant();                         // 2026-10-15T14:30:00Z

Notice that LocalDate.now() reads today’s date, so the first lines and the age in step 4 show different values on the day we run the code. Also notice that plusDays() returns a new date and leaves today unchanged, because every java.time class is immutable (an object never changes after we create it).

Next, we see which class to pick for which value, and what to read first. After that, we group every date and time tutorial of the site by task, from getting the current date to dates in JSON and databases.

1. Which Date and Time Class to Use

Most date bugs come from picking the wrong class. A local class holds a date or time as we read it on a wall clock, without a time zone, so “10:30” alone does not say which city’s 10:30 we mean. A zoned class, an offset class or an Instant points to one exact moment on the timeline. An offset is a fixed shift from UTC, such as -04:00.

For example, a booking app stores a flight departure from New York as the LocalDateTime 2026-10-15T10:30. A user in Kolkata also sees 10:30, although the flight leaves at 20:00 Kolkata time. With a ZonedDateTime, the app can show both times correctly.

ClassHoldsExample valueUse it for
LocalDatedate only2026-10-15birthdays, due dates, holidays
LocalTimetime only10:30opening hours, daily alarms
LocalDateTimedate and time, no zone2026-10-15T10:30a meeting time inside one known time zone
ZonedDateTimedate, time and zone region2026-10-15T10:30-04:00[America/New_York]scheduling across zones, daylight saving rules
OffsetDateTimedate, time and fixed UTC offset2026-10-15T10:30-04:00REST payloads, database columns, logs
Instanta point on the UTC timeline2026-10-15T14:30:00Ztimestamps, event times, audit columns
Durationan amount in hours, minutes and secondsPT1H45Mtimeouts, elapsed time
Periodan amount in years, months and daysP1M15Dage, subscription length

New code uses java.time only. The old classes, such as java.util.Date and Calendar, create mutable objects, so any code holding a reference can change them. SimpleDateFormat is also not thread-safe, so two threads must not share one SimpleDateFormat object. We keep the old classes only where an old library or API still expects them, and at that boundary we convert with Date.from(instant) and date.toInstant().

2. What to Read First

When we are new to the API, the fastest path is the overview article first and then one article for each main class, in this order.

3. Get the Current Date and Time

The now() methods read the system clock, and by default they use the default time zone of the JVM. If we want a different zone, or a fixed time in tests, we pass a ZoneId or a Clock to now().

ZonedDateTime nowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));         // current time in Tokyo
Clock fixed = Clock.fixed(Instant.parse("2026-10-15T14:30:00Z"), ZoneOffset.UTC);
LocalDate testToday = LocalDate.now(fixed);                                     // 2026-10-15 in every test run

4. Compare Dates and Times

The java.time classes have methods such as isBefore() and isAfter(), and they also implement Comparable (the interface that defines the natural order of objects), so we can sort a list of dates with Collections.sort() or sorted().

5. Convert Between Date and Time Types

A conversion can add or drop information. Going from LocalDateTime to ZonedDateTime needs a zone, whereas going back drops the zone.

6. Work With Time Zones and Offsets

A ZoneId names a region, such as America/New_York, and knows the daylight saving rules of that region, whereas a ZoneOffset, such as -04:00, is only a fixed shift from UTC.

The difference shows up twice a year. Say a reminder app stores “9:00 every day in New York” as an OffsetDateTime with -04:00. After the clocks change on November 1, New York is at -05:00, so the reminder fires at 8:00. When we compute the next reminder with plusDays() on a ZonedDateTime with America/New_York, the reminder stays at 9:00.

ZonedDateTime zoned = ZonedDateTime.of(2026, 10, 31, 9, 0, 0, 0, ZoneId.of("America/New_York"));
OffsetDateTime offset = zoned.toOffsetDateTime();                          // 2026-10-31T09:00-04:00

ZonedDateTime nextZoned = zoned.plusDays(1);                               // 2026-11-01T09:00-05:00[America/New_York]
OffsetDateTime nextOffset = offset.plusDays(1);                            // 2026-11-01T09:00-04:00
ZonedDateTime nextInNewYork = nextOffset.atZoneSameInstant(ZoneId.of("America/New_York"));
                                                                           // 2026-11-01T08:00-05:00[America/New_York]

7. Parse a String to a Date

Parsing turns text such as “2026-10-15” into a date object. Text in the ISO format (year-month-day, as in “2026-10-15”) parses without a pattern, whereas any other layout needs a DateTimeFormatter with a matching pattern, or parse() throws DateTimeParseException.

Invalid input such as “2026-02-30” must fail with an error, because February has no 30th day. The ISO parser throws DateTimeParseException for this text. A formatter built with ofPattern(“yyyy-MM-dd”) uses the SMART resolver by default (a mode that moves an invalid day to the last valid day of the month), so the text becomes 2026-02-28 without an error. To reject such dates, we make the formatter strict with ResolverStyle.STRICT and write the year as uuuu. With yyyy (year of era), a strict formatter rejects every date, even valid ones, because the text has no era.

DateTimeFormatter smart = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate adjusted = LocalDate.parse("2026-02-30", smart);       // 2026-02-28 (no error)

DateTimeFormatter strict = DateTimeFormatter.ofPattern("uuuu-MM-dd")
    .withResolverStyle(ResolverStyle.STRICT);
LocalDate valid = LocalDate.parse("2026-02-28", strict);         // 2026-02-28
LocalDate invalid = LocalDate.parse("2026-02-30", strict);       // DateTimeParseException: Invalid date 'FEBRUARY 30'

8. Format a Date to a String

Formatting is the reverse of parsing, and the same DateTimeFormatter pattern turns a date object back into display text.

9. Add, Subtract and Adjust Dates

The plus…() and minus…() methods move a date by a fixed amount, such as 3 days, whereas a TemporalAdjuster moves a date to a day picked by a rule, such as “last day of the month”.

10. Difference Between Two Dates and Elapsed Time

The call ChronoUnit.DAYS.between() returns one number of days. When we need the gap in calendar terms, Period splits it into years, months and days, and when we need clock time, Duration measures it in hours, minutes and seconds.

For example, a gym membership runs from 2026-01-15 to 2026-03-01. ChronoUnit.DAYS.between() returns 45, and Period.between() returns P1M14D, i.e. one month and 14 days.

11. Read Parts of a Date

Getters such as getYear() and getDayOfWeek() read one field of a date, and the DayOfWeek and Month enums give display names, such as “Monday” or “October”.

12. Locales and Localized Formatting

A Locale is a language and region pair, such as English in the US. The locale decides the language and the regional style of month names and number formats.

13. More Class References

Each class reference covers one class with examples and lists its constructors, factory methods (static methods that create an object, such as LocalDate.of()) and common operations.

14. Dates in JSON and Databases

Frameworks need a little setup to read and write java.time values. Jackson 2 needs the JavaTimeModule, or it throws an InvalidDefinitionException for java.time types. Jackson 3, which Spring Boot 4 uses, supports java.time without any setup. JPA (the standard for mapping Java objects to tables) maps java.time fields to SQL date and timestamp columns.

15. Conclusion

Pick the class that matches the value first. We use LocalDate for a calendar date, LocalDateTime for a wall-clock time in one known zone, ZonedDateTime or OffsetDateTime when the zone matters, and Instant for timestamps.

After that choice, parsing, formatting and arithmetic work the same way in all java.time classes. Each section of this guide links the tutorials for one task, so we can jump to the one we need.

16. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.