Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Room LocalDateTime TypeConverter

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);
    }
}}
like image 779
bodovix Avatar asked Feb 28 '19 14:02

bodovix


People also ask

What is @typeconverter in room?

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).

How to instantiate type converters in room?

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:

How many @typeconverter methods can a class have?

A class can have as many @TypeConverter methods as it needs. Each converter method should receive 1 parameter and have non-void return type.

How to identify type converters for persisting enums?

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.


1 Answers

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.

like image 60
jguerinet Avatar answered Sep 19 '22 08:09

jguerinet