Timezone issue in Spring Boot JPA application - mysql

I am facing date time issue in my spring boot jpa application.
For example, In my database I have one column created_on which contains 2019-07-11 09:30:00 date.
When I fetch this record threw JPA it converts to UTC.
Means date 2019-07-11 09:30:00 converts to 2019-07-11 05:00:00.
My System time is in IST and date is saved in database in IST as well.
I am using mysql database.
In my Enitity
private Date createdOn;
Database column:
created_on timestamp
Service:
#Service
#Transactional(readOnly = true)
public class EntityTypeService {
#Autowired
private IEntityTypeRepository entityTypeRepository;
public EntityType findById(Long id) {
EntityType entityType = entityTypeRepository.findById(id).orElse(new EntityType());
System.out.println(entityType.getCreatedOn());
return entityType;
}
}
Repository
#Repository
public interface IEntityTypeRepository extends CrudRepository<EntityType, Long> {
}
Date in database is 2019-07-11 09:30:00
But when I print it on service System.out.println(entityType.getCreatedOn()); it gives me 2019-07-11 05:00:00.
This is generic issue in my whole application.

After so much research I found the solution.
Actually issue was because of
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
this property which I have set in my appication.properties.
When I removed this property everything works fine at the backend. Backend showing the perfect time which is available in database.
But now when response comes to frontend, at that time my date gets converted to UTC.
Like backend it's showing 2020-06-03 18:56:14.0 and when it comes to front end it converts to 2020-06-02T13:26:14.000+0000.
Which is also an issue for me.
So after some more research I found that Jackson by default converts all date to UTC when object send to frontend.
The solution to this problem is
spring.jackson.time-zone=IST
My Database and System timezone is IST so I have set IST to jackson timezone too which solves the problem.
Hope this answer may help someone.

You can set timezone for in database connection using serverTimezone eg:Asia/Kolkata and use useLegacyDatetimeCode=false
spring.datasource.url= = jdbc:mysql://127.0.0.1/db_name?useLegacyDatetimeCode=false&serverTimezone=Asia/Kolkata
And don't use legacy class Date rather use modern class LocalDateTime

When working on JPA + Spring Boot for a backend application, make sure to use same TimeZone through out server configuration. For example, to use UTC do as below:
On server OS level: sudo timedatectl set-timezone UTC (for example on Cent OS)
On MySQL / Database server in my.cnf file (optional)
Spring config: spring.jpa.properties.hibernate.jdbc.time_zone=UTC
MySQL URL query parameters spring.datasource.url=jdbc\:mysql\://localhost\:3306/my_db_name?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useLegacyDatetimeCode=false
And if you are using Jackson JSON framework you can automatically parse DateTime value to String format using #JsonFormat(shape= JsonFormat.Shape.STRING, pattern="dd MMM yyyy HH:mm:ss") on the entity property / field.
Application entry point #SpringBootApplication
#PostConstruct public void init(){ TimeZone.setDefault(TimeZone.getTimeZone("UTC")); }
This should cover most of the implementation challenges while work on Dates and Timestamps. Hope that it helps.

Try to avoid using Date for timestamps in time zones because it is not designed to handle these in a good way.
You could try to print the date object with a formatter or use LocalDateTime (or ZonedDateTime if time zones are important to you) instead.

You may try putting #DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") on createdOn setter.

Related

MySQL Date column returns from REST call with incorrect time

I have a MySQL table containing a DATETIME column, my_date.
This column is defined in my domain object as type java.util.Date and annotated as Temporal:
#Entity()
#Table(name="Thing")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Thing {
...
#Column(name="my_date", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date myDate;
...
}
The current my_date column value in the db is 2022-07-17 12:34:56, per MySQL Workbench.
I have a pretty straightforward REST endpoint, created using Spring JPA, that for some reason pulls that value as:
...
"myDate": "2022-07-17T19:34:56.000+00:00"
...
Why would the time portion return with a value 7 hours later than is showing in the database?
Update: I'm actually using MariaDB (10.7.3-MariaDB). Not sure if that's relevant here, but it just dawned on me, so mentioning it just in case that somehow could be the cause of the time portion getting offset.
I think it is the timezone problem, you can add code like below to Dockerfile for container of Mysql or you app
RUN rm /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
update 1
according to https://javabydeveloper.com/temporal/
The mapping between the Java 8 Date/Time classes and the SQL types is implicit, there is not need to specify the #Temporal annotation.
try remove #Temporal annotation
update 2
Is java.sql.Timestamp timezone specific?
https://stackoverflow.com/a/14070771/16702058
For example: Your local time zone is GMT+2. You store "2012-12-25 10:00:00 UTC". The actual value stored in the database is "2012-12-25 12:00:00". You retrieve it again: you get it back again as "2012-12-25 10:00:00 UTC" (but only if you retrieve it using getTimestamp(..)), but when another application accesses the database in time zone GMT+0, it will retrieve the timestamp as "2012-12-25 12:00:00 UTC".

Hibernate store YearMonth in MySQL as Blob instead of text

