Room Using Date field

2020-05-25 08:38发布

问题:

I am using date converter class to convert my date object. However, I still encounter an error saying. error: Cannot figure out how to save this field into a database. You can consider adding a type converter for it.

My Date Converter class

public class DateConverter {

    @TypeConverter
    public static Date toDate(Long dateLong){
        return dateLong == null ? null: new Date(dateLong);
    }

    @TypeConverter
    public static long fromDate(Date date){
        return date == null ? null :date.getTime();
    }
}

My Database table for using the date object.

@Entity(tableName = "userFitnessDailyRecords")

    @TypeConverters(DateConverter.class)
    public class UserFitnessDailyRecords {

        @NonNull
        @PrimaryKey(autoGenerate = true)
        public int id;
        public Date forDay;

        public Date getForDay() {
            return forDay;
        }

        public void setForDay(Date forDay) {
            this.forDay = forDay;
        }
    }

I followed the example from google code persistence labs and from commonwares room respective GitHub example. I am using room version 1.0.0.

回答1:

You're converting from Date to Long (wrapper) and from long (primitive) to Date. I changed it to Long and it compiled. Besides, unboxing null in your converter produces a NPE.

public class DateConverter {

    @TypeConverter
    public static Date toDate(Long dateLong){
        return dateLong == null ? null: new Date(dateLong);
    }

    @TypeConverter
    public static Long fromDate(Date date){
        return date == null ? null : date.getTime();
    }
}


回答2:

I had this same problem (how to store time to Room), but I was using Calendar, so I made this: [note: This anwer is for Calendar]

edit: the main reason for this answer is that Date is deprecated, so here you go

  @TypeConverter
  public static Calendar toCalendar(Long l) {
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(l);
    return c;
  }

  @TypeConverter
  public static Long fromCalendar(Calendar c){
    return c == null ? null : c.getTime().getTime();
  }


回答3:

Put converter class in class of data base, not in the model :

@Database(entities = {
    Patient.class,Medicine.class,Tooth.class,})

@TypeConverters({TimeConverter.class,OutBoundConverter.class})

public abstract class PatientDataBase extends RoomDatabase {//your data base}


回答4:

See my complete example.

Refer to the documentation : https://developer.android.com/training/data-storage/room/referencing-data

public class Converters {
    @TypeConverter
    public static Date fromTimestamp(Long value) {
        return value == null ? null : new Date(value);
    }

    @TypeConverter
    public static Long dateToTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}

Then map it to the database.

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

And the entity.

@Entity
public class User {
    private Date birthday;
}


回答5:

Using Calendar with Kotlin (adapted from O95's answer):

@TypeConverter
fun toCalendar(l: Long?): Calendar? =
    if (l == null) null else Calendar.getInstance().apply { timeInMillis = l }

@TypeConverter
fun fromCalendar(c: Calendar?): Long? = c?.time?.time


回答6:

You can write it on Kotlin as well

@TypeConverter
fun toDate(dateLong:Long):Date {
    return Date(dateLong)
}

@TypeConverter
fun fromDate(date: Date):Long{
    return date.time;
}


回答7:

AndroidThreeTen is the port of Java8 new time classes, which unfortunately are available only for api>=26. Using https://github.com/JakeWharton/ThreeTenABP , we can use LocalDateTime on all versions of Android. Here in kotlin the converter,

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): LocalDateTime? {
        return value?.let {
            LocalDateTime.ofInstant(
                Instant.ofEpochMilli(it), ZoneId.systemDefault()
            )
        }
    }

    @TypeConverter
    fun LocalDateTimeToTimestamp(date: LocalDateTime?): Long? {
        return date?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
    }
}

which, as other good answers already said, it's declared on the Database abstract class:

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}