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.
| Class | Holds | Example value | Use it for |
|---|---|---|---|
| LocalDate | date only | 2026-10-15 | birthdays, due dates, holidays |
| LocalTime | time only | 10:30 | opening hours, daily alarms |
| LocalDateTime | date and time, no zone | 2026-10-15T10:30 | a meeting time inside one known time zone |
| ZonedDateTime | date, time and zone region | 2026-10-15T10:30-04:00[America/New_York] | scheduling across zones, daylight saving rules |
| OffsetDateTime | date, time and fixed UTC offset | 2026-10-15T10:30-04:00 | REST payloads, database columns, logs |
| Instant | a point on the UTC timeline | 2026-10-15T14:30:00Z | timestamps, event times, audit columns |
| Duration | an amount in hours, minutes and seconds | PT1H45M | timeouts, elapsed time |
| Period | an amount in years, months and days | P1M15D | age, 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.
- Java LocalDate class covers the class used for most business dates.
- Java LocalDateTime class adds the time of day.
- Java ZonedDateTime class adds the time zone.
- Java DateTimeFormatter explains the pattern letters used for parsing and formatting.
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
- Get Current Date and Time
- Get Current Timestamp
- Get Elapsed Time since Midnight
- Getting the Start and the End of a Day
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().
- Comparing Dates in Java covers both the legacy and the new classes.
- Compare LocalDate instances
- Compare LocalDateTime instances
- Compare ZonedDateTime instances explains why equals() and isEqual() give different answers.
- Get Object with Max Date From a List uses a Stream to find the latest date.
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.
- Convert between LocalDateTime and ZonedDateTime
- Convert between LocalDate and ZonedDateTime
- Convert between LocalDateTime and LocalDate
- Convert Instant to LocalDateTime, LocalDate or LocalTime
- Convert Instant to ZonedDateTime
- Convert java.util.Date to LocalDate
- Convert java.util.Date to LocalDateTime
- Convert LocalDate to java.sql.Date for older JDBC code.
- Convert between Month Name and Month Number
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]
- Differences Between ZonedDateTime and OffsetDateTime
- List of Zone Ids and Zone Offsets
- Converting Date and Time between Timezones
- Convert a Date to EST/EDT Timezone
- How to Set the JVM Timezone
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.
- Parse a String to Date in Java 8
- Convert String to LocalDate
- Convert String to LocalDateTime
- Convert String to ZonedDateTime
- Convert String to UTC Date Time
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'
- Java Date Format Validation
- Strict, Smart and Lenient Date Resolution with ResolverStyle.
- RegEx for Matching a Date Pattern
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.
- Format Dates to String in Java
- Format LocalDate
- Format LocalDateTime
- Format ZonedDateTime
- Format Time in 12 Hours Pattern with AM and PM.
- Date Format with Day Period prints “in the morning” or “at night”.
- Format a Milliseconds Duration to Hours, Minutes and Seconds
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”.
- Add or Subtract Days, Months and Years
- Add or Subtract Hours, Minutes and Seconds
- Get Next and Previous Date
- Add or Subtract Business Days
- Get First and Last Day of Week, Month or Year
- The DayOfWeek enum covers its methods, day names and arithmetic.
- Get Quarter from Date, Quarter Start and End Date
- Java TemporalAdjusters
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.
- Difference Between Two Dates
- Count Number of Days Between Two Dates
- Calculate Number of Weeks between Two Dates
- Calculate Business Days between Two Dates
- Get All Dates Between Two Dates
- Split a Date-time Range into Equal Intervals
- Calculate Age from Date of Birth
- Java Period
- Measure Elapsed Time with System.nanoTime(), Instant and Duration.
- Java StopWatch
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”.
- Get Year, Month and Day from Date
- Finding the Day of Week for a Date
- Displaying the Name of the Day of the Week
- Check if a Date is a Weekend
- Check if a Year is a Leap Year
- Java TemporalQuery for custom questions such as “is this date in a holiday season?”
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.
- Get Current User Locale
- Java Locale Class
- Location Based Date Time Formatting
- Location Based Currency Formatting
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.
- Jackson Error: Java 8 date/time type not supported by default
- Hibernate Date and Time Mapping for LocalDateTime, Instant and the zoned types.
- Tracking Entity Creation and Update Timestamps in Spring Data JPA.
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 !!