Jackson #JsonFormat converting date with incorrect timezone - java

I have a value coming in from JSON payload as:
"callStartTime" : "2019-03-27 13:00:00"
Entity.java
#JsonProperty("callStartTime")
#Column(name = "call_start_dt", nullable = false)
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", lenient = OptBoolean.FALSE)
private Date callStartTime;
When I printed it on console, it says:
Wed Mar 27 08:00:00 CDT 2019
I wanted to be the same as it was in json payload. How I can fix it?
I am just taking date from json and writing it to mysql db in a datetime column.

Simple solution: I solved it by changing the data type to String which completes my aim to capture the value as it is coming from JSON payload. Using Date and other data types were converting the value to some different timezone.
#JsonProperty("callStartTime")
#Column(name = "call_start_dt", nullable = false)
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", lenient = OptBoolean.FALSE)
private **String** callStartTime;

Try this
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
private Date callStartTime;

java.util.Date does not capture time zone data. It only knows about number of millis since the epoch.
You could try using one of the modules in jackson-modules-java8 and deserialize into an instance of ZonedDateTime instead, which is time-zone aware.
EDIT: try this as a basis for getting it to work:
public class SoTest {
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper().registerModule(new ParameterNamesModule())
.registerModule(new JavaTimeModule());
String s = "{\"callStartTime\" : \"2019-03-27T13:00:00Z\" }";
MyType mt = om.readValue(s, MyType.class);
System.out.println(mt.getCallStartTime());
}
}
class MyType {
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssX", lenient = OptBoolean.FALSE)
private ZonedDateTime callStartTime;
public ZonedDateTime getCallStartTime() {
return callStartTime;
}
public void setCallStartTime(ZonedDateTime date) {
this.callStartTime = date;
}
}

There are two possible solutions for this :
1. Define ObjectMapper bean and set date format.
#Bean
public ObjectMapper objectMapper()
{
ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
objectMapper.setDateFormat(df);
return objectMapper;
}
2. Set date format for the particular field using #JsonFormat
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", lenient = OptBoolean.FALSE)
private Date createTime;

Related

How do I use different date formats for serialization & deserialization?

I'm getting an object with the date field in the format 2022-02-11 which I'm mapping into an object as follows:
{ "dateTimeField": "2022-02-11" }
#Data
class MyPojo {
#JsonFormat(pattern = "yyyy-MM-dd")
private Date dateTimeField;
}
Now I need to send this object as a json response, but I need it to be in a different format:
{ "dateTimeField": "2022-02-11 00:00:00" }
If I change the pattern field, deserialization fails:
#Data
class MyPojo {
// com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2022-02-11": expected format "yyyy-MM-dd HH:mm:ss"
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date dateTimeField;
}
How do I use different patterns for serialization & deserialization?
This can be accomplished using separate annotations on the getter and setter of the field:
#Data
class MyPojo {
private Date dateTimeField;
// Used during serialization
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date getDateTimeField() {
return dateTimeField;
}
// Used during deserialization
#JsonFormat(pattern = "yyyy-MM-dd")
public void setDateTimeField(Date dateTimeField) {
this.dateTimeField = dateTimeField;
}
}
Alternatively, using Lombok's (experimental as of 11 Feb 2022) onX feature:
#Data
class MyPojo {
#Getter(onMethod_ = {#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")}) // Used during serialization
#Setter(onMethod_ = {#JsonFormat(pattern = "yyyy-MM-dd")}) // Used during deserialization
private Date dateTimeField;
}

JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime` from String

I am sending request to external service which has updatedDate property
#UpdateTimestamp
#Column(name = "updated_date")
private LocalDateTime updatedDate;
When I receive the response in my DTO I am trying to format the LocalDateTime property like this
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime updatedDate;
But I get error in Postman
"message": "JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime` from String \"2020-04-14T10:45:07.719\": Text '2020-04-14T10:45:07.719' could not be parsed at index 14; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDateTime` from String \"2020-04-14T10:45:07.719\
There are milliseconds in the input string, so your format should be "yyyy-MM-dd'T'HH:mm:ss.SSS"
Update:
If the millisecond part consists of 1, 2, 3 digits or is optional, you may use the following format:
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS][.SS][.S]")
private LocalDateTime updatedTime;
You can remove the annotation #JsonFormat and let it works in a default way. It is working fine for me even if I removed the millisecond.
#NotNull
#FutureOrPresent(message = ErrorMessages.INVALID_CAMPAIGN_START_DATE)
//#JsonFormat(pattern = "MM/dd/yyyy")
private LocalDateTime campaignStartDate;
JSON Request:
{ "campaignStartDate" : "2020-12-31T15:53:16",
"campaignExpDate" : "2021-01-24T15:53:16",
}
{
"campaignStartDate" : "2020-12-31T15:53:16.45",
"campaignExpDate" : "2021-01-24T15:53:16.45",
}
{
"campaignStartDate" : "2020-12-31T15:53:16.445",
"campaignExpDate" : "2021-01-24T15:53:16.445",
}
These JSON requests will work fine.
I had the same error, I used this one with "pickupDate":"2014-01-01T00:00:00"
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
#JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime pickupDate;
I was getting this because my JSONproperty setter was not properly handling null.
e.g.
#Column(name = "equipment_purchase_date")
private LocalDate purchaseDate;
bad:
#JsonProperty
public void setPurchaseDate(String dateStr) throws ParseException
{
this.purchaseDate = LocalDate.parse(dateStr, df);
}
good(Fix):
#JsonProperty
public void setPurchaseDate(String dateStr) throws ParseException
{
this.purchaseDate = dateStr == null ? null : LocalDate.parse(dateStr, df);
}
thought i would include this as none of the above answers were applicable in this case.

Validate that Java LocalDate matches yyyy-MM-dd format with readable message

I have below property in POJO class for DoB.
#NotNull(message = "dateOfBirth is required")
#JsonDeserialize(using = LocalDateDeserializer.class)
LocalDate dateOfBirth;
How can I validate that
User is sending valid date format (accepting only YYYY-MM-DD)
If user enters incorrect date I want to send custom message or more readable message. Currently if user entered invalid date then application sends below long error -
JSON parse error: Cannot deserialize value of type `java.time.LocalDate` from String \"1984-33-12\": Failed to deserialize java.time.LocalDate:
(java.time.format.DateTimeParseException) Text '1984-33-12' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 33;
...
You can use this annotation:
#JsonFormat(pattern = "YYYY-MM-DD")
You can read further about custom error messages when validating date format in here:
custom error message
You should create your custom deserializer, overwrite deserialize method to throw your custom error and use it in #JsonDeserialize
public class CustomDateDeserializer
extends StdDeserializer<LocalDate> {
private static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("YYYY-MM-DD");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class<?> vc) {
super(vc);
}
#Override
public LocalDate deserialize(
JsonParser jsonparser, DeserializationContext context)
throws IOException {
String date = jsonparser.getText();
try {
return LocalDate.parse(date, formatter);
} catch (DateTimeParseException e) {
throw new RuntimeException("Your custom exception");
}
}
}
Use it:
#JsonDeserialize(using = CustomDateDeserializer.class)
LocalDate dateOfBirth;
Something like this.
#Column(name = "date_of_birth")
#DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE)
#JsonFormat(pattern = "YYYY-MM-dd")
private LocalDateTime dateOfBirth;
DateTimeFormatter Java doc
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

json formatting datetime, date and time

