How to Configure Date Formatting in SpringBoot Backend Applications
This guide explains how to customize the serialization and deserialization of Date objects in SpringBoot by adjusting application.yml/properties, using @JsonFormat, @DateTimeFormat, and @Temporal annotations, and by creating global converters for both form submissions and JSON payloads, ensuring consistent timezone handling.
In a SpringBoot application, the default JSON serialization of Date produces an ISO‑8601 timestamp such as 2020-12-03T15:12:26.000+00:00 , which often needs to be converted to a custom format for front‑end display.
Method 1: Modify configuration files
In application.yml set the Jackson date format and time zone:
spring:
# configure date format
jackson:
date-format: yyyy-MM-dd HH:mm:ss # convert timestamps to the specified format
time-zone: GMT+8 # set time zone to UTC+8 (Beijing)Or achieve the same effect in application.properties :
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss # convert timestamps to the specified format
spring.jackson.time-zone=GMT+8 # set time zone to UTC+8 (Beijing)Note: Adjusting time-zone is necessary because the database stores dates in UTC; without it the displayed time will be eight hours behind Beijing time.
Method 2: Annotate fields in Java beans
I. @JsonFormat – specify the pattern directly on a Date field:
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;II. @DateTimeFormat – use this annotation on a Date property when converting from a string:
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;III. @Temporal – control the persistence format with TemporalType.TIMESTAMP :
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;2. Configure a global date converter for incoming String parameters
2.1 Define a Converter<String, Date> component that parses several common date patterns and registers it as a bean:
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Component
public class GlobalFormDateConvert implements Converter
{
private static final List
paramList = new ArrayList<>();
private static final String param1 = "yyyy-MM";
private static final String param2 = "yyyy-MM-dd";
private static final String param3 = "yyyy-MM-dd HH:mm";
private static final String param4 = "yyyy-MM-dd HH:mm:ss";
static {
paramList.add(param1);
paramList.add(param2);
paramList.add(param3);
paramList.add(param4);
}
public Date parseDate(String source, String format) {
System.out.println("parseDate converting date");
Date date = null;
try {
DateFormat dateFormat = new SimpleDateFormat(format);
date = dateFormat.parse(source);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
@Override
public Date convert(String source) {
System.out.println("convert date format");
if (StringUtils.isEmpty(source)) {
return null;
}
source = source.trim();
if (source.matches("^\\d{4}-\\d{1,2}$")) {
return parseDate(source, paramList.get(0));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
return parseDate(source, paramList.get(1));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}$")) {
return parseDate(source, paramList.get(2));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
return parseDate(source, paramList.get(3));
} else {
throw new IllegalArgumentException("Undefined date format -> " + source);
}
}
}2.2 Define a global JSON‑to‑Date converter by extending StdDateFormat and overriding parse and format methods:
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import org.springframework.util.StringUtils;
public class GlobalJsonDateConvert extends StdDateFormat {
public static final GlobalJsonDateConvert instance = new GlobalJsonDateConvert();
@Override
public Date parse(String dateStr, ParsePosition pos) {
return getDate(dateStr, pos);
}
@Override
public Date parse(String dateStr) {
ParsePosition pos = new ParsePosition(0);
return getDate(dateStr, pos);
}
private Date getDate(String dateStr, ParsePosition pos) {
System.out.println("json date conversion");
SimpleDateFormat sdf = null;
if (StringUtils.isEmpty(dateStr)) {
return null;
} else if (dateStr.matches("^\\d{4}-\\d{1,2}$")) {
sdf = new SimpleDateFormat("yyyy-MM");
return sdf.parse(dateStr, pos);
} else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(dateStr, pos);
} else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}$")) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
return sdf.parse(dateStr, pos);
} else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.parse(dateStr, pos);
} else if (dateStr.length() == 23) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return sdf.parse(dateStr, pos);
}
return super.parse(dateStr, pos);
}
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date, toAppendTo, fieldPosition);
}
@Override
public GlobalJsonDateConvert clone() {
return new GlobalJsonDateConvert();
}
}2.3 Register the converters in a @Configuration class, creating a MappingJackson2HttpMessageConverter with the custom ObjectMapper and a ConversionService that includes the form converter:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xgf.online_mall.convert.GlobalFormDateConvert;
import com.xgf.online_mall.convert.GlobalJsonDateConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ConversionServiceFactoryBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Configuration
public class WebConfig {
// JSON global date converter
@Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(GlobalJsonDateConvert.instance);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
converter.setObjectMapper(mapper);
List
list = new ArrayList<>();
list.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(list);
return converter;
}
// Form global date converter
@Bean
@Autowired
public ConversionService getConversionService(GlobalFormDateConvert globalDateConvert) {
ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
Set
converters = new HashSet<>();
converters.add(globalDateConvert);
factoryBean.setConverters(converters);
return factoryBean.getObject();
}
}By applying these configuration methods and global converters, SpringBoot applications can consistently format Date objects for both JSON responses and form submissions, while respecting the desired time zone.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.