eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

Java 8 introduced new APIs for Date and Time to address the shortcomings of the older java.util.Date and java.util.Calendar.

In this tutorial, let’s start with the issues in the existing Date and Calendar APIs and discuss how the new Java 8 Date and Time APIs address them.

We will also look at some of the core classes of the new Java 8 project that are part of the java.time package, such as LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Period, Duration and their supported APIs.

Further reading:

Working with Date Parameters in Spring

Learn how to work with Date parameters in Spring MVC

Check If a String Is a Valid Date in Java

Have a look at different ways to check if a String is a valid date in Java

2. Issues With the Existing Date/Time APIs

  • Thread safety – The Date and Calendar classes are not thread safe, leaving developers to deal with the headache of hard-to-debug concurrency issues and to write additional code to handle thread safety. On the contrary, the new Date and Time APIs introduced in Java 8 are immutable and thread safe, thus taking that concurrency headache away from developers.
  • API design and ease of understanding – The Date and Calendar APIs are poorly designed with inadequate methods to perform day-to-day operations. The new Date/Time API is ISO-centric and follows consistent domain models for date, time, duration and periods. There are a wide variety of utility methods that support the most common operations.
  • ZonedDate and Time – Developers had to write additional logic to handle time-zone logic with the old APIs, whereas with the new APIs, handling of time zone can be done with Local and ZonedDate/Time APIs.

3. Using LocalDate, LocalTime and LocalDateTime

The most commonly used classes are LocalDate, LocalTime and LocalDateTime. As their names indicate, they represent the local date/time from the context of the observer.

We mainly use these classes when time zones are not required to be explicitly specified in the context. As part of this section, we will cover the most commonly used APIs.

3.1. Working With LocalDate

The LocalDate represents a date in ISO format (yyyy-MM-dd) without time. We can use it to store dates like birthdays and paydays.

An instance of current date can be created from the system clock:

LocalDate localDate = LocalDate.now();

And we can get the LocalDate representing a specific day, month and year by using the of method or the parse method.

For example, these code snippets represent the LocalDate for February 20, 2015:

LocalDate.of(2015, 02, 20);

LocalDate.parse("2015-02-20");

The LocalDate provides various utility methods to obtain a variety of information. Let’s have a quick peek at some of these API methods.

The following code snippet gets the current local date and adds one day:

LocalDate tomorrow = LocalDate.now().plusDays(1);

This example obtains the current date and subtracts one month. Note how it accepts an enum as the time unit:

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);

In the following two code examples, we parse the date “2016-06-12” and get the day of the week and the day of the month respectively. Note the return values — the first is an object representing the DayOfWeek, while the second is an int representing the ordinal value of the month:

DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek();

int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();

We can test if a date occurs in a leap year, for example the current date:

boolean leapYear = LocalDate.now().isLeapYear();

Also, the relationship of a date to another can be determined to occur before or after another date:

boolean notBefore = LocalDate.parse("2016-06-12")
  .isBefore(LocalDate.parse("2016-06-11"));

boolean isAfter = LocalDate.parse("2016-06-12")
  .isAfter(LocalDate.parse("2016-06-11"));

Finally, date boundaries can be obtained from a given date.

In the following two examples, we get the LocalDateTime that represents the beginning of the day (2016-06-12T00:00) of the given date and the LocalDate that represents the beginning of the month (2016-06-01) respectively:

LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay();
LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12")
  .with(TemporalAdjusters.firstDayOfMonth());

Now let’s have a look at how we work with local time.

3.2. Working With LocalTime

The LocalTime represents time without a date.

Similar to LocalDate, we can create an instance of LocalTime from the system clock or by using parse and of methods.

We’ll now take a quick look at some of the commonly used APIs.

An instance of current LocalTime can be created from the system clock:

LocalTime now = LocalTime.now();

We can create a LocalTime representing 6:30 a.m. by parsing a string representation:

LocalTime sixThirty = LocalTime.parse("06:30");

The factory method of can also be used to create a LocalTime. This code creates LocalTime representing 6:30 a.m. using the factory method:

LocalTime sixThirty = LocalTime.of(6, 30);

Let’s create a LocalTime by parsing a string and adding an hour to it by using the “plus” API. The result would be LocalTime representing 7:30 a.m.:

LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);

Various getter methods are available that can be used to get specific units of time like hour, min and secs:

int six = LocalTime.parse("06:30").getHour();

We can also check if a specific time is before or after another specific time. This code sample compares two LocalTime for which the result would be true:

boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));

Finally, the max, min and noon time of a day can be obtained by constants in LocalTime class. This is very useful when performing database queries to find records within a given span of time.

For example, the below code represents 23:59:59.99:

LocalTime maxTime = LocalTime.MAX

Now let’s dive into LocalDateTime.

3.3. Working With LocalDateTime

LocalDateTime is used to represent a combination of date and time. This is the most commonly used class when we need a combination of date and time.

The class offers a variety of APIs. Here, we’ll look at some of the most commonly used ones.

An instance of LocalDateTime can be obtained from the system clock similar to LocalDate and LocalTime:

LocalDateTime.now();

The below code samples explain how to create an instance using the factory “of” and “parse” methods. The result would be a LocalDateTime instance representing February 20, 2015, 6:30 a.m.:

LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
LocalDateTime.parse("2015-02-20T06:30:00");