A Spring Boot 2.3.0 Project is Storing Data in MySQL 8.0. (jdk 9)
A JPA Class has Java 8 YearMonth field
#Data
#Entity
public class Version {
...
private YearMonth releaseDate;
private LocalDateTime createdAt;
When I persist an instance of version, it's stored like this:
As You can see LocalDateTime gets stored as text but YearMonth as Blob. Now When I get back the entity it works fine and I do get YearMonth value.
The problem is that I cannot read it through MySQL Workbench. And I know that EclipseLink (official implementation of JPA) does persist YearMonth as Text.
How Can I store it as Text and not BLOB?

MySQL/Hibernate: getting value +1H on insert type Time

I'm working on a java web project that uses:
Hibernate 5.2.2/JPA 2.0+ MySQL5InnoDBDialect
MySQL 5.6.15-innoDB (on EasyPHP/PHPMyAdmin) + JDBC connector 6.0.4
Joda time API 2.9.4 + Fasterxml jackson API 2.8.3
I'm facing a problem on inserting Time data on database. everytime i put a row, i get a +1H value on time column!
Attribute on Java:
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="HH:mm")
#Column(name = "RES_DUREE", nullable = false)
#Temporal(TemporalType.TIME) private Date resDuree;
Attribute on SQL:
RES_DUREE TIME NOT NULL;
EDIT (After Adrian Shum's Comment):
Connection line:
jdbc.url =
jdbc:mysql://localhost:3306/mydb?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
I do use UTC but it still 1H+ .
Any suggestion will help, thanks.
Normally it is caused by server and DB time zone mismatch.
In brief, java.util.Date does not contain Timezone information. Conceptually you can treat it as simply representing Date + Time (similar to what JODA/JSR310 LocalDateTime is doing). Therefore if your app server is UTC+10, and your DB is UTC+2, when you save a date of "2016-10-13 10:11:12", although your app server is treating it as "2016-10-13 10:11:12 +10:00", it is simply passing "2016-10-13 10:11:12" to DB. Given DB is UTC+2, it is thinking the time actually means "2016-10-13 10:11:12 +02:00". Situation become more messy if your JDBC connection is claimed to be "UTC+10", most DB is going to "smartly" translate "2016-10-13 10:11:12 +02:00" to "2016-10-13 18:11:12 +10:00" which caused weird time stored and retrieved.
You may diagnose by tracing the SQL (and the actual value used) for corresponding inserts and select. You should see discrepancies between the values, vs the value stored in table. Such tracing can be done by misc way, e.g.
Older version of Hibernate can show the parameter used in prepared statement by turning on proper logger
You may use tools like JdbcDsLog (Disclaimer: I am maintainer for a fork of JbdcDsLog at http://github.com/adrianshum/jdbcdslog)
There is probably tools in DBMS side to trace incoming queries.
Best way to solve is to make sure everything is in the same timezone, and the most rational choice for timezone is UTC.

Storing milliseconds in MySQL timestamp column using Hibernate

I'm trying to store a java Date with milliseconds in MySQL's timestamp column using Hibernate, but the millisecods are stored always as .000.
The definition of the column in hibernate is as follows:
#Type(type="timestamp")``
private Timestamp timestamp;
In DB the column is declared as TIMESTAMP(3)
I've tried different combinations, including Date, but neither helped.
I use MySQL 5.6.25, Connector/J version 5.1.37, Hibernate 4.0.1.
I've been investigating it for a while, but still couldn't find any solution that works form me.
ANy help will be appreciated.
Have you tried using DATETIME(3) or TIMESTAMP(4)? I believe both of these will give you the milliseconds. If you are trying to get the millisecond time where the interatction happens such as the row becomes updated you can use ON UPDATE DATETIME(3)
It seems that Hibernate and MySql interaction removes de milliseconds precision of your Date/Timestamp Java property. I have the same problem.
My solution is to "hack" hibernate telling that the entity property is an string and then serializing/deserializing the value in the setter/getter
#Column(name="time")
private String time
...
public Date getTime(){
return strTodate( this.time );
}
public void setTime(Date value){
this.time = dateToStr( value );
}
When MySQL receives an String for a Datetime(3) column, string is properly converted and milliseconds are not lost :-)
Fortunately, when reading from MySQL, Datetime(3) is propery serialized to string without milliseconds lost
The string date format used is "yyyy-MM-dd hh:mm:ss.SSS"
The idea of this solution is, don't let hibernate deal with dates. Delegate the responsability to MySql.
Unfortunatelly, MySQL doesn't accept an standard ISO string (i.e.: "yyyy-MM-ddThh:mm:ss.SSSZ") and this solution is not compatible with postgres (string date format is not the same)

How do i map a sql Time type to a java type using hibernate?

I've got a sql data type of TIME. Now, the data for 12:00 AM is stored as 00:00:00.
In the POJO that is mapped to the table, I have given the datatype as java.util.Date as per the hibernate specification. However, on loading a row that has the data type 00:00:00 i get this exception.
Cannot convert value '00:00:00' from column 18 to TIMESTAMP
How do I solve this?
For SQLServer you can use something like this. It should also work for time types I guess.(I don't know if it changes for other DB types)
private Date lockedUntil;
#Column(name="DATE", columnDefinition="DATETIME")
#Temporal(TemporalType.TIMESTAMP)
public Date getDate() {
return date;
}