# DateTime

Course: [Java](https://www.devtutorials.ai/learn/java) · Section: Reference Types
Source: https://www.devtutorials.ai/learn/java/reference-types/datetime

> 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:

1. Which date and time class to use for which job.
2. How to create dates and times with `LocalDate`, `LocalTime` and `LocalDateTime`.
3. How `ZonedDateTime` handles time zones.
4. How to format dates as text and parse text into dates with `DateTimeFormatter`.
5. How to add days, months and years.
6. How to measure gaps with `Duration` and `Period`.
7. How to compare dates and read the current date and time.

## Start With a Working Example

Press **Run**.

```java runnable title="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:

```text
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-2026` or `25 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`:

```text
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`.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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")`.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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.

```java runnable title="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:

```text
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:** **D**uration is for the **d**ial on a clock. **P**eriod is for **p**ages 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.

```java runnable title="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:

```text
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()`.

```java readonly title="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:

```text
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 `LocalDate` for dates, `LocalTime` for times, `LocalDateTime` for both, and `ZonedDateTime` when time zones matter.
- Create values with `of()`, and read the clock with `now()`.
- `DateTimeFormatter.ofPattern` formats dates as text and parses text back. `MM` is months and `mm` is minutes.
- `plusDays`, `plusMonths` and `plusYears` return new dates and handle month lengths and leap years.
- `Duration` measures clock time. `Period` measures calendar time.
- Compare dates with `isBefore`, `isAfter` and `isEqual`, never with `<` or `>`.

Next: Classes and Objects