There are utility APIs to support addition and subtraction of specific units of time like days, months, years and minutes.

The below code demonstrates the “plus” and “minus” methods. These APIs behave exactly like their counterparts in LocalDate and LocalTime:

localDateTime.plusDays(1);
localDateTime.minusHours(2);

Getter methods are also available to extract specific units similar to the date and time classes. Given the above instance of LocalDateTime, this code sample will return the month February:

localDateTime.getMonth();

4. Using ZonedDateTime API

Java 8 provides ZonedDateTime when we need to deal with time-zone-specific date and time. The ZoneId is an identifier used to represent different zones. There are about 40 different time zones, and the ZoneId represents them as follows.

Here, we create a Zone for Paris:

ZoneId zoneId = ZoneId.of("Europe/Paris");

And we can get a set of all zone ids:

Set<String> allZoneIds = ZoneId.getAvailableZoneIds();

The LocalDateTime can be converted to a specific zone:

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

The ZonedDateTime provides the parse method to get time-zone-specific date-time:

ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");

Another way to work with time zone is by using OffsetDateTime. The OffsetDateTime is an immutable representation of a date-time with an offset. This class stores all date and time fields, to a precision of nanoseconds, as well as the offset from UTC/Greenwich.

The OffSetDateTime instance can be created using ZoneOffset. Here, we create a LocalDateTime representing 6:30 a.m. on February 20, 2015:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

Then we add two hours to the time by creating a ZoneOffset and setting for the localDateTime instance:

ZoneOffset offset = ZoneOffset.of("+02:00");

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

We now have a localDateTime of 2015-02-20 06:30 +02:00.

Now let’s move on to how to modify date and time values using the Period and Duration classes.

5. Using Period and Duration

The Period class represents a quantity of time in terms of years, months and days, and the Duration class represents a quantity of time in terms of seconds and nanoseconds.

5.1. Working With Period

The Period class is widely used to modify values of given a date or to obtain the difference between two dates:

LocalDate initialDate = LocalDate.parse("2007-05-10");

We can manipulate the Date by using Period:

LocalDate finalDate = initialDate.plus(Period.ofDays(5));

The Period class has various getter methods such as getYears, getMonths and getDays to get values from a Period object.

For example, this returns an int value of 5 as we try to get difference in terms of days:

int five = Period.between(initialDate, finalDate).getDays();

We can get the Period between two dates in a specific unit such as days or months or years, using ChronoUnit.between:

long five = ChronoUnit.DAYS.between(initialDate, finalDate);

This code example returns five days.

Let’s continue by taking a look at the Duration class.

5.2. Working With Duration

Similar to Period, the Duration class is used to deal with Time.

Let’s create a LocalTime of 6:30 a.m. and then add a duration of 30 seconds to make a LocalTime of 6:30:30 a.m.:

LocalTime initialTime = LocalTime.of(6, 30, 0);

LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));

We can get the Duration between two instants as either a Duration or a specific unit.

First, we use the between() method of the Duration class to find the time difference between finalTime and initialTime and return the difference in seconds:

long thirty = Duration.between(initialTime, finalTime).getSeconds();

In the second example, we use the between() method of the ChronoUnit class to perform the same operation:

long thirty = ChronoUnit.SECONDS.between(initialTime, finalTime);

Now we’ll look at how to convert existing Date and Calendar to new Date/Time.

6. Compatibility With Date and Calendar

Java 8 has added the toInstant() method, which helps to convert existing Date and Calendar instance to new Date and Time API:

LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());

The LocalDateTime can be constructed from epoch seconds. The result of the below code would be a LocalDateTime representing 2016-06-13T11:34:50:

LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);

Now let’s move on to Date and Time formatting.

7. Date and Time Formatting

Java 8 provides APIs for the easy formatting of Date and Time:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);

This code passes an ISO date format to format the local date, with a result of 2015-01-25:

String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);

The DateTimeFormatter provides various standard formatting options.

Custom patterns can be provided to the format method as well, which here returns a LocalDate as 2015/01/25:

localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

We can pass in formatting style either as SHORT, LONG or MEDIUM as part of the formatting option.

For example, this would give an output representing LocalDateTime in 25-Jan-2015, 06:30:00:

localDateTime
  .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
  .withLocale(Locale.UK));

Let’s take a look at alternatives available to Java 8 Core Date/Time APIs.

8. Backport and Alternate Options

8.1. Using the ThreeTen Project

For organizations that are on the path of moving to Java 8 from Java 7 or Java 6 and that want to use date and time API, the ThreeTen project provides the backport capability.

Developers can use classes available in this project to achieve the same functionality as that of new Java 8 Date and Time APIs. And once they move to Java 8, the packages can be switched.

The artifact for the ThreeTen project can be found in the Maven Central Repository:

<dependency>
    <groupId>org.threeten</groupId>
    <artifactId>threetenbp</artifactId>
    <version>1.3.1</version>
</dependency>

8.2. Joda-Time Library

Another alternative for Java 8 Date and Time library is Joda-Time library. In fact, the Java 8 Date/Time API has been led jointly by the author of Joda-Time library (Stephen Colebourne) and Oracle. This library provides pretty much all capabilities that are supported in the Java 8 Date/Time project.

The artifact can be found in Maven Central by including the below pom dependency in our project:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.4</version>
</dependency>

9. Conclusion

Java 8 provides a rich set of APIs with consistent API design for easier development.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)