DateTime in Java
By the Syncfusion DevTutorials team · Last updated
Handle dates and times with LocalDate, LocalTime, LocalDateTime and ZonedDateTime, format and parse them, do date arithmetic, and measure gaps with Duration and Period.
Think about a train ticket.
It shows a date, such as 15 August 2026. It shows a departure time, such as 09:30. Sometimes it also names a time zone, because 09:30 in Chennai is not 09:30 in London.
A program needs all of these ideas too. Java's date and time classes give each idea its own type, so you never mix them up.
In simple words: Java has separate classes for a date, a time, a date with a time, and a date with a time in a time zone.
What You Will Learn
In this lesson, you will learn:
- Which date and time class to use for which job.
- How to create dates and times with
LocalDate,LocalTimeandLocalDateTime. - How
ZonedDateTimehandles time zones. - How to format dates as text and parse text into dates with
DateTimeFormatter. - How to add days, months and years.
- How to measure gaps with
DurationandPeriod. - How to compare dates and read the current date and time.
Start With a Working Example
Press Run.
A due date, 14 days after borrowing a book
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate borrowed = LocalDate.of(2026, 8, 25);
LocalDate due = borrowed.plusDays(14);
System.out.println("Borrowed: " + borrowed);
System.out.println("Due back: " + due);
System.out.println("Due on a: " + due.getDayOfWeek());
}
}
Expected output:
Borrowed: 2026-08-25
Due back: 2026-09-08
Due on a: TUESDAY
plusDays(14) worked out the new date, even though it moved into a new month. Java also knows which day of the week that date falls on.
Try This
Change 14 to 30. Java moves into the next month by itself and gives the new weekday.
Introduction to Date and Time
Dates are harder than they look:
- Months have 28, 29, 30 or 31 days.
- Leap years add an extra day to February.
- The same moment has a different clock time in each country.
- People write dates in many styles:
25/08/2026,08-25-2026or25 Aug 2026.
Doing this maths by hand is a common source of bugs. Java's java.time package does it for you.
The Main Classes
| Class | Holds | Example value |
|---|---|---|
LocalDate | A date only | 2026-08-25 |
LocalTime | A time only | 09:30 |
LocalDateTime | A date and a time | 2026-08-25T09:30 |
ZonedDateTime | A date, a time and a time zone | 2026-08-25T09:30+05:30[Asia/Kolkata] |
Duration | A gap in hours, minutes and seconds | PT2H30M |
Period | A gap in years, months and days | P1Y2M |
DateTimeFormatter | A pattern for turning dates into text and back | dd/MM/yyyy |
"Local" means no time zone. A LocalDate is just a calendar date, like a birthday.
All of these classes are immutable, just like String. A method like plusDays() returns a new object. The original never changes.
You import them from java.time:
import java.time.LocalDate;
Older Java code uses java.util.Date and Calendar. Those classes are hard to use and easy to get wrong. For new code, always use the java.time classes in this lesson.
LocalDate
A LocalDate holds a year, a month and a day. It has no time and no time zone.
Use it for birthdays, due dates and holidays.
You create one with LocalDate.of(year, month, day). Months are numbered 1 to 12, so August is 8.
Create a date and read its parts
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate birthday = LocalDate.of(2008, 3, 14);
System.out.println("Date: " + birthday);
System.out.println("Year: " + birthday.getYear());
System.out.println("Month: " + birthday.getMonth());
System.out.println("Month number: " + birthday.getMonthValue());
System.out.println("Day: " + birthday.getDayOfMonth());
System.out.println("Weekday: " + birthday.getDayOfWeek());
System.out.println("Leap year? " + birthday.isLeapYear());
}
}
Expected output:
Date: 2008-03-14
Year: 2008
Month: MARCH
Month number: 3
Day: 14
Weekday: FRIDAY
Leap year? true
A LocalDate prints in the standard year-month-day form, called ISO format.
getMonth() returns the month's name. getMonthValue() returns its number.
LocalTime
A LocalTime holds a time of day: hours, minutes, seconds and parts of a second. It has no date.
Use it for opening hours, alarm times and class schedules.
A time of day, with no date
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalTime opens = LocalTime.of(9, 30);
LocalTime closes = LocalTime.of(18, 0);
LocalTime lunch = LocalTime.of(13, 15, 45);
System.out.println("Opens: " + opens);
System.out.println("Closes: " + closes);
System.out.println("Lunch: " + lunch);
System.out.println("Closing hour: " + closes.getHour());
System.out.println("Last order: " + closes.minusMinutes(30));
}
}
Expected output:
Opens: 09:30
Closes: 18:00
Lunch: 13:15:45
Closing hour: 18
Last order: 17:30
Hours use the 24-hour clock, so 6 pm is 18.
Seconds only show when they are not zero.
LocalDateTime
A LocalDateTime joins a date and a time together. It still has no time zone.
Use it for appointments and events that happen in one place.
A date and a time together
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalDateTime exam = LocalDateTime.of(2026, 11, 20, 10, 0);
System.out.println("Exam: " + exam);
LocalDate day = LocalDate.of(2026, 12, 31);
LocalTime time = LocalTime.of(23, 59);
LocalDateTime newYearsEve = LocalDateTime.of(day, time);
System.out.println("Countdown: " + newYearsEve);
System.out.println("Date part: " + exam.toLocalDate());
System.out.println("Time part: " + exam.toLocalTime());
}
}
Expected output:
Exam: 2026-11-20T10:00
Countdown: 2026-12-31T23:59
Date part: 2026-11-20
Time part: 10:00
The T separates the date from the time. It is part of the standard format.
You can build a LocalDateTime from numbers, or from a LocalDate and a LocalTime. You can also split it back into the two parts.
ZonedDateTime
A ZonedDateTime is a date and time in a particular time zone.
A time zone is a region that shares the same clock time. India uses Asia/Kolkata, which is 5 hours and 30 minutes ahead of UTC. UTC is the world's reference clock.
Use ZonedDateTime when people in different countries are involved: online meetings, flight times and global events.
Time zones are named with a ZoneId, such as ZoneId.of("Asia/Kolkata").
One meeting, three local clock times
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2026, 9, 15, 18, 0);
ZonedDateTime inIndia = start.atZone(ZoneId.of("Asia/Kolkata"));
ZonedDateTime inLondon = inIndia.withZoneSameInstant(ZoneId.of("Europe/London"));
ZonedDateTime inTokyo = inIndia.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("India: " + inIndia.toLocalTime() + " " + inIndia.getOffset());
System.out.println("London: " + inLondon.toLocalTime() + " " + inLondon.getOffset());
System.out.println("Tokyo: " + inTokyo.toLocalTime() + " " + inTokyo.getOffset());
}
}
Expected output:
India: 18:00 +05:30
London: 13:30 +01:00
Tokyo: 21:30 +09:00
withZoneSameInstant keeps the same moment but shows it on another zone's clock. When it is 6 pm in India, it is 1:30 pm in London and 9:30 pm in Tokyo.
The offset, such as +05:30, is how far that zone is ahead of UTC on that date. London shows +01:00 here because it uses summer time in September.
Time zone rules change over time, for example when a country starts or stops using summer time. Java keeps a database of these rules, so always use zone names like Europe/London rather than fixed offsets like +01:00.
DateTimeFormatter
The standard format, 2026-08-25, is good for computers. People often want something else, like 25/08/2026 or 25 Aug 2026.
A DateTimeFormatter describes a pattern. It turns dates into text in that pattern, and turns text in that pattern back into dates.
You create one with DateTimeFormatter.ofPattern("..."), using these letters:
| Letter(s) | Meaning | Example |
|---|---|---|
yyyy | Four-digit year | 2026 |
MM | Month number, two digits | 08 |
MMM | Short month name | Aug |
MMMM | Full month name | August |
dd | Day of the month, two digits | 05 |
EEEE | Full weekday name | Tuesday |
HH | Hour, 24-hour clock | 18 |
hh | Hour, 12-hour clock | 06 |
mm | Minutes | 45 |
a | AM or PM | PM |
Capital MM means months. Small mm means minutes. Mixing them up is a very common bug, and it gives dates that look almost right.
Date Formatting
Formatting turns a date or time into text. You call format() on the date and pass in the formatter.
One date, written in four styles
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2026, 8, 5);
LocalDateTime meeting = LocalDateTime.of(2026, 8, 5, 18, 45);
DateTimeFormatter indian = DateTimeFormatter.ofPattern("dd/MM/yyyy");
DateTimeFormatter us = DateTimeFormatter.ofPattern("MM-dd-yyyy");
DateTimeFormatter longStyle = DateTimeFormatter.ofPattern("dd MMM yyyy");
DateTimeFormatter clock = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
System.out.println(date.format(indian));
System.out.println(date.format(us));
System.out.println(date.format(longStyle));
System.out.println(meeting.format(clock));
}
}
Expected output:
05/08/2026
08-05-2026
05 Aug 2026
05/08/2026 18:45
The date is the same in every line. Only the pattern changes how it is written.
05/08/2026 and 08-05-2026 show why patterns matter. In India the first means 5 August. In the US, the second does.
Date Parsing
Parsing is the opposite of formatting. It turns text into a date or time object.
If the text is already in the standard ISO form, parse() needs no formatter. For any other style, pass a formatter whose pattern matches the text.
Turn text into real date objects
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
LocalDate iso = LocalDate.parse("2026-12-25");
System.out.println("ISO text: " + iso.getDayOfWeek());
DateTimeFormatter indian = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate fromForm = LocalDate.parse("15/08/2026", indian);
System.out.println("Form text: " + fromForm);
System.out.println("Next day: " + fromForm.plusDays(1));
LocalTime alarm = LocalTime.parse("06:45");
System.out.println("Alarm: " + alarm);
}
}
Expected output:
ISO text: FRIDAY
Form text: 2026-08-15
Next day: 2026-08-16
Alarm: 06:45
Once text becomes a LocalDate, you can do date maths with it.
If the text does not match the pattern, such as "2026/15/08", the program stops with a DateTimeParseException.
Date Arithmetic
Date arithmetic means adding or taking away time. Java handles month lengths and leap years for you.
Every method returns a new date, because dates are immutable.
plusDays()
plusDays(n) adds n days. It moves into the next month or year when needed.
plusMonths()
plusMonths(n) adds n months. If the day does not exist in the new month, Java uses that month's last day.
plusYears()
plusYears(n) adds n years. 29 February becomes 28 February in a year that is not a leap year.
Each has a matching minus method: minusDays, minusMonths and minusYears. Times have plusHours and plusMinutes as well.
Add days, months and years
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate start = LocalDate.of(2026, 1, 31);
System.out.println("Start: " + start);
System.out.println("+ 10 days: " + start.plusDays(10));
System.out.println("+ 1 month: " + start.plusMonths(1));
System.out.println("+ 2 years: " + start.plusYears(2));
System.out.println("- 1 week: " + start.minusWeeks(1));
LocalDate leapDay = LocalDate.of(2028, 2, 29);
System.out.println("Leap + 1 yr: " + leapDay.plusYears(1));
System.out.println("Start again: " + start);
}
}
Expected output:
Start: 2026-01-31
+ 10 days: 2026-02-10
+ 1 month: 2026-02-28
+ 2 years: 2028-01-31
- 1 week: 2026-01-24
Leap + 1 yr: 2029-02-28
Start again: 2026-01-31
31 January plus one month would be 31 February, which does not exist. So Java uses 28 February, the last day of that month.
The last line proves start never changed. Each method returned a new date.
Duration
A Duration measures a gap in hours, minutes and seconds. Use it with times and date-times.
Duration.between(start, end) measures the gap between two moments.
Measure a gap in hours and minutes
import java.time.Duration;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalTime checkIn = LocalTime.of(9, 15);
LocalTime checkOut = LocalTime.of(17, 45);
Duration worked = Duration.between(checkIn, checkOut);
System.out.println("Worked: " + worked);
System.out.println("Total minutes: " + worked.toMinutes());
long hours = worked.toHours();
long minutes = worked.toMinutes() % 60;
System.out.println("Hours: " + hours + ", minutes: " + minutes);
Duration movie = Duration.ofMinutes(165);
System.out.println("Movie ends at: " + LocalTime.of(19, 0).plus(movie));
}
}
Expected output:
Worked: PT8H30M
Total minutes: 510
Hours: 8, minutes: 30
Movie ends at: 21:45
PT8H30M is the standard way to write a duration. Read it as "Period of Time: 8 Hours, 30 Minutes".
toMinutes() gives the whole gap in minutes. toHours() gives the full hours. toMinutes() % 60 gives only the minutes left over after the full hours.
Period
A Period measures a gap in years, months and days. Use it with dates.
Period.between(start, end) measures the calendar gap between two dates. This is how you work out someone's age.
Measure a gap in years, months and days
import java.time.LocalDate;
import java.time.Period;
public class Main {
public static void main(String[] args) {
LocalDate born = LocalDate.of(2008, 3, 14);
LocalDate today = LocalDate.of(2026, 10, 7);
Period age = Period.between(born, today);
System.out.println("Period: " + age);
System.out.println("Age: " + age.getYears() + " years, "
+ age.getMonths() + " months, " + age.getDays() + " days");
Period trial = Period.ofMonths(3);
System.out.println("Trial ends: " + LocalDate.of(2026, 10, 7).plus(trial));
}
}
Expected output:
Period: P18Y6M23D
Age: 18 years, 6 months, 23 days
Trial ends: 2027-01-07
P18Y6M23D reads as "Period: 18 Years, 6 Months, 23 Days".
Duration vs Period
Duration | Period | |
|---|---|---|
| Measures in | Hours, minutes, seconds | Years, months, days |
| Works with | LocalTime, LocalDateTime | LocalDate |
| Example use | Time spent on a task | A person's age |
| Text form | PT2H30M | P1Y2M10D |
Easy Way to Remember: Duration is for the dial on a clock. Period is for pages on a calendar.
Date Comparison
You compare dates with three methods:
isBefore(other)is true if this date comes first.isAfter(other)is true if this date comes later.isEqual(other)is true if they are the same date.
equals() works too. compareTo() gives a negative number, zero or a positive number, like it does for strings.
Check whether a payment is late
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate due = LocalDate.of(2026, 10, 10);
LocalDate paidOn = LocalDate.of(2026, 10, 12);
System.out.println("Paid before due date? " + paidOn.isBefore(due));
System.out.println("Paid after due date? " + paidOn.isAfter(due));
System.out.println("Paid on the due date? " + paidOn.isEqual(due));
if (paidOn.isAfter(due)) {
System.out.println("Late fee applies.");
} else {
System.out.println("No late fee.");
}
}
}
Expected output:
Paid before due date? false
Paid after due date? true
Paid on the due date? false
Late fee applies.
Do not compare dates with < or >. Those operators only work on numbers. Dates are objects, so you use their methods.
Current Date and Time
now() gives the current date or time, read from the computer's clock.
Every class in this lesson has it: LocalDate.now(), LocalTime.now(), LocalDateTime.now() and ZonedDateTime.now().
Read the clock right now
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDateTime rightNow = LocalDateTime.now();
DateTimeFormatter style = DateTimeFormatter.ofPattern("dd MMM yyyy, HH:mm");
System.out.println("Today: " + today);
System.out.println("Now: " + rightNow.format(style));
System.out.println("Days until New Year: "
+ (today.lengthOfYear() - today.getDayOfYear() + 1));
}
}
The output depends on when the program runs. It will look something like this:
Today: 2026-10-07
Now: 07 Oct 2026, 14:32
Days until New Year: 86
If you run it twice a minute apart, the time changes.
Use now() for real program features, like timestamps and greetings. In examples and tests, use fixed dates with of() instead. A fixed date gives the same answer every time, so you can check it.
Common mistakes
The following mistakes are common when working with dates and times. Each row shows what you see, why it happens and how to fix it.
| Symptom | Cause | Fix |
|---|---|---|
A date stays the same after plusDays | The new date was not stored | Assign it back: d = d.plusDays(1); |
| Minutes appear where the month should be | mm was used instead of MM | Use MM for months |
DateTimeParseException | The text does not match the pattern | Pass a formatter with the matching pattern |
DateTimeException: Invalid date | The date does not exist | Check the day for that month |
UnsupportedTemporalTypeException | Duration was used on LocalDate values | Use Period for dates |
bad operand types for binary operator '<' | < was used on dates | Use isBefore or isAfter |
What to Remember
- Use
LocalDatefor dates,LocalTimefor times,LocalDateTimefor both, andZonedDateTimewhen time zones matter. - Create values with
of(), and read the clock withnow(). DateTimeFormatter.ofPatternformats dates as text and parses text back.MMis months andmmis minutes.plusDays,plusMonthsandplusYearsreturn new dates and handle month lengths and leap years.Durationmeasures clock time.Periodmeasures calendar time.- Compare dates with
isBefore,isAfterandisEqual, never with<or>.
Next: Classes and Objects