When saving a LocalDate
field (e.g. '2017-09-27') to a mySQL Date
column using JPA CriteriaBuilder API, the result is different (e.g. '2017-09-26').
I have validated that my database's timezone is set to UTC using SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)
as the result is '00:00:00'.
I am testing this locally, and I have a timezone of GMT + 2, so my suspicion is that when the conversion occurs from LocalDate
to Date
, 2 hours are being deducted and producing a date 1 day before the requested date (assuming that the LocalDate
field, as a result of it having no time information, is being treated as 00:00:00.
What is the best way to save LocalDates in this situation? Should I be following the advice here https://stackoverflow.com/a/29751575/3832047 and explicitly setting all LocalDate fields to UTC or something similar?
I ran a test to see what happens when converting them in code and got the following result:
Date convertedDate = Date.valueOf(localDate);
conversion-result
EDIT
Here is an example of the code I use to retrieve the data, where the odd date change occurs as well. If I request data for 2017-06-27
, I receive results for 2017-06-26
.
CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(HorseAndTrailerRequest.class);
Root<HorseAndTrailerRequest> criteria = criteriaQuery.from(HorseAndTrailerRequest.class);
ParameterExpression<LocalDate> effectiveDateParameter = criteriaBuilder.parameter(LocalDate.class);
criteriaQuery.select(criteria)
.where(
criteriaBuilder.equal(criteria.get("effectiveDate"), effectiveDateParameter)
);
TypedQuery<HorseAndTrailerRequest> query = sessionFactory.getCurrentSession().createQuery(criteriaQuery);
query.setParameter(effectiveDateParameter, date);
return query.getResultList();
MySQL retrieves and displays DATETIME values in ' YYYY-MM-DD hh:mm:ss ' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59' . The TIMESTAMP data type is used for values that contain both date and time parts.
You need to implement the AttributeConverter<LocalDateTime, Timestamp> interface and the converter needs to be annotated with the @Converter annotation. Similar to the LocalDateConverter, the conversion between a LocalDateTime and a java. sql. Timestamp is done with the conversion methods of Timestamp.
We can use COMMIT command to make the changes, made in a current transaction, permanently recorded in MySQL database. Suppose if we run some DML statements and it updates some data objects, then COMMIT command will record these updates permanently in the database.
For example, the value "2nd October 2007" can be stored in a LocalDate . This class does not store or represent a time or time-zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
Since LocalDate
has no TimeZone, you can map the column_date as long in your database schema, and use AttributeConverter
to convert LocalDate
to long to avoid time zone conversion problems :
import javax.persistence.Converter;
import java.time.LocalDate;
import javax.persistence.AttributeConverter;
@Converter
public class LocalDateToLong implements AttributeConverter<LocalDate, Long> {
@Override
public Long convertToDatabaseColumn(LocalDate date) {
if (date != null) {
long epochDay = date.toEpochDay();
return epochDay;
}
return null;
}
@Override
public LocalDate convertToEntityAttribute(Long epochDay) {
// TODO Auto-generated method stub
if (epochDay != null) {
LocalDate date = LocalDate.ofEpochDay(epochDay);
return date;
}
return null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With