Spring jackson:date-format formatting changes after upgrade - spring-boot

After upgrading from spring boot 1.2.6.RELEASE -> 1.3.1.RELEASE there seems to be a problem when using iso 8101 dateformat with timezone offset.
In my application.yml the jackson date-format is set to format with timezone offset
spring:
jackson:
date-format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
With boot 1.2.6 this results in datetime formats with the correct iso 8601 timezone format like 2014-01-01T23:01:01.010+01:00
But with boot 1.3.1 the format is kept in Zulu time zone
2014-01-01T22:01:01.010Z

By default Jackson uses GMT time zone. You can change it by adding to your configuration file:
spring:
jackson:
time-zone: Europe/Berlin
or change it for certain property by using
public class DateStuff {
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:00", timezone="CET")
public Date creationTime;
}
Jackson FAQ: Date Handling

With thanks to #dimuha I figured it out. You have to add the time-zone property too to have the same behavior as before the upgrade
spring:
jackson:
date-format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
time-zone: Europe/Berlin
This will output 2014-01-01T23:01:01.010+01:00 iso 8601 dates.

Related

Cockroach Db with Spring Boot

While using Coacroach Db with Spring Boot and Spring Batch, I am getting the following error.
org.postgresql.util.PSQLException: ERROR: invalid value for parameter "TimeZone": "Europe/London"
Detail: The system cannot find the path specified.
Application.properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
spring.datasource.username=root
spring.datasource.password=
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.jpa.properties.hibernate.jdbc.time_zone= UTC
spring.batch.initialize-schema = always
I also added this and above properties as mentioned somewhere but didn't help.
#PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
Out of curiosity, which operating system are you using? We have an open issue relating to timezones, which is known to affect Windows.
When you specify the UTC timezone, do you receive the same error as you do with "Europe/London"? What if you try using a numerical offset, like "+0:00"?
Also, when setting the timezone through the URL, the parameter should be timezone=utc (or whichever other value you want).
So see a number of issues.
1. You said you are using Coacroach Db but you seem to be loading a JDBC JAR and ULR string for Postgres.
2. Posgres does not have "Europe/London" as a valid TimeZone String. There is a "Europe/London GB GB-Eire"
See: https://www.postgresql.org/docs/8.1/datetime-keywords.html
3. You have a space in the time zone property name.
This: spring.jpa.properties.hibernate.jdbc.time_zone= UTC
Should Be: spring.jpa.properties.hibernate.jdbc.time_zone=UTC

How to convert from Instant to LocalDate

I have an Instant coming from a source that should, according to the specs, be a LocalDate, but don't see any methods in the LocalDate class to convert the Instant to a LocalDate.
What is the best way to do this?
Java 9+
LocalDate.ofInstant(...) arrived in Java 9.
Instant instant = Instant.parse("2020-01-23T00:00:00Z");
ZoneId zone = ZoneId.of("America/Edmonton");
LocalDate date = LocalDate.ofInstant(instant, zone);
See code run live at IdeOne.com.
Notice the date is 22nd rather than 23rd as that time zone uses an offset several hours before UTC.
2020-01-22
Java 8
If you are using Java 8, then you could use ZonedDateTime's toLocalDate() method:
yourInstant.atZone(yourZoneId).toLocalDate()
Other answers provided the mechanics for the transformation, but I wanted to add some background on the meaning of such transformation which hopefully helps explain why it works the way it works.
LocalDate and Instant seem similar – they both hold date(/time) information without the time zone information. However, they have quite a different meaning.
Instant represents a point in time unambiguously. The representation does not explicitly contain any time zone, but implicitly it refers to the UTC time line.
LocalDateTime (and LocalDate) is ambiguous, because it represents a point in the local timeline, which implicitly refers to the local time zone.
So, in order to correctly transform an Instant into a LocalDateTime (conceptually – some of these steps are bundled together into a single operation in the implementation) you need to:
1. convert the Instant into a ZonedDateTime by applying the UTC time zone info
2. change the time zone from UTC to the local time zone (which implies applying the relevant time zone offset) which gives you another ZonedDateTime (with different time zone)
3. convert the ZonedDateTime into a LocalDateTime which makes the time zone implicit (local) by removing the time zone info.
Finally, you can drop the time-part of LocalDateTime and end up with the LocalDate.
If using java 8 you can do the following
Instant instantOfNow = Instant.now();
LocalDate localDate
= LocalDateTime.ofInstant(instantOfNow, ZoneOffset.UTC).toLocalDate();
You need to ask yourself at what zone offset you want to transform it to most probably and when you know the answer to that:
LocalDate.ofInstant(yourInstant, yourZoneOffSet)
EDIT
just realized that this is only possible since java-9, for a pre-java9 see the other answer
Complete running example, Java 8 compatible:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
class Scratch {
public static void main(String[] args) {
Instant now = Instant.now();
LocalDateTime ldt = now.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(ldt);
}
}
Instant instant = Instant.now();
LocalDate localDate = LocalDate.ofInstant(instant, ZoneOffset.UTC);
the above code worked for me.

App Engine logging.properties: customize Date format for lazy-evaluation Log

