Reputation: 820
I've been working on this for hours, and I can't seem to figure out how to save dates to my Room Sqllite database. I'm basically copying the code to do this wholesale from the Android documentation.
Here's what I have.
Database:
@Database(entities = {Review.class},
version = 3,
exportSchema=false)
@TypeConverters(DateTypeConverter.class)
public abstract class NotecardDatabase extends RoomDatabase {
...etc...
}
Entity:
@Entity(tableName = "review",
indices = {
@Index(value = "next_review"),
}
public class Review {
...Other columns...
@TypeConverters(DateTypeConverter.class)
@ColumnInfo(name ="next_review")
@NonNull
private Date nextReview;
}
Next, my converter:
public class DateTypeConverter {
private static Logger log = Logger.getLogger("DateTypeConverter");
@TypeConverter
public static Date fromTimestamp(Long value) {
if(value != null) {
log.info("Incoming long: " + value + "\nTo Date: " + new Date(value));
}
return value == null ? null : new Date(value);
}
@TypeConverter
public static Long dateToTimestamp(Date date) {
if(date != null) {
log.info("Incoming date: " + date + "\n to Long: " + date.getTime());
}
return date == null ? null : date.getTime();
}
}
And finally, here's the output I get from running that when I try to create some Review objects:
06-18 18:13:38.522 7081-7098/DateTypeConverter: Incoming date: Mon Jun 18 18:13:38 PDT 2018 to Long: 1529370818524
06-18 18:13:38.522 7081-7106/DateTypeConverter: Incoming long: 1529370818 To Date: Sun Jan 18 08:49:30 PST 1970
So it seems that it saves correctly (see first log statement), but when I get the thing out of the database, the last 3 digits of the long are simply chopped off, returning a date in 1970.
Help?
Upvotes: 1
Views: 6565
Reputation: 820
Okay, so after much work, I figured out the problem. Thanks for all who were trying to help on this.
I changed from Date to Calendar, though that's not what fixed this problem.
The real issue was that there are two timestamps: the Linux timestamp, which is milliseconds since epoch, and the Java/Sqllite timestamp, which is seconds since epoch.
In order to have everything play nicely with Sqllite functions and also to save and read properly, here's the my working code:
public class DateTypeConverter {
@TypeConverter
public static Calendar calendarFromTimestamp(String value) {
if(value == null) {
return null;
}
Calendar cal = new GregorianCalendar();
cal.setTimeInMillis(NumberUtils.toLong(value)*1000);
return cal;
}
@TypeConverter
public static String dateToTimestamp(Calendar cal) {
if(cal == null) {
return null;
}
return "" + cal.getTimeInMillis()/1000;
}
}
Note the usage of the cal.getTimeInMillis() function, which explicitly calls out that we're doing the millisecond timestamp. Then when saving to the database, we divide by 1000 to save the seconds timestamp, because the Sqllite date functions deal with the seconds timestamp.
Note also that you could probably also use Longs instead of Strings, but the Strings worked for me.
Upvotes: 5
Reputation: 24947
Instead of @TypeConverters(DateTypeConverter.class)
Use
@TypeConverters({DateTypeConverter.class})
Upvotes: 0