The Master Class of "Learn Spring Security" is out:

>> CHECK OUT THE COURSE

1. Introduction

Thymeleaf is a Java template engine designed to work directly with Spring. For an intro to Thymeleaf and Spring, have a look at this write-up.

Besides these basic functions, Thymeleaf offers us a set of utility objects that will help us perform common tasks in our application.

In this article, we will discuss the processing and formatting of the new and old Java Date classes with handful features of Thymeleaf 3.0.

2. Maven Dependencies

First, let’s see the configuration needed to integrate Thymeleaf with Spring into our pom.xml:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring4</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

The latest versions of thymeleaf and thymeleaf-spring4 can be found on Maven Central. Note that, for a Spring 3 project, the thymeleaf-spring3 library must be used instead of thymeleaf-spring4.

Moreover, in order to work with new Java 8 Date classes, we will add the following dependency to our pom.xml:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
    <version>3.0.0.RELEASE</version>
</dependency>

The thymeleaf extras is an optional module, fully supported by the official Thymeleaf team, that was created for compatibility with the Java 8 Time API. It adds a #temporals object to the Context as a utility object processor during expression evaluations. This means that it can be used to evaluate expressions in Object-Graph Navigation Language (OGNL) and Spring Expression Language (SpringEL).

3. Old and New: java.util and java.time

The Time package is a new date, time, and calendar API for the Java SE platform. The main difference between old legacy Date and is that the new API distinguishes between machine and human views of a timeline. The machine view reveals a sequence of integral values relative to the epoch, whereas view reveals a set of fields (e.g., year or day).

To work with new Time package, we need to configure our template engine to use the new Java8TimeDialect:

private TemplateEngine templateEngine(ITemplateResolver templateResolver) {
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.addDialect(new Java8TimeDialect());
    engine.setTemplateResolver(templateResolver);
    return engine;
}

This will add the #temporals object similar to the ones in the Standard Dialect, allowing the formatting and creation of Temporal objects from Thymeleaf templates.

In order to test the processing of new and old classes, we’ll create the following variables and add them as model objects to our controller class:

model.addAttribute("standardDate", new Date());
model.addAttribute("localDateTime", LocalDateTime.now());
model.addAttribute("localDate", LocalDate.now());
model.addAttribute("timestamp", Instant.now());

Now we are ready to use Expression and Temporals Utility Objects provided by Thymeleaf.

3.1. Format Dates

The first function that we want to cover is formatting of a Date object (which is added to the Spring model parameters). We decided to use ISO8601 format:

<h1>Format ISO</h1>
<p th:text="${#dates.formatISO(standardDate)}"></p>
<p th:text="${#temporals.formatISO(localDateTime)}"></p>
<p th:text="${#temporals.formatISO(localDate)}"></p>
<p th:text="${#temporals.formatISO(timestamp)}"></p>

No matter how our Date was set on the back-end side, it will be shown accordingly to selected standard. The standardDate is going to be processed by the #dates utility. The new LocalDateTime, LocalDate and Instant classes are going to be processed by the #temporals utility. This is the final result we’ll see in the browser:

This is the final result we’ll see in the browser:

Moreover, if we want to set the format manually, we can do it by using:

<h1>Format manually</h1>
<p th:text="${#dates.format(standardDate, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDateTime, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDate, 'MM-yyyy')}"></p>

As we can observe, we cannot process the Instant class with #temporals.format(…) — it will result in UnsupportedTemporalTypeException. Moreover, formatting the LocalDate is only possible if we’ll specify only the particular date fields, skipping the time fields.

The final result:

3.2. Obtain Specific Date Fields

In order to obtain the specific fields of the java.util.Date class, we should use the following utility objects:

${#dates.day(date)}
${#dates.month(date)}
${#dates.monthName(date)}
${#dates.monthNameShort(date)}
${#dates.year(date)}
${#dates.dayOfWeek(date)}
${#dates.dayOfWeekName(date)}
${#dates.dayOfWeekNameShort(date)}
${#dates.hour(date)}
${#dates.minute(date)}
${#dates.second(date)}
${#dates.millisecond(date)}

For the new java.time package, we should stick with #temporals utilities:

${#temporals.day(date)}
${#temporals.month(date)}
${#temporals.monthName(date)}
${#temporals.monthNameShort(date)}
${#temporals.year(date)}
${#temporals.dayOfWeek(date)}
${#temporals.dayOfWeekName(date)}
${#temporals.dayOfWeekNameShort(date)}
${#temporals.hour(date)}
${#temporals.minute(date)}
${#temporals.second(date)}
${#temporals.millisecond(date)}

Let’s look at a few examples. First, let’s show today’s day of the week:

<h1>Show only which day of a week</h1>
<p th:text="${#dates.day(standardDate)}"></p>
<p th:text="${#temporals.day(localDateTime)}"></p>
<p th:text="${#temporals.day(localDate)}"></p>

Next, let’s show the name of the week day:

<h1>Show the name of the week day</h1>
<p th:text="${#dates.dayOfWeekName(standardDate)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDateTime)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDate)}"></p>

And finally, let’s show the current second of the day:

<h1>Show the second of the day</h1>
<p th:text="${#dates.second(standardDate)}"></p>
<p th:text="${#temporals.second(localDateTime)}"></p>

Please note that in order to work with time parts, you would need to use LocalDateTime, as LocalDate will throw an error.

4. Conclusion

In this quick tutorial, we discussed Java Date processing features implemented in the Thymeleaf framework, version 3.0.

The full implementation of this tutorial can be found in the GitHub project – this is a Maven-based project that is easy to import and run.

How to test? Our suggestion is to play with the code in a browser first, then check our existing JUnit tests as well.

Please note that our examples do not cover all available options in Thymeleaf. If you want to learn about all types of utilities, then take a look at our article covering Spring and Thymeleaf Expressions.

The Master Class of "Learn Spring Security" is out:

>> CHECK OUT THE COURSE