I have a very simple code
Logger logger = Logger.getLogger(HelloAppEngine.class.getName());
logger.log(Level.INFO, "This is now: {0}", new Date());
defined inside a (Maven based) Google App Engine project.
The output of this log is
giu 10, 2017 6:03:10 PM it.log.HelloAppEngine doGet
INFO: This is now: 10/06/17 18.03
with the default Date format. I want to customize the Date format with my own.
I don't really know where this configuration need to be placed, I think that can be inside the logging.properties file, but I'm unable to find the proper cofniguration
Which is the proper way to customize the Date format provided by the lazy-evaluted log message?
I found the relevant code inside the java.text.MessageFormat class.
which is triggered to format the Date object
It does not seem that is accessing to an external configuration in order to format the date, it uses a fixed DateFormat.SHORT format. Maybe there is a way to provide a custom formatter which will override that entire implementation.
I want to customize the Date format with my own.
I don't really know where this configuration need to be placed, I think that can be inside the logging.properties file, but I'm unable to find the proper configuration
You have to include the date format in the log string as described in the java.text.MessageFormat class level docs. As stated there you can use any of the java.text.SimpleDateFormat patterns.
For example, you can use the DateFormat constants:
logger.log(Level.INFO, "This is now: {0,date,long} at {0,time,full}", new Date());
Otherwise, you can use a pattern:
logger.log(Level.INFO, "This is now: {0,date,EEE, MMM dd HH:mm:ss:S ZZZ yyyy}", new Date());
If you use localization in your logging you can replace the messages with a shorter key and leave the date format patterns in your ResourceBundle.

Jackson is changing date to one day old in spring boot rest application.

I have created a simple application with spring boot 1.5.2. I am passing date and already mentioned the date format in application.properties file as follwoing :
spring.jackson.joda-date-time-format=yyyy-MM-dd
But while calling the rest rest service using any client for POST(Insert) or PUT(Update), date is changing to on day old. Example 2017-03-21 will change to 2017-03-20.
I had the same issue and I solved it in that way:
In your entitiy, add theses annotations:
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, locale = "fr-FR", timezone = "Europe/Paris")
private Date yourDate;
Or you can add theses line to application.properties file:
spring.jackson.time-zone=Europe/Paris
spring.jackson.locale=fr_FR
If you are in another country you can change locale and timezone, but even if you keep France, it will work.
Just set the timezone to UTC like below
SpringApplication.run(Application.class, args);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
It solved my problem.

#DateTimeFormat in Spring produces off-by-one day error

I am currently using #DateTimeFormat in a domain object as follows:
#DateTimeFormat(pattern = "MM/dd/yyyy")
private Date startDate = new Date();
In a Spring MVC Controller, I am posting today's date: 10/19/2011 using the jQuery UI Date picker, and I confirm that this is being sent as an HTTP Post parameter using firebug as follows:
startDate=10%2F19%2F2011
Unfortunately, once it gets to Spring on the server, it stores the date as 10/18/2011 - there is an off-by-one day error.
There is nothing in my code that even remotely touches the date - there is no calculations or anything going on with regards to this date.
Is there something about #DateTimeFormat that I should be aware of?
Could something in Hibernate be responsible for changing the date too?
I'm also looking at the my database for this application. I am storing another date, called creationDate which is an actual timestamp and differs from user input. In most cases, the dates are the same but the client wanted the ability to set it differently so that is what startDate is for.
Start Date Creation Date (actual timestamp, not user input)
2011-04-17 19:00:00 2011-04-17 21:32:27
2011-04-18 19:00:00 2011-04-18 21:14:01
2011-04-20 19:00:00 2011-04-20 23:06:47
2011-04-26 19:00:00 2011-04-26 23:24:34
2011-04-28 19:00:00 2011-04-28 20:07:06
2011-05-01 19:00:00 2011-05-02 13:35:37
2011-06-21 19:00:00 2011-06-22 15:06:36
2011-07-28 19:00:00 2011-07-29 15:32:35
2011-09-03 19:00:00 2011-09-04 13:11:45
2011-10-11 19:00:00 2011-10-12 11:45:14
2011-10-11 19:00:00 2011-10-12 11:49:55
2011-10-18 19:00:00 2011-10-19 02:20:43
At first it seems like it was a bug started in May, but then I realized that the date is correct if it was over 19:00:00, and it's off-by-one if it's under 19:00:00.
I hate Java :(
The problem seems to occur when Spring creates a date given 10/19/2011 - it seems to translate that user input and formats it to 2011-10-18 19:00:00.
What is the simplest solution?
Thanks
It seems very likely to me that this is actually a matter of time zones. A Date object represents an instant in time - I suspect if you look at the exact value that you've got (e.g. in UTC, to keep things clear) you'll get a better idea of what's going on. Chances are that where you're seeing "10/18/2011" you're interpreting it in a different time zone.
If Spring supports converting to Joda Time types I'd suggest using that instead - then you can use LocalDate which really does mean a date instead of an instant in time.
I've found that starting your JVM with your local timezone specified in the arguments solves this issue. For me it was just adding this line to the run configuration:
-Duser.timezone="Asia/Dhaka"

Resources