1. Introduction
In this article, we are going to present ways to format Date in Thymeleaf templates . We will use special #calendars util available in Thymeleaf engine, created for date manipulations on templates.
2. Using #calendar
utility class
Thymeleaf comes with a special utility class called #calendars , that can be used in expression statements to format date.
Example of date formatting with specific pattern is shown in the following code:
Copy
${#calendars.format(cal, 'dd/MMM/yyyy HH:mm')}
In patterns we can use the following letters (very similar to SimpleDateFormat pattern ):
Copy
G - Era designator (before christ, after christ)
y - Year (e.g. 12 or 2012). Use either yy or yyyy.
M - Month in the year. Number of M's determine length of format (e.g. MM, MMM or MMMMM)
d - Day in a month. Number of d's determine length of format (e.g. d or dd)
h - Hour of the day, 1-12 (AM / PM) (normally hh)
H - Hour of the day, 0-23 (normally HH)
m - Minute in an hour, 0-59 (normally mm)
s - Second in a minute, 0-59 (normally ss)
S - Millisecond in second, 0-999 (normally SSS)
E - Day in a week (e.g Monday, Tuesday, etc.)
D - Day in the year (1-366)
F - Day of week in the month (e.g. 1st Thursday of December)
w - Week in the year (1-53)
W - Week in a month (0-5)
a - AM / PM marker
k - Hour in day (1-24, unlike HH's 0-23)
K - Hour in day, AM / PM (0-11)
z - Time Zone
3. Real-life example
Now let's use #calendars utility class in a real-life application.
The project structure is as follows:
Copy
── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── frontbackend
│ │ │ └── thymeleaf
│ │ │ ├── Application.java
│ │ │ ├── config
│ │ │ │ └── WebConfig.java
│ │ │ └── controller
│ │ │ └── IndexController.java
│ │ └── resources
│ │ ├── messages_en_US.properties
│ │ ├── messages_es.properties
│ │ ├── messages.properties
│ │ └── templates
│ │ └── index.html
All GET requests to the root context are handled by IndexController
. Additionally, we set exampleDate
variable with the date 20/06/2020
. We will use this variable to check how the formatting will change by changing the locale.
Copy
package com.frontbackend.thymeleaf.controller;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/")
public class IndexController {
private final static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
@GetMapping
public String main(Model model) throws ParseException {
model.addAttribute("exampleDate", sdf.parse("20/06/2020"));
return "index";
}
}
WebConfig
class is used to change default Spring Boot locale configuration and to set LocaleChangeInterceptor
- that will handle language change initialized on the frontend.
Copy
package com.frontbackend.thymeleaf.config;
import java.util.Locale;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.US);
return localeResolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
Message bundle for localized messages has the following content:
messages.properties:
Copy
home.title=Title
date.format=MM/dd/yyyy
messages_es.properties
Copy
home.title=Título
date.format=dd/MM/yyyy
Finally our Thymeleaf template - index.html
:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Date Format</title>
<link th:rel="stylesheet" th:href="@{assets/bootstrap-slider/css/bootstrap-slider.css}"/>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">Thymeleaf - Bootstrap Date Format</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
th:text="${#strings.toUpperCase(#locale)}">
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" th:href="@{/(lang=en)}">English</a>
<a class="dropdown-item" th:href="@{/(lang=es)}">Spanish</a>
</div>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col mt-5">
<h1 th:text="#{home.title}"></h1>
<div th:with="df=#{date.format}">Date formatted by locale: <strong
th:text="${#calendars.format(exampleDate,df)}"></strong></div>
<div>Custom date format 1: <strong
th:text="${#calendars.format(exampleDate,'yyyy.MM.dd G, HH:mm:ss z')}"></strong></div>
<div>Custom date format 2: <strong
th:text="${#calendars.format(exampleDate,'yyyy-MM-dd HH:mm:ss.SSSZ')}"></strong></div>
<div>Custom date format 3: <strong
th:text="${#calendars.format(exampleDate,'EEE, d MMM yyyy HH:mm:ss Z')}"></strong></div>
</div>
</div>
</div>
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/popper.js/umd/popper.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
</body>
</html>
We used locale variables to set df
object with localized date format.
Copy
<div th:with="df=#{date.format}">Date formatted by locale: <strong
th:text="${#calendars.format(exampleDate,df)}"></strong></div>
The application presents the following functionality:
4. Conclusion
In this article, we presented how to format the date in Thymeleaf templates. We used a sample Spring Boot application and changed default locale configuration to present how to use locale-dependent date formats.
As usual, the code used in this article is available under our GitHub repository
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}