I have a Class with the following
class MyClass {
private Date datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-01-01 11:32:15");
private Time time = new Time(System.currentTimeMillis());
private Date date = new Date(System.currentTimeMillis());
// getters and setters
}
Gson
Gson gson = new Gson();
System.out.println(gson.toJson(myClass));
Gson gsonBuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
System.out.println(gsonBuilder.toJson(myClass));
I get
{"datetime":"Jan 1, 2018 11:32:15 AM","time":"04:51:23 PM","date":"Jan 1, 2018 4:51:23 PM"}
{"datetime":"2018-01-01 11:32:15","time":"04:51:23 PM","date":"2018-01-01 16:51:23"}
Jackson
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(myClass));
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
System.out.println(mapper.writeValueAsString(myClass));
I get
{"datetime":1514806335000,"time":"17:01:18","date":1514826078776}
{"datetime":"2018-01-01T11:32:15.000+0000","time":"17:13:52","date":"2018-01-01T17:13:52.224+0000"}
How can I get
{"datetime":"2018-01-01 11:32:15","time":"16:51:23","date":"2018-01-01"}
I am not tied to any library so if there is a more appropriate JSON library that can do the job, please comment.
With Jackson, annotate your dateTime and date fields with
#JsonFormat
(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
Found the answer:
Using Jackson you can annotate each Field
class MyClass {
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
public Date datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-01-01 11:32:15");
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
public Time time = new Time(System.currentTimeMillis());
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public Date date = new Date(System.currentTimeMillis());
MyClass() throws ParseException { }
}
MyClass myClass = new MyClass();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(myClass));
Gives you
{"datetime":"2018-01-01 11:32:15","time":"17:21:22","date":"2018-01-01"}

Converting date from timestamp to human readable in entity constructor

Currently, the format of the Date requestDate variable stored looks like: 2017-02-17 00:00:00.0. I want to convert this into, for example: Friday, February 17, 2017. I would like to do the conversion here in my entity and return it so that when it's displayed it is more human readable. This will likely happen in the constructor, at this line: this.setRequestDate(doDateConversion(requestDate));. How can I make this conversion?
My Request entity:
#Entity
#Table(name = "Request")
public class RequestDO implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="request_id")
private Long id;
private Date requestDate;
private String description;
private RequestStatus status;
/*private Boolean read;*/
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="user_id", nullable = false)
private Users users;
public RequestDO() {}
public RequestDO(Users user, Date requestDate) {
this.setUsers(user);
this.setRequestDate(requestDate);
}
#Override
public String toString() {
return String.format(
"RequestDO[id=%d, inital='%s', requestDate='%s']",
getId()
, getUsers().getInitialName()
, getRequestDate());
}
public Date getRequestDate() {
return requestDate;
}
public void setRequestDate(Date requestDate) {
this.requestDate = requestDate;
}
}
You can use SimpleDateFormat to convert your Date to a readable String of your choice.
The time format String for your example is EEEE, MMMM, dd, yyyy. You have to create a new SimpleDateFormat object and format your date to a String. Examples...
But Spring provides some specials out of the box. For example you can use Jackson for date format: #JsonFormat(pattern="yyyy-MM-dd") more. It is also possible to add a data format in application.properties file : spring.jackson.date-format
Using SimpleDateFormat:
java.sql.Date date = new Date(System.currentTimeMillis());
System.out.println(new SimpleDateFormat("EEEE, MMMM dd, YYYY").format(date));
See this for more details.
I solved the problem by changing the dates as they are read in my controller, using SimpleDateFormat:
#RequestMapping(value = "/requests", method = RequestMethod.GET)
public String getAllRequests(Model model, RequestModel requestModel) throws ParseException {
List<RequestDO> requestDOArrayList = new ArrayList<RequestDO>();
for (RequestDO requestDO : requestRepository.findAll()) {
log.info(requestDO.toString());
// Display all dates in Requests list in human-readable form
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(requestDO.getRequestDate().toString());
log.info(String.valueOf(date));
requestDO.setRequestDate(date);
requestDOArrayList.add(requestDO);
}
model.addAttribute("requests", requestDOArrayList);
log.info(requestDOArrayList.toString());
return "requests";
}

Categories

Resources