Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop LocalDate from changing when being saved to a mySQL database

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();
like image 980
Phobos Avatar asked Sep 27 '17 11:09

Phobos


People also ask

How are Datetimes stored in MySQL?

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.

How to persist LocalDate and LocalDateTime with JPA?

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.

Can we make the changes to the data stored in MySQL?

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.

Does LocalDate store time?

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.


1 Answers

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;
    }

}
like image 200
SEY_91 Avatar answered Sep 28 '22 15:09

SEY_91