1

I am using a MyBatis ORM to interact between my Java 11 application and the MySql database. When I want to insert date objects (tried java.time.LocalDate and java.sql.Date) to the table (column has jdbc type DATE), all dates are shifted backwards by 1 day.

Pseudo-Example:

Entry entry1 = new Entry("John", LocalDate.of(2019,4,29))
Entry entry2 = new Entry("John", Date.valueOf("2019-04-29"))

Both of these will be stored as follows in the sql table.

user  |date       |
------|-----------|
John  |2019-04-28 |

The mysql server uses UTC, the application may run on different timezones (GMT+1, GMT+2) but this shouldn't consistently shift dates, should it?

The java class:

public class Entry {
    public String user;
    public LocalDate date;
}

The MyBatis mapper and Service:

import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserEntryMapper {
    void saveEntry(@Param("entry") Entry entry);
}

public class UserEntryService {
    private final UserEntryMapper userEntryMapper;

    @Inject
    public UserEntryService(UserEntryMapper dbMapper){
        this.userEntryMapper = dbMapper;
    }

    @Transactional
    public void saveEntry(Entry entry) {
        userEntryMapper.saveEntry(entry);
    }
}

The MyBatis xml:

<insert id="saveEntry">
   INSERT INTO `user_entry_list`
   (`user`, `date`)
   VALUES
   (#{entry.user}, #{entry.date, jdbcType=DATE});
</insert>

EDIT: I tried instantiating the java.util.Date differently:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2019);
cal.set(Calendar.MONTH, Calendar.APRIL);
cal.set(Calendar.DATE, 29);
cal.set(Calendar.HOUR_OF_DAY, 0);
java.util.Date date = cal.getTime();

Indeed, this still results in 2019-04-28. However, if I put cal.set(Calendar.HOUR_OF_DAY, 2), then the correct date is saved. This means java.util.Date and LocalDate are implicitly setting a time at midnight... : /

Damian
  • 79
  • 1
  • 11
  • Just a quick guess: If the timestamp by "Date.valueOf" is based on the date with 12 AM, a shift to the UTC would be e.g. -1 or -2 hours, which leads to one day off. Instead of 2019-04-29 00:00:00 you will get 2019-04-28 22:00:00 – Enak Apr 29 '19 at 07:30
  • Look at [this question](https://stackoverflow.com/questions/25113579/java-8-localdate-mapping-with-mybatis), it might help you. – Joakim Danielson Apr 29 '19 at 07:31
  • @Enak I suspected something similar. but `java.sql.Date.valueOf()` takes the string representation of a date, not a timestamp. It would be strange if this is converted internally to a timestamp – Damian Apr 29 '19 at 07:38
  • 1
    @JoakimDanielson, I am using the current version of mybatis which should have support for these classes included (Type handlers for "JSR 310: Date and Time API" has been merged into mybatis core since 3.4.5) – Damian Apr 29 '19 at 07:51
  • 1
    @Damian Maybe just give it a try. Get your date by using `Date.valueOf` and use `setHours(int i)` to set the value to e.g. 8 AM, insert it into the table and check what happened. AFAIK a java.sql.date is just a wrapper for a timestamp, so it could still be a conversion problem. See https://docs.oracle.com/javase/7/docs/api/java/sql/Date.html – Enak Apr 29 '19 at 08:24
  • @Enak Thanks for the hint, added the test case to the question – Damian Apr 29 '19 at 12:25
  • i want you to think about this sentence really hard : "`The mysql server uses UTC, the application may run on different timezones (GMT+1, GMT+2) `" – specializt Apr 30 '19 at 06:37

1 Answers1

0

Try adding serverTimezone=GMT%2B1 to the JDBC connection URL. e.g.

jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B1

UPDATE
This seems like a bug, actually.
https://bugs.mysql.com/bug.php?id=93444

ave
  • 3,244
  • 2
  • 14
  • 20