When system running JVM uses JST (or perhaps happen in not UTC system), LocalDate
column is not saved right value to database (MySQL). It is one day ago date. I use JDBC.
I investigate this symptom, I found some things.
In spring boot, when write to database, LocalDate
is converted to Date
and its locale is system's.
// in BasicRelationalPersistentProperty.java
private static final Map<Class<?>, Class<?>> javaToDbType = new LinkedHashMap<>();
static {
javaToDbType.put(Enum.class, String.class);
javaToDbType.put(ZonedDateTime.class, String.class);
javaToDbType.put(Temporal.class, Date.class);
}
// in Jsr310Converters.java
@WritingConverter
public static enum LocalDateToDateConverter implements Converter<LocalDate, Date> {
INSTANCE;
@Nonnull
@Override
public Date convert(LocalDate source) {
return Date.from(source.atStartOfDay(systemDefault()).toInstant());
}
}
But, when Date
is converted to String
to build query, JDBC uses US locale. It sometimes mismatches to origin Date
's TZ. (This code may not be in spring-boot)
// in com.mysql.cj.util.TimeUtil.java
public static SimpleDateFormat getSimpleDateFormat(SimpleDateFormat cachedSimpleDateFormat, String pattern, Calendar cal, TimeZone tz) {
SimpleDateFormat sdf = cachedSimpleDateFormat != null ? cachedSimpleDateFormat : new SimpleDateFormat(pattern, Locale.US); // here(cachedSimpleDateFormat is null in the first and initialize here.)
if (cal != null) {
sdf.setCalendar((Calendar) cal.clone()); // cloning the original calendar to avoid it's modification
}
if (tz != null) {
sdf.setTimeZone(tz);
}
return sdf;
}
So, I suggest to prepare LocalDateToStringConverter
not to be affected system. Because LocalDate
dosen't have locale, LocalDate
should not be converted to Date
which has locale.
Comment From: bclozel
This code lives in Spring Data Commons, so this can't be fixed in Spring Boot directly.
Could you create an issue on the relevant tracker please? Unfortunately, I can't transfer this issue automatically as Spring Data is not using GitHub for issues.
Thanks!
Comment From: sasurai-usagi3
[NOTE] I notice this code can resolve this problem.
package hoge
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import java.util.*
@SpringBootApplication
class HogeApplication
fun main(args: Array<String>) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC")) // add this code
runApplication<HogeApplication>(*args)
}