# Introduction to Java 8 Date and Time API

By Atta Ur Rehman Shah (https://attacomsian.com/about). Published Dec 19, 2019, updated Oct 13, 2022. Topics: Java.
Canonical URL: https://attacomsian.com/blog/java-new-date-time-api

> A comprehensive guide to learning about new Java 8 date and time APIs including LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, and more. 

Java 8 introduced new classes for date and time to resolve the long-standing issues of existing APIs: `java.util.Date` and `Java.util.Calendar`. These newly introduced immutable-value classes are easy-to-use, well-documented, and thread-safe.

In this article, we will **look at all Java 8 new date and time APIs** in detail with examples. Let us start with the issues in the existing `Date` and `Calendar` classes and how the newly introduced API addressed these shortcomings.

## Why Java 8 new Date & Time API?

Java 8 new date and time API was launched to address the following issues with the current date and time API:

1. **Thread-Safety** &mdash; Both `java.util.Date` and `java.util.Calendar` classes are not thread-safe. Therefore, developers have to deal with concurrency issues by writing additional codes. The new date and time APIs are immutable and thread-safe.
2. **Easier to Use & Understand** &mdash; The old APIs are poorly designed with little to no direct methods for basic date operations. The new date and time APIs introduced in Java 8 provide a consistent and easier-to-user ISO-centric interface for dealing with dates, times, durations, and periods. Tons of utility methods are included in the new API for simple date and time operations.
3. **Better Time Zone Handling** &mdash; Old APIs do not provide any direct way to handle different timezones. Developers were forced to write additional logic to deal with timezone issues. Java 8 new date and time API separated local and zoned date times handling into two categories. Thus, making it straightforward to handle different timezones without writing extra codes.

 ## Local Date & Time API
 
As a part of the local date and time API, Java 8 introduced `LocalDate`, `LocalTime`, and `LocalDateTime` classes. As their names suggest, these classes are intended to use for local date and time operations without timezones. You should use them when time zones are no longer required.
 
 ### `LocalDate` Class
 
The `LocalDate` class **represents a date without time** in the ISO-8601 format (yyyy-MM-dd). This class does not store or represent a time or time zone. Instead, it is a date description used for birthdays and anniversaries.
 
To **create an instance of the current local date** from the system clock, you can use the `LocalDate.now()` static method:
 
```java
LocalDate now = LocalDate.now();
```

To create an instance of `LocalDate` for a **specific day, month, and year**, you can use the `LocalDate.of()` method:

```java
LocalDate localDate = LocalDate.of(2019, 12, 20);
```

To convert a **string representation of ISO-8601 format to date**, you can use `LocalDate.parse()` method:

```java
LocalDate localDate = LocalDate.parse("2019-12-20");
```

The `LocalDate` class offers various **utility methods** that can be used to access different types of information. For example, the following code snippet shows how you can [get the current local date](https://attacomsian.com/blog/java-get-current-date-time) and then **add or subtract days**:

```java
LocalDate tomorrow = LocalDate.now().plusDays(1);
LocalDate yesterday = LocalDate.now().minusDays(1);
```

Just like days, you can also **add or minus months and years** to an instance of `LocalDate`:

```java
LocalDate lastMonth = LocalDate.now().minusMonths(1);
// OR        
LocalDate lastMonth = LocalDate.now().minus(1, ChronoUnit.MINUTES);
```

Here is another example that shows how you can **obtain the day of the week and the day of the month** from an instance of `LocalDate`:

```java
// get the day of the week
DayOfWeek day = LocalDate.now().getDayOfWeek();

// get the day of the month
int month = LocalDate.parse("2020-01-12").getDayOfMonth();
```

To check if the current year is **leap year**, you can do the following:

```java
boolean isLeap = LocalDate.now().isLeapYear();
```

You can also **compare two local dates** using `isBefore()` and `isAfter()` methods as shown below:

```java
// create local dates
LocalDate date1 = LocalDate.parse("2019-08-02");
LocalDate date2 = LocalDate.parse("2018-01-45");

// check if `date1` is before `date2`
boolean isBefore = date1.isBefore(date2);

// check if `date1` is after `date2`
boolean isAfter = date1.isAfter(date2);
```

You can use `LocalDate` to **obtain different date boundaries** such as the first day of the month, the start of the day (returns a `LocalDateTime` instance), and more. Here is an example:

```java
// get the start of the day
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();

// get the first day of the month
LocalDate firstDayOfMonth = LocalDate.parse("2019-12-18")
        .with(TemporalAdjusters.firstDayOfMonth());
```

### `LocalTime` Class

The `LocalTime` class **represents a time without date or timezone** information in the ISO-8601 calendar system. This class does not store or represent a date or time zone. Instead, it is a local time description, as seen on a wall clock.

Just like `LocalDate`, you can use **create an instance** of `LocalTime` from the system clock, parse a string, or specify time units manually:

```java
// use system clock
LocalTime now = LocalTime.now();

// parse a string
LocalTime parseTime = LocalTime.parse("02:08");

// specify hour-minute-second - 08:45:20 AM
LocalTime specificTime = LocalTime.of(8, 45, 20);
```

Similarly, you can use also **add or minus hours, minutes, seconds, or even nanoseconds** to a given `LocalTime` object:

```java
// past hour
LocalTime pastHour = LocalTime.now().minusHours(1);

// add minutes - can be replaced with `plusMinutes()`
LocalTime addMinutes = LocalTime.now().plus(15, ChronoUnit.MINUTES);
```

The `LocalTime` class provides various utility methods to **get different units of the time** like hours, minutes, seconds, or nanoseconds:

```java
int hour = LocalTime.now().getHour();
int minutes = LocalTime.now().getMinute();
int seconds = LocalTime.now().getSecond();
int nanoseconds = LocalTime.now().getNano();
```

You can also **compare two local times** to check if a given local time is after or before another local time, as shown below:

```java
// create local times
LocalTime time1 = LocalTime.parse("05:15");
LocalTime time2 = LocalTime.parse("21:00");

// is `time1` before `time2`?
boolean isBefore = time1.isBefore(time2);

// is `time1` after `time2`?
boolean isAfter = time1.isAfter(time2);
```

`LocalTime` also provides various **constants to get the maximum, minimum, or noon time** of a day, as shown below:

```java
// get max time (23:59:59.999999999)
LocalTime max = LocalTime.MAX;

// get min time (00:00)
LocalTime min = LocalTime.MIN;

// the time of noon (12:00)
LocalTime noon = LocalTime.NOON;

// time of midnight (00:00)
LocalTime midnight = LocalTime.MIDNIGHT;
```

### `LocalDateTime` Class

The `LocalDateTime` class is used to **represent both local date and time** without timezone information. It is a date description used for birthdays, combined with the local time, as seen on a wall clock.

`LocalDateTime` is the most commonly used class of Java 8 new data and time API for handling dates and times together. This class provides a range of utility methods for various date and time operations.

To **create a new instance** of `LocalDateTime`, you can either **use the system clock, parse a string, or manually define the date and time units** as shown below:

```java
// use system clock
LocalDateTime now = LocalDateTime.now();

// parse a string
LocalDateTime parseDT = LocalDateTime.parse("2019-08-02T15:20");

// specify data and time units
LocalDateTime specificDT = LocalDateTime.of(2019, Month.AUGUST, 2, 15, 20);
```

Just like `LocalDate` and `LocalTime`, you can **add or subtract different date and time units** from `LocalDateTime` as shown below:

```java
// yesterday
LocalDateTime yesterday = LocalDateTime.now().minusDays(1);

// subtract one year from a specific date and time
LocalDateTime lastYear = LocalDateTime.parse("2019-08-02T15:20")
        .minus(1, ChronoUnit.YEARS);

// add 4 hours to the current date and time
LocalDateTime nextHour = LocalDateTime.now().plusHours(4);
```

`LocalDateTime` also provides **getter methods to extract specific date and time units** similar to individual local date and time classes. The following example shows how you can get the month and hour units from an instance of `LocalDateTime`:

```java
Month month = LocalDateTime.now().getMonth();
int hour = LocalDateTime.now().getHour();
```

You can also [compare](https://attacomsian.com/blog/java-compare-dates) two `LocalDateTime` instances to **check if the given instance is after or before** the other one:

```java
// create local dates and times
LocalDateTime dt1 = LocalDateTime.parse("2019-08-08T05:10");
LocalDateTime dt2 = LocalDateTime.parse("2019-10-29T23:45");

// check if `dt1` is after `dt2`
boolean isAfter = dt1.isAfter(dt2);

// check if `dt1` is before `dt2`
boolean isBefore = dt1.isBefore(dt2);
```

## Zoned Date & Time API

The `ZonedDateTime` and `ZoneId` classes were added to Java 8 new date and time API to deal with situations where you can need the timezone information. 

### `ZoneId` Class

The `ZoneId` is an **identifier used to identify different timezones**. There are around 40 different timezones provided by `ZoneId`. Here is how you can create a zone for Paris and Karachi:

```java
ZoneId paris = ZoneId.of("Europe/Paris");
ZoneId karachi = ZoneId.of("Asia/Karachi");
```

To get all available zones, you can do the following:

```java
Set<String> zones = ZoneId.getAvailableZoneIds();
```

### `ZonedDateTime` Class

 The `ZonedDateTime` class **represents a date-time with a time-zone in the ISO-8601** format (e.g. *2019-12-20T10:15:30+05:00 Asia/Karachi*). It stores all date and time fields, to a precision of nanoseconds, and a timezone, with a zone offset used to handle ambiguous local date times.

To obtain the **current date-time from the system clock** in the default timezone, you can use `ZonedDateTime.now()` as shown below:

```java
ZonedDateTime now = ZonedDateTime.now();
```

An instance of `LocalDateTime` can also be **converted to a specific zone** to create a new `ZonedDateTime`:

```java
ZonedDateTime zonedDT = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Europe/Paris"));
```

The `ZonedDateTime` class also provides the `parse()` method to **create a zoned date and time instance of a string** as shown below:

```java
ZonedDateTime zonedDT = ZonedDateTime.parse("2019-12-20T10:15:30+05:00[Asia/Karachi]");
```

Just like `LocalDateTime`, you can also **add or subtract different date and time units** from `ZonedDateTime`:

```java
// add 2 months to a specific zoned date and time
ZonedDateTime addMonths = ZonedDateTime.parse("2019-12-20T10:15:30+05:00[Asia/Karachi]")
        .plusMonths(2);

// subtract one year from now
ZonedDateTime lastYear = ZonedDateTime.now().minus(1, ChronoUnit.YEARS);
```

Similarly, you can also **get different date and time units** using `ZonedDateTime` getter methods:

```java
Month month = ZonedDateTime.now().getMonth();
int year = ZonedDateTime.now().getYear();
```

You can also **compare** two `ZonedDateTime` instances to **check if the given instance is after or before** the other one:

```java
// create zoned dates and times
ZonedDateTime dt1 = ZonedDateTime.parse("2019-12-20T10:15:30+01:00[Europe/Paris]");
ZonedDateTime dt2 = ZonedDateTime.parse("2017-03-05T02:45:15+00:00[Europe/London]");

// check if `dt1` is after `dt2`
boolean isAfter = dt1.isAfter(dt2);

// check if `dt1` is before `dt2`
boolean isBefore = dt1.isBefore(dt2);
```

### `ZonedOffset` & `OffsetDateTime` Classes

Another way to deal with zoned date and time is by using the `ZoneOffset` and `OffsetDateTime` classes. 

`ZonedOffset` is an extension of `ZoneId` that **stores the amount of time that a timezone differs** from Greenwich/UTC. This is usually a fixed number of hours and minutes. Here is an example of `ZonedOffset` that adds 4 hours to the UTC time:

```java
ZoneOffset offset = ZoneOffset.of("+04:00");
```

The `OffsetDateTime` class **represents a date and time with an offset** from UTC/Greenwich in the ISO-8601 calendar system, such as *2019-12-03T10:15:30+01:00*. This class stores all date and time fields to a precision of nanoseconds, plus the offset from UTC/Greenwich.

To **create a new instance** of `OffsetDateTime`, you can either **use the system clock, parse a string, or convert local data time** to zoned date time with `ZonedOffset`:

```java
// use system clock
OffsetDateTime now = OffsetDateTime.now();

// use local date and time with `ZonedOffset`
ZoneOffset offset = ZoneOffset.of("+04:00");
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.JULY, 17, 11, 30);

OffsetDateTime offsetDT = OffsetDateTime.of(localDateTime, offset);

// parse a string
OffsetDateTime parseOffsetDT = OffsetDateTime.parse("2019-12-03T10:15:30+01:00");
```

Just like `ZonedDateTime`, you can use utility methods from `OffsetDateTime` to get different units, add or subtract date and time units, and perform a comparison between two instances.

## Instant API

The `Instant` class is used to **represents a specific moment on the timeline**. It is defined as an offset from January 1st, 1970, at 00:00:00 UTC, also called an [EPOCH](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#EPOCH). Time is measured using 86,400 seconds per day going forward from the origin.

To **create an instance** of `Instant` API, you can either **use the system clock or parse a [Unix timestamp](https://attacomsian.com/blog/java-get-unix-timestamp) or a date string**:

```java
// use system clock
Instant now = Instant.now();

// parse ISO 8601 string
Instant parseISO = Instant.parse("2019-08-08T12:58:00Z");

// parse UNIX timestamp - 2019-09-04T01:54:18Z
Instant parseUnix = Instant.ofEpochSecond(1567562058);

// same time in milliseconds
Instant parseMillis = Instant.ofEpochMilli(1567562058000L);
```

To convert an instance of `Instant` to **EPOCH seconds or milliseconds**, you can do the following:

```java
Instant instant = Instant.parse("2019-12-08T12:58:00Z");

// epoch seconds - 1575809880
long epochSeconds = instant.getEpochSecond();

// epoch milliseconds - 1575809880000
long epochMillis = instant.toEpochMilli();
```

The `Instant` class also provides several **utility methods to make calculations** relative to an `Instant`:

```java
// add 10 seconds
Instant addSeconds = Instant.now().plusSeconds(10);

// minus milliseconds
Instant minusMillis = Instant.now().minus(500, ChronoUnit.MILLIS);
```

## Period and Duration API

Java 8 new date and time API introduced two classes (`Period` and `Duration`) to work with the date and time differences.

### `Period` Class

The `Period` class **represents time in terms of years, months, and days**. It is commonly used to modify an existing date object value and to get the difference between two dates.

The following example demonstrates how you can use the `Period` class to **manipulate** an instance of `LocalDate`:

```java
// future local date
LocalDate futureDate = LocalDate.now().plus(Period.ofDays(5));

// past local date
LocalDate pastDate = LocalDate.now().minus(Period.ofWeeks(1));

// period for specific months and days
LocalDate specificDate = LocalDate.now().plus(Period.ofMonths(2).plusDays(15));
```

Similarly, you can also use the `Period` class to get **the difference between two dates**:

```java
LocalDate firstDate = LocalDate.of(2018, Month.JULY, 5); // 2018-07-05
LocalDate secondDate = LocalDate.of(2019, Month.DECEMBER, 20); // 2019-12-20

// difference between two dates
Period period = Period.between(firstDate, secondDate);

int days = period.getDays(); // 15
int months = period.getMonths(); // 5
int years = period.getYears(); // 1
boolean isNegative = period.isNegative(); // false
boolean isZero = period.isZero(); // false
```

Alternatively, you can use the `ChronoUnit` class to **obtain the period between two dates in a specific unit** such as day, month, or year:

```java
long days = ChronoUnit.DAYS.between(firstDate, secondDate); // 533
long months = ChronoUnit.MONTHS.between(firstDate, secondDate); // 17
long years = ChronoUnit.YEARS.between(firstDate, secondDate); // 1
```

### `Duration` Class

The `Duration` class **represents time in terms of days, hours, seconds, milliseconds, and nanoseconds**. It can be used to modify existing time values and to get the difference between two times.

```java
// future local time
LocalTime futureTime = LocalTime.now().plus(Duration.ofHours(5));

// past local time
LocalTime pastTime = LocalTime.now().minus(Duration.ofDays(1));

// specific days and hours
LocalTime specificTime = LocalTime.now().plus(Duration.ofDays(7).plusHours(3));
```

Here is another example that shows how you can create a `LocalTime` of *11:15 AM* and then add 40 seconds to make it *11:15:40 AM*:

```java
LocalTime time = LocalTime.of(11, 15); // 11:15

// add duration to local time
LocalTime newTime = time.plus(Duration.ofSeconds(40)); // 11:15:40
```

The `Duration` between two times can be obtained either as an instance of `Duration` or as a specific unit. Here is an example that uses the `between()` method from `Duration` to get the **difference between two times**:

```java
LocalTime firstTime = LocalTime.of(11, 30); // 11:30
LocalTime secondTime = LocalTime.of(22, 35); // 22:35

// get the difference between times
Duration duration = Duration.between(firstTime, secondTime);

long millis = duration.toMillis(); // 39900000
long seconds = duration.getSeconds(); // 39900
long minutes = duration.toMinutes(); // 665
long hours = duration.toHours(); // 11
```

Here is another example that uses the `between()` method from `ChronoUnit` to get the **duration between two times in specific units**:

```java
long seconds = ChronoUnit.SECONDS.between(firstTime, secondTime); // 39900
long minutes = ChronoUnit.MINUTES.between(firstTime, secondTime); // 665
long hours = ChronoUnit.HOURS.between(firstTime, secondTime); // 11
```

## Chrono Units Enum

The `ChronoUnit` enum was added to Java 8 new date and time API to **represent individual date and time units** such as day, month, year, week, hour, minutes, and more. It replaces the integer values used in the old API to represent these units.

Here is an example that demonstrates how you can use `ChronoUnit` for different tasks:

```java
// the current date
LocalDate today = LocalDate.now();
System.out.println("Current Date: " + today);

// next week
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Next Week: " + nextWeek);

// next month
LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
System.out.println("Next Month: " + nextMonth);

// next year
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Next Year: " + nextYear);

// next decade
LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
System.out.println("Next Decade: " + nextDecade);

// next century
LocalDate nextCentury = today.plus(1, ChronoUnit.CENTURIES);
System.out.println("Next Century: " + nextCentury);
```

The above code will produce the following output:

```bash
Current Date: 2019-12-19
Next Week: 2019-12-26
Next Month: 2020-01-19
Next Year: 2020-12-19
Next Decade: 2029-12-19
Next Century: 2119-12-19
```

## Temporal Adjusters

Temporal adjusters are **highly useful for performing different calculations** on date and time. You can use them to modify temporal objects and answer questions like *find the next Friday*, *find the second Tuesday of the month*, etc.

Java 8 introduced the `TemporalAdjusters` class for this purpose. Here is how you can use it:

```java
// the current date
LocalDate today = LocalDate.now();
System.out.println("Current date: " + today);

// first day of the month
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("First day of month: " + firstDay);

// last day of the month
LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Last day of month: " + lastDay);

// next Tuesday
LocalDate nextTuesday = today.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
System.out.println("Next Tuesday: " + nextTuesday);

// first day of next month
LocalDate firstDayOfNextMonth = today.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println("First day of next month: " + firstDayOfNextMonth);

// last day of the year
LocalDate lastDayofYear = today.with(TemporalAdjusters.lastDayOfYear());
System.out.println("Last day of year: " + lastDayofYear);

// first day of the year
LocalDate firstDayOfYear = today.with(TemporalAdjusters.firstDayOfYear());
System.out.println("First day of year: " + firstDayOfYear);

// last Friday of the month
LocalDate lastFridayOfMonth = today.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY));
System.out.println("Last Sunday of month: " + lastFridayOfMonth);
```

You should see something like the below printed on the console:

```bash
Current date: 2019-12-19
First day of month: 2019-12-01
Last day of month: 2019-12-31
Next Tuesday: 2019-12-24
First day of next month: 2020-01-01
Last day of year: 2019-12-31
First day of year: 2019-01-01
Last Sunday of month: 2019-12-27
```

## Date and Time Formatting

Just like the `parse()` method to convert a string to an instance of date and time, Java 8 new date and time API also provides the `format()` method for formatting the output.

The below example shows how you can format an instance of `LocalDateTime` in **ISO date format** (yyyy-MM-dd):

```java
LocalDateTime date = LocalDateTime.of(2019, Month.DECEMBER, 18, 9, 45);

// ISO date format (yyyy-MM-dd) - 2019-12-18
String isoDate = date.format(DateTimeFormatter.ISO_DATE);
```

The `DateTimeFormatter` class provides various standard date and time formatting options. Here is another example of **formatting a local date and time to ISO 8601 format**:

```java
// ISO date and time format - 2019-12-18T09:45:00
String isoDateTime = date.format(DateTimeFormatter.ISO_DATE_TIME);
```

**Custom formatting patterns** can also be provided to the `format()` method as shown below:

```java
// custom format pattern (MM/dd/yyyy HH:mm a) - 12/18/2019 09:45 AM
String customFormat = date.format(DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm a"));
```

We can also **pass in the formatting style** like `SHORT`, `MEDIUM`, or `LONG` as part of the formatting pattern as shown below:

```java
// formatting style MEDIUM - Dec 18, 2019 9:45:00 AM
String customFormat = date.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
        .withLocale(Locale.US));
```

## Backward Compatibility

Java 8 has added `toInstant()` method to the legacy `Date` and `Calendar` classes. It can be used to convert a `Date` or `Calendar` instance to a new date and time API instance.

The following example shows how you can use `ofInstant()` to convert a legacy `Date` object to a `LocalDateTime` and `ZonedDateTime` objects:

```java
// current date and time
Date date = new Date();
System.out.println("Current date: " + date);

// get the Instant of the current date (in milliseconds)
Instant now = date.toInstant();

// convert instant to local date/time
LocalDateTime localDT = LocalDateTime.ofInstant(now, ZoneId.systemDefault());
System.out.println("Local date: " + localDT);

// convert instant to zoned date/time
ZonedDateTime zonedDT = ZonedDateTime.ofInstant(now, ZoneId.systemDefault());
System.out.println("Zoned date: " + zonedDT);
```

Here is the output of the above code snippet:

```bash
Current date: Thu Dec 19 14:37:38 PKT 2019
Local date: 2019-12-19T14:37:38.606
Zoned date: 2019-12-19T14:37:38.606+05:00[Asia/Karachi]
```

## Summary

In this in-depth article, we looked at Java 8 new date and time API in detail with examples. Java 8 new date and time APIs are thread-safe and developer-friendly with easier-to-use utility methods and far better zoned date-time handling.

Here is a short summary of the new date and time APIs we have discussed above:

* **Local Date & Time API:** Local date and time API is intended for local date and time operations when you no longer need the timezone information. `LocalDate`, `LocalTime`, and `LocalDateTime` classes are a part of the local API.
* **Zoned Date & Time API:** Java 8 introduced `ZonedDateTime` and `OffsetDateTime` classes along with `ZoneId` and `ZonedOffset` identifiers for handling date and time with timezone information.
* **Instant API:** The `instant` class is added to Java 8 new date and time API to represent a specific moment on the timeline.
* **Period & Duration API:** To work with date and time differences, Java 8 new date and time API introduced `Period` and `Duration` classes. These classes represent time in different units like days, months, years, hours, minutes, etc.
* **Chrono Units Enum:** The `ChronoUnit` enum replaced the legacy integer values in the old API to represent different date and time units.
* **Temporal Adjusters:** Temporal adjusters are another feature to perform date and time calculations in Java 8 and higher.
* **Date and Time Formatting:** To format the date and time output, Java 8 new date and time API introduced the `format()` method.
* **Backward Compatibility:** To keep the new date and time API backward compatible, Java 8 has added the `toInstant()` method to existing `Date` and `Calendar` classes. 

## Further Reading

You may be interested in reading the following Java date and time tutorials:

* [How to get current date and time in Java](https://attacomsian.com/blog/java-get-current-date-time)
* [How to convert a string to date in Java](https://attacomsian.com/blog/java-convert-string-to-date)
* [How to compare dates in Java](https://attacomsian.com/blog/java-compare-dates)
* [How to format a date to string in Java](https://attacomsian.com/blog/java-date-format-to-string)
* [Calculate the difference between two dates in Java](https://attacomsian.com/blog/java-date-difference)
