I have been used Spring Date Rest with Spring Boot in my project.
This project has a object and I have used the annotation #JsonFormat to format the date field that will be received from my Json.
The format of field Date is "dd/MM/yyyy".
When I send in my json the value "08/07/1980" the Jackson convert to the value "07/07/1980".
The problem is that #JsonFormat set the date with one day less
This is my source code
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy", locale = "pt-BR", timezone = "UTC")
private Date birthDate;
Thanks
Use this solution, it is more effective and modern than my solution: https://stackoverflow.com/a/45456037/4886918
Thanks #Benjamin Lucidarme.
I resolved my problem using:
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy", locale = "pt-BR", timezone = "Brazil/East")
private Date birthDate;
I changed timezone to "Brazil/East" or "America/Sao_Paulo" and working now
Thanks
#William's answer works but you should add theses lines to your application.properties files instead:
spring.jackson.time-zone=Brazil/East
spring.jackson.locale=pt-BR
In that way, you indicate the time-zone and locale only one time, and it applicate to all the Date of your application.
I'd go with setting ObjectMapper timezone as default JVM timezone:
ObjectMapper objectMapper = new ObjectMapper();
//Set default time zone as JVM timezone due to one day difference between original date and formatted date.
objectMapper.setTimeZone(TimeZone.getDefault());
It's a better solution if you don't know what timezone is used on a server environment.
In spring-boot environment you can override default JacksonAutoConfiguration:
#Bean
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false)
// Set timezone for JSON serialization as system timezone
.timeZone(TimeZone.getDefault())
.build();
}
On both side (Client - Server) annotate your date filed like this:
#JsonDeserialize(using = JsonDateDeserializer.class)
#JsonSerialize(using = JsonDateSerializer.class)
private Date birthDate;
and on both side again put this implementations for serializing and deserializing:
public class JsonDateSerializer extends JsonSerializer<Date> {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
#Override
public void serialize(final Date date, final JsonGenerator gen, final SerializerProvider provider) throws IOException, JsonProcessingException {
String dateString = format.format(date);
gen.writeString(dateString);
}
}
public class JsonDateDeserializer extends JsonDeserializer<Date> {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
#Override
public Date deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
if (jp.getCurrentToken().equals(JsonToken.VALUE_STRING)) {
try {
Date date = format.parse(jp.getText().toString());
return date;
} catch (ParseException e) {
//e.printStackTrace();
}
}
return null;
}
}
I too faced similar issue. I guess all the answers added for this question are specific to above question, my solution will explain the issue and provide generic solution.
You may face this issue, when you are using 2 different time-zones for same Date .
When you do new Date(), it uses your default time-zone unless you explicitly specify time-zone. Lemme explain this to you with a code-snippet, (you are in India and current date is (9/5/2021, 12 a.m. IST)
// 09/05/2021 00:00:00 IST
Date birthDate = new Date();
Now, when set above birthDate to model and when it's serialized using JsonFormat. By default JsonFormat uses UTC time-zone.
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private Date birthDate;
Serialization will result in 08/05/2021, not 09/05/2021.
Lemme write the dates with timezone that's 08/05/2021 UTC, and 09/05/2021 IST.
Lemme add time too for dates, 08/05/2021 18:30:00 UTC, and 09/05/2021 00:00:00 IST.
Now you get why its happening, if you see dates are correct, but having different time-zones. There are 2 ways to handle this problem,
Use same time-zones
Add time and time-zones too while serializing dates. Like 08/05/2021 18:30:00 UTC, and 09/05/2021 00:00:00 IST
Related
How can I reformat this date time even I'm putting this annotation in my java code :
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateFinContrat;
and in my html file :
<td th:text="${#dates.format(row.dateNaissance, 'dd/MM/yyyy')}"></td>
what i want is to remove the hh:mm:ss in my web page.
it shows like this :
this is how it looks like
2050-07-07 00:00:00.0
As you can see , there's a space before that 00:00:00.
2050-07-07 00:00:00.0
So first try to split that string with 'Space'.
I would recommend formatting the date in either the service or the UI. Also try using LocalDate and LocalDateTime class which are latest class from java.utils.
Annotation Based
If REST service with JSON response, Please use the following to format the date based on the pattern:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
or
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
Using DateTimeFormatter or SimpleDateFormat Utility Class
SimpleDateFormat Code Snippet:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = formatter.format(date);
DateTimeFormatter Code Snipped:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
formatter.formate(date);
Please reference: #DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") is Not Working
I want to serialize a Json object with a date field, into a Pojo.
For example
{
date: <some arbitrary date format>
}
to
#JsonFormat(???)
LocalDateTime dateTime;
The problem is that the date can be in any number of formats. For example, maybe just a year, just a date, or date and time. And even those can be in multiple formats.
2021
2021-5-23
2021/05/23
2021/05/23 02:07
2021-05-23 02:07:53
2021/05/23 02:07:50.567
I've already written a parser that has a list of formats and will loop through them until it finds one that works. How can I write a custom Jackson serializer or formatter that uses that code and can take a string from a Json object and properly convert it to a Date or LocalDateTime object in the Pojo?
If it makes a difference, I'm also doing this in SpringBoot
I think, you are talking about DEserializing? If so, you can create your own JsonDeserializer that supports LocalDateTime and register it with JsonComponent. This would look like this:
(The "input" can be accessed via p.getText())
#JsonComponent
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
#Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String stringValue = p.getText();
// Use your parser instead of this
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("yyyy[-MM-dd HH:mm:ss]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter();
return LocalDateTime.parse(stringValue, formatter);
}
}
I have a problem with date format in JSON response generated in REST project (SpringBoot+Hibernate).
When I call function I got JSON like this:
"rezerwacjaDataOd": 1535580000000,
"rezerwacjaDataDo": 1535839200000,
"rezerwacjaGodzOd": "14:00:00",
"rezerwacjaGodzDo": "12:00:00"
my entity:
private Date rezerwacjaDataOd;
private Date rezerwacjaDataDo;
private Time rezerwacjaGodzOd;
private Time rezerwacjaGodzDo;
It's Date from java.sql and Time from java.sql too
My controller:
#RestController
#CrossOrigin
#RequestMapping("api/rezerwacja")
#Api
public class RezerwacjaController {
...
#GetMapping(value = "/getRezerwacjaById")
public #ResponseBody
Rezerwacja getRezerwacjaById(Integer id) {
return rezDao.findOne(id);
}
...
Why Time is in "12:00:00" format, but Date in 1535580000000 format?
How to make Date to be in "yyyy-MM-dd" format?
You should do two things
add spring.jackson.serialization.write-dates-as-timestamps:false in your application.properties this will disable converting dates to timestamps and instead use a ISO-8601 compliant format
You can then customize the format by annotating the getter method of you dateOfBirth property with #JsonFormat(pattern="yyyy-MM-dd")
The differences in the way hibernate persists the date/time objects in the database have to do with the way these objects are used.
Per the documentation Time is a thin wrapper around Date that allows the underlying JPA provider to save the date object using the convention your noticed.
On the other hand, the Date object you pass in is converted directly to a timestamp and gets saved this way.
In both cases you can retrieve the value in question and serialize over to the desired format (with ISO-8601 being the best).
Another solution, other than the one mentioned above, is to create a custom serializer to do this.
A simple implementation would be:
public class Iso8601Serializer extends StdSerializer<Date> {
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
public Iso8601Serializer() {
this(null);
}
public Iso8601Serializer(Class clazz) {
super(clazz);
}
#Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
if (date == null) {
jsonGenerator.writeNull();
} else {
jsonGenerator.writeString(DateFormatUtils.format(date, ISO_8601_FORMAT));
}
}
}
Also (and this is a personal thing), I would advise in using plain Date objects to store dates and futhermore, have the respective fields annotated as #Temporal.
Actually I try to invoke a get request with the restTemplate in Spring. Debbuging my application clearly shows that the JSON is downloaded but the automatic mapping does not work. My List of domain object includes only 0 values and null values.
When I invoke the get request from the browser, I get the following response as JSON (I copied here the first two record out of the 3 192):
[{"OrderId":77862,"DateAdded":"2016-04-30T02:25:40.263","OrderItemCorpusId":"HUBW","OrderItemCorpusOriginalId":null,"OrderItemCurrency":"HUF","OrderItemExchangeRate":1.00000,"OrderItemOriginalLocation":"HU","OrderItemBuyLocation":"HU","OrderItemPrice":1337.80314,"OrderItemDiscountId":0,"OrderItemDiscountValue":"","DocumentId":25140,"Title":"Romana Gold 10. kötet","PublisherOriginalName":"Harlequin Kiadó","ISBN":"9789634073369"},{"OrderId":77864,"DateAdded":"2016-04-30T15:49:22.61","OrderItemCorpusId":"HUBW","OrderItemCorpusOriginalId":null,"OrderItemCurrency":"HUF","OrderItemExchangeRate":1.00000,"OrderItemOriginalLocation":"HU","OrderItemBuyLocation":"HU","OrderItemPrice":2748.03149,"OrderItemDiscountId":0,"OrderItemDiscountValue":"","DocumentId":25252,"Title":"Az eltűnt lány","PublisherOriginalName":"Harlequin Kiadó","ISBN":"9789634072423"}]
My POJO domain object which should keep the converted data from JSON:
#JsonIgnoreProperties(ignoreUnknown = true)
public class BandWTransaction {
private long OrderId;
private Date DateAdded;
private String OrderItemCurrency;
private double OrderItemExchangeRate;
private String OrderItemBuyLocation;
private double OrderItemPrice;
private String OrderItemDiscountValue;
private long DocumentId;
private String Title;
private String PublisherOriginalName;
private String ISBN;
//getters and setters
Finally the code snippet I use for the rest get request:
String startDate = new SimpleDateFormat("yyyy-MM-dd").format(start.getTime());
String endDate = new SimpleDateFormat("yyyy-MM-dd").format(end.getTime());
UriComponents uri = UriComponentsBuilder.newInstance().scheme("http").host("www.bookandwalk.hu")
.path("/api/AdminTransactionList").queryParam("password", "XXX")
.queryParam("begindate", startDate).queryParam("enddate", endDate).queryParam("corpusid", "HUBW")
.build().encode();
LOG.log(Level.INFO, "{0} were called as a rest call", uri.toString());
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set("User-Agent", "Anything");
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<List<BandWTransaction>> transResponse = restTemplate.exchange(uri.toString(), HttpMethod.GET,
entity, new ParameterizedTypeReference<List<BandWTransaction>>() {
});
List<BandWTransaction> transactions = transResponse.getBody();
When I debug the app I realized that the transactions list includes objects with full of null and 0 values. More precisely, there is no and objcet within the list having other values as 0 and null in the properties.
I have also checked that spring boot automatically registered in the restTemplate.messageConverters ArrayList 9 HttpMessageConverter. The 7th element of this ArrayList is the org.springframework.http.converter.json.MappingJackson2HttpMessageConverter which supports the application/json and application/+json media types.
Any idea is appreciated to solve this problem as I am newbie in spring and in JSON mapping in general.
It seems you have a naming convention issue due to your field variables starts with a uppercase. When Jackson finds a pair getTitle/setTitleasumes that the name of this variable is title (starting with lowercase). Of course, if you change the capitalization of your variables, json properties and java variables has different names, so mapping still fails. The best solution is change your names to meet Java conventions, and use Jackson annotations to define your mappings.
#JsonProperty(value="OrderId")
private int orderId;
#JsonProperty(value="DateAdded")
private Date dateAdded;
Hope it helps.
I can suggest you to write a test and check how fasterxml ObjectMapper read a json and unmarshall json to your object:
ObjectMapper objectMapper = new ObjectMapper();
String somestring = objectMapper.readValue("somestring", String.class);
just replace String with your class and "somestring" with your json. So you check if there is problem with it.
And try to use #JsonPropery cause all this capital letters fields start with looks messy:
#JsonIgnoreProperties(ignoreUnknown = true)
public class BandWTransaction {
#JsonProperty("OrderId")
private long OrderId;
[...]
With this stuff I read json correct. You can come in from other side remove ignoring unknown properties:
#JsonIgnoreProperties(ignoreUnknown = true) //remove it and run test
public class BandWTransaction {
and you get :
(11 known properties: "dateAdded", "orderItemExchangeRate",
"documentId", "orderItemPrice", "orderId", "orderItemBuyLocation",
"orderItemDiscountValue", "orderItemCurrency", "isbn", "title",
"publisherOriginalName"])
So problem in variables naming and you can fix it with #JsonProperty
I'm using Jackson (via Spring MVC Annotations) to deserialize a field into a java.util.Date from JSON. The POST looks like - {"enrollDate":"2011-09-28T00:00:00.000Z"}, but when the Object is created by Spring & Jackson it sets the date as "2011-09-27 20:00:00".
How can I set the proper timezone in Jackson?
Or if that is not the problem, how do I send EST from the JSON message?
Javascript/jQuery:
var personDataView = { enrollDate : new Date($("#enrollDate").val()),
//...other members
};
$.postJSON('/some/path/', personDataView, function(data){
//... handle the response here
});
JSON Message:
{"enrollDate":"2011-09-28T00:00:00.000Z"}
Spring Controller:
#RequestMapping(value="/", method=RequestMethod.POST)
public #ResponseBody String saveProfile(#RequestBody personDataView persondataView, HttpServletRequest request)
{
//...dataView has a java.util.Date enrollDate field
//...other code
}
In Jackson 2+, you can also use the #JsonFormat annotation:
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone="America/Phoenix")
private Date date;
If it doesn't work this way then try wrapping Z with single quotes, i.e. pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
Have you tried this in your application.properties?
spring.jackson.time-zone= # Time zone used when formatting dates. For instance `America/Los_Angeles`
If you really want Jackson to return a date with another time zone than UTC (and I myself have several good arguments for that, especially when some clients just don't get the timezone part) then I usually do:
ObjectMapper mapper = new ObjectMapper();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("CET"));
mapper.getSerializationConfig().setDateFormat(dateFormat);
// ... etc
It has no adverse effects on those that understand the timezone-p
I am using Jackson 1.9.7 and I found that doing the following does not solve my serialization/deserialization timezone issue:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
objectMapper.setDateFormat(dateFormat);
Instead of "2014-02-13T20:09:09.859Z" I get "2014-02-13T08:09:09.859+0000" in the JSON message which is obviously incorrect. I don't have time to step through the Jackson library source code to figure out why this occurs, however I found that if I just specify the Jackson provided ISO8601DateFormat class to the ObjectMapper.setDateFormat method the date is correct.
Except this doesn't put the milliseconds in the format which is what I want so I sub-classed the ISO8601DateFormat class and overrode the format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition)
method.
/**
* Provides a ISO8601 date format implementation that includes milliseconds
*
*/
public class ISO8601DateFormatWithMillis extends ISO8601DateFormat {
/**
* For serialization
*/
private static final long serialVersionUID = 2672976499021731672L;
#Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition)
{
String value = ISO8601Utils.format(date, true);
toAppendTo.append(value);
return toAppendTo;
}
}
Looks like older answers were fine for older Jackson versions, but since objectMapper has method setTimeZone(tz), setting time zone on a dateFormat is totally ignored.
How to properly setup timeZone to the ObjectMapper in Jackson version 2.11.0:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));
Full example
#Test
void test() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);
objectMapper.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));
ZonedDateTime now = ZonedDateTime.now();
String converted = objectMapper.writeValueAsString(now);
ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
System.out.println("serialized: " + now);
System.out.println("converted: " + converted);
System.out.println("restored: " + restored);
Assertions.assertThat(now).isEqualTo(restored);
}
`
Just came into this issue and finally realised that LocalDateTime doesn't have any timezone information. If you received a date string with timezone information, you need to use this as the type:
ZonedDateTime
Check this link
Your date object is probably ok, since you sent your date encoded in ISO format with GMT timezone and you are in EST when you print your date.
Note that Date objects perform timezone translation at the moment they are printed. You can check if your date object is correct with:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(date);
System.out.println (cal);
I had same problem with Calendar deserialization, solved extending CalendarDeserializer.
It forces UTC Timezone
I paste the code if someone need it:
#JacksonStdImpl
public class UtcCalendarDeserializer extends CalendarDeserializer {
TimeZone TZ_UTC = TimeZone.getTimeZone("UTC");
#Override
public Calendar deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken t = jp.getCurrentToken();
if (t == JsonToken.VALUE_NUMBER_INT) {
Calendar cal = Calendar.getInstance(TZ_UTC);
cal.clear();
cal.setTimeInMillis(jp.getLongValue());
return cal;
}
return super.deserialize(jp, ctxt);
}
}
in JSON model class just annotate the field with:
#JsonDeserialize(using = UtcCalendarDeserializer.class)
private Calendar myCalendar;
For anyone struggling with this problem in the now (Feb 2020), the following Medium post was crucial to overcoming it for us.
https://medium.com/#ttulka/spring-http-message-converters-customizing-770814eb2b55
In our case, the app uses #EnableWebMvc and would break if removed so, the section on 'The Life without Spring Boot' was critical. Here's what ended up solving this for us. It allows us to still consume and produce JSON and XML as well as format our datetime during serialization to suit the app's needs.
#Configuration
#ComponentScan("com.company.branch")
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2XmlHttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.defaultUseWrapper(false)
.createXmlMapper(true)
.simpleDateFormat("yyyy-mm-dd'T'HH:mm:ss'Z'")
.build()
));
converters.add(1, new MappingJackson2HttpMessageConverter(
new Jackson2ObjectMapperBuilder()
.build()
));
}
}