spring-data-mongodb
spring-data-mongodb copied to clipboard
Java LocalTime read converter and write converter problem
Hello
I have saved some time series data in a field type LocalTime.
When a LocalTime type field saved into MongoDB collection, it is saved as in MongoDB data type "date" which is in the form of ISO Date. However, the date part and the time part are the compulsory of MongoDB data type "date" so when LocalTime is saved, rubbish date part is included. Now the write converter put the rubbish date part is creation date of the object.
For example, when "14:21:12" LocalTime is saved, MongoDB collection data is saved by the form "2022-03-01 14:21:12".
so far, there is no problem.
But when find by LocalTime for a field, there is a problem. If the spring application is running on different date to the creation of the MongoDB date field which the time information saved, the MongoDB query generated with different date to the stored MongoDB date, so finding the time part of the date can't be matched which it should be founded.
For example, on the date 2022-03-01 document -> { editDate: 2022-03-01 14:21:12 }
on the date 2022-03-02 finding the above document, if I find "14:21:12", finding query is generated as "{editDate: ISODate('2022-03-02 14:21:12')}", so the document can't be founded properly
Spring Data MongoDB should create a query "{editDate: ISODate('%%%%-%%-%% 14:21:12')}". % means one digit number 0 to 9
Thank you.
I write custom LocalTime converter classes to make "find" query correctly
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.core.convert.converter.Converter;
public class LocalTimeWriteConverter implements Converter<LocalTime, Date> {
@Override
public Date convert(LocalTime localTime) {
LocalDateTime ldt = LocalDateTime.of(1970, 1, 1,
localTime.getHour(), localTime.getMinute(), localTime.getSecond());
ZonedDateTime zdt = ldt.atZone(TimeZone.getDefault().toZoneId());
return Date.from(zdt.toInstant());
}
}
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.core.convert.converter.Converter;
public class LocalTimeReadConverter implements Converter<Date, LocalTime> {
@Override
public LocalTime convert(Date date) {
ZonedDateTime zdt = date.toInstant().atZone(TimeZone.getDefault().toZoneId());
return LocalTime.of(zdt.getHour(), zdt.getMinute(), zdt.getSecond());
}
}
Have you already tried using the driver native time codec? It can be enabled via MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs().
If you have the time, it would be great it you could provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.
Have you already tried using the driver native time codec? It can be enabled via
MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs().If you have the time, it would be great it you could provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.
I have tried to use the default LocalTime converter.
The problem is LocalTime is saved with current date. which the date should be fixed like LocalDate's time. It caused a problem when I find the date by time only.
Using the native java.time codecs by setting MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs() fixes the date to the Java epoch 1970-01-01 and thereby avoids the problem you were seeing.