I need to be able to Store and Retrieve LocalDateTime properties on my sqlite database using Rooms TypeConverters.
After some researching I implemented the below converter. However, this converter appears to only store the default date time (1970-01-01). So isn't converting correctly Does anyone have a working LocalDateTime Converter? or have any improvements for this one?
public class LocalDateTimeConverter {
@TypeConverter
public static LocalDateTime toDate(Long timestamp) {
LocalDateTime ldt;
if (timestamp == null){
return null;
}else{
ldt = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
return ldt;
}
@TypeConverter
public static Long toTimestamp(LocalDateTime date) {
if (date == null){
return null;
}else {
return date.getLong(ChronoField.CLOCK_HOUR_OF_DAY);
}
}}
Room typically stores primitive types such as String, Int, Float, Double, and others. However, a @TypeConverter is very useful when it comes to storing custom types, such as: We will be trying to store a word and its various meanings in Room database (The way a dictionary has a word that has several meanings).
Ordinarily, Room handles instantiation of type converters for you. However, sometimes you might need to pass additional dependencies to your type converter classes, which means that you need your app to directly control initialization of your type converters. In that case, annotate your converter class with @ProvidedTypeConverter:
A class can have as many @TypeConverter methods as it needs. Each converter method should receive 1 parameter and have non-void return type.
You identify type converters by using the @TypeConverter annotation. Note: Room 2.3 and higher includes a default type converter for persisting enums. Existing type converters take precedence over the default, but if you have not already defined a type converter for enums then you don't need to define one.
I have implemented a LocalDateTimeConverter
in my library, Suitcase, here. Keep in mind that this extends my BaseConverter
class here. Note: This is all in Kotlin.
If you want to implement yourself, I would recommend storing is as a String as opposed to a timestamp. If you check out the links above, you will see that I first convert the date to a String using toString()
, and then back to a LocalDateTime
using the parse()
function.
Here it is in Java:
public class LocalDateTimeConverter {
@TypeConverter
public static LocalDateTime toDate(String dateString) {
if (dateString == null) {
return null;
} else {
return LocalDateTime.parse(dateString);
}
}
@TypeConverter
public static String toDateString(LocalDateTime date) {
if (date == null) {
return null;
} else {
return date.toString();
}
}
}
Edit:
The reason the code you are using above isn't working is because in your toTimestamp()
function you are simply asking for the hour of day as a Long
. So given a LocalDateTime
that is January 1, 2019, 12:00 PM, you are storing 12
. So in toDate
, you are asking to convert the timestamp 12
to a LocalDateTime
, which would be 12 milliseconds after midnight on January 1, 1970.
You can choose to continue using timestamps to store your date by simply changing that line in toTimestamp()
to date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
. This will give you the actual timestamp for the LocalDateTime
in the current time zone. Be aware of timezones here: as you are using the system's default timezone to save/load to/from the database, you may get a wrong value should the system changes timezones. If I use your app in New York, and then reopen the app in San Francisco all of the times will be off by 3 hours. It would be better to use a set timezone to save/load, and then convert that to the device's current timezone.
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