1

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?

Joey
  • 760
  • 2
  • 7
  • 23
  • Your passing value "1529370818" to fromTimestamp().Where from you get this value ? – Ranjith KP Jun 19 '18 at 01:34
  • That is passed into my function from the Room. I'm assuming that Room is reading the int value stored in the database and passing it to fromTimestamp. – Joey Jun 19 '18 at 22:24
  • It's not int long right ?if value reading from room then who saves this "1529370818" value to room? – Ranjith KP Jun 20 '18 at 00:42

2 Answers2

5

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.

Joey
  • 760
  • 2
  • 7
  • 23
  • FYI, the troublesome old date-time classes such as `java.util.Date`, `java.util.Calendar`, and `java.text.SimpleDateFormat` are now legacy, supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. Much of the *java.time* functionality is back-ported to Java 6 & Java 7 in the [***ThreeTen-Backport***](http://www.threeten.org/threetenbp/) project. Further adapted for earlier Android in the [***ThreeTenABP***](https://github.com/JakeWharton/ThreeTenABP) project. See [*How to use ThreeTenABP…*](http://stackoverflow.com/q/38922754/642706). – Basil Bourque Jun 20 '18 at 22:47
  • I am having the same problem like you. I implemented yout solution, but I am getting the following error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. Any idea? – Batz Feb 10 '19 at 23:34
0

Instead of @TypeConverters(DateTypeConverter.class)

Use

@TypeConverters({DateTypeConverter.class})

Community
  • 1
  • 1
Sagar
  • 23,903
  • 4
  • 62
  • 62
  • My problem is not with the getTime function, but rather with the fact that when I read it out of the database after saving, it's a totally different number. Also, when I tried to store as strings, I had an almost identical problem with the data getting scrambled. – Joey Jun 19 '18 at 22:27