JSON Java 8 LocalDateTime format in Spring Boot
update: Spring Boot 2.x doesn't require this configuration anymore. I've written a more up to date answer here.
(This is the way of doing it before Spring Boot 2.x, it might be useful for people working on an older version of Spring Boot)
I finally found here how to do it. To fix it, I needed another dependency:
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")
By including this dependency, Spring will automatically register a converter for it, as described here. After that, you need to add the following to application.properties:
spring.jackson.serialization.write_dates_as_timestamps=false
This will ensure that a correct converter is used, and dates will be printed in the format of 2016-03-16T13:56:39.492
Annotations are only needed in case you want to change the date format.
LocalDateTime parsing with jackson
Thank you to @mohammedkhan for the guide!
In this answer:
JSON Java 8 LocalDateTime format in Spring Boot
There's already a setting in spring-boot there's no need to @Autowire
the ObjectMapper
dd this annotation for the Json Deserializer
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateOccurred;
Thank you!
Deserialize Java 8 LocalDateTime with JacksonMapper
The date time you're passing is not an ISO local date time format.
Change to
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
and pass the date string in the format '2011-12-03T10:15:30'.
But if you still want to pass your custom format, you just have to specify the right formatter.
Change to
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
I think your problem is the @DateTimeFormat has no effect at all. As the Jackson is doing the deserialization and it doesn't know anything about spring annotation, and I don't see spring scanning this annotation in the deserialization context.
Alternatively, you can try setting the formatter while registering the Java time module.
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
Here is the test case with the deseralizer which works fine. Maybe try to get rid of that DateTimeFormat annotation altogether.
@RunWith(JUnit4.class)
public class JacksonLocalDateTimeTest {
private ObjectMapper objectMapper;
@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Test
public void test() throws IOException {
final String json = "{ \"date\": \"2016-11-08 12:00\" }";
final JsonType instance = objectMapper.readValue(json, JsonType.class);
assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate());
}
}
class JsonType {
private LocalDateTime date;
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
}
Spring boot: JSON deserialize date and time with time zone to LocalDateTime
There are two problems with your code:
1. Use of wrong type
Cannot deserialize value of type
java.time.LocalDateTime
from String
"2019-10-21T13:00:00+02:00": Failed to deserialize
java.time.LocalDateTime: (java.time.format.DateTimeParseException)
Text '2019-10-21T13:00:00+02:00' could not be parsed, unparsed text
found at index 19
If you analyze the error message, you will find that it is clearly telling you that there is some problem at index 19.
2019-10-21T13:00:00+02:00
// index 19 ----> ^
And, the problem is that LocalDateTime
does not support timezone. Given below is an overview of java.time types and you can see that the type which matches with your date-time string is OffsetDateTime
because it has a zone offset of +02:00
hours.
Change your declaration as follows:
private OffsetDateTime startTime;
2. Use of wrong format
You need to use XXX
for the offset part i.e. your format should be uuuu-MM-dd'T'HH:m:ssXXX
. If you want to stick to Z
, you need to use ZZZZZ
. Check the documentation page of DateTimeFormatter
for more details.
Demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String strDateTime = "2019-10-21T13:00:00+02:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:m:ssXXX");
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}
Output:
2019-10-21T13:00+02:00
Learn more about the modern date-time API from Trail: Date Time.
Also related, RFC3339 - Date and Time on the Internet: Timestamps
This document defines a date and time format for use in Internet
protocols that is a profile of the ISO 8601 standard for
representation of dates and times using the Gregorian calendar.
LocalDateTime is representing in array format
The culprit was @EnableWebMVC
. One of my cors class was having @EnableWebMVC
annotation. This was disabling the spring boot auto configuration and also overriding the mapper confiiguration. This won't let you to override the configuration of object mapper. By removing @EnableMVC
annotation, this is working fine now. In SpringBoot2, we don't need to do any configuration explicitly related to date serialization, it will automatically parse the java 8 dates in "yyyy-mm-dd" format.
Json string from LocalDateTime(java 8) in Spring MVC
A similar question is answered here. You may have to add @JsonSerialize(using = LocalDateTimeSerializer.class)
to your field.
You can also create a custom serializer like below:
public class CustomLocalDateTimeSerializer extends JsonSerializer<LocalDateTime>{
@Override
public void serialize(LocalDateTime dateTime, JsonGenerator generator, SerializerProvider sp)
throws IOException, JsonProcessingException {
String formattedDateTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
generator.writeString( formattedDateTime);
}
}
and use that custom serializer in your LocalDateTime field:
@JsonSerialize(using = CustomLocalDateTimeSerializer.class)
private LocalDateTime w_date;
How to parse LocalDate with Jackson
Since you set values through contructor, not setters, you should put @JsonFormat(...)
on constructor parameters, not fields. This should fix it:
public class LeaveApplUx {
@JsonIgnore
private final String employeeCode;
private final LocalDate startDate;
@JsonIgnore
private final LocalDate rejoinDate;
public LeaveApplUx(@JsonProperty("employeeCode") String employeeCode,
@JsonProperty("startDate") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate startDate,
@JsonProperty("rejoinDate") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate rejoinDate) {
this.employeeCode = employeeCode;
this.startDate = startDate;
this.rejoinDate = rejoinDate;
}
//getters
}
LocalDateTime not displaying as timestamps (ie as a long) java 8 spring boot 2.2.0
Thanks to @deHaar who gave me some hints I've found how to proceed.
I created a custom serializer :
public class LocalDateTimeSerialize extends StdSerializer<LocalDateTime> {
public LocalDateTimeSerialize(Class<LocalDateTime> t) {
super(t);
}
@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
Long l = localDateTime.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli();
jsonGenerator.writeString(l.toString());
}
}
I change my extendMessageConverters to use this custom serializer in my objectMapper :
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()
.addSerializer(LocalDateTime.class, new LocalDateTimeSerialize(LocalDateTime.class)));
Related Topics
How to Determine the Class of a Generic Type
When Should One Use Final for Method Parameters and Local Variables
How Does Auto Boxing/Unboxing Work in Java
What Is the Best Approach for Using an Enum as a Singleton in Java
Java Thread.Sleep Puts Swing UI to Sleep Too
How to Re-Run Failed Junit Tests Immediately
Spring Resttemplate - How to Enable Full Debugging/Logging of Requests/Responses
Setting Background Color for a Jframe
Android 6.0 Open Failed: Eacces (Permission Denied)
How to Avoid Floating Point Precision Errors with Floats or Doubles in Java
Keyword for the Outer Class from an Anonymous Inner Class
How to Change Text Color in the Jtextarea
Returning Null as an Int Permitted with Ternary Operator But Not If Statement
Only One Component Shows Up in Jframe