如何使用 Android Room 比较两个日期?

How to compare two dates using Android Room?

总结

我正在制作一个 Android 应用程序,我有一个名为 Objective 的 Room 实体,其中存储了它的 startDateendDate
我想做一个查询,我可以在其中检索“活动”目标,或者换句话说,已经开始但尚未结束的目标。

这是我目前得到的:

查询

@Dao
public interface ObjectiveDao {
    /* some code goes here... */

    /*
       For an objective to be active, its start date should be before the current day,
       and its end date should be after the current day.
    */
    @Query("SELECT * FROM objectives " +
            "WHERE end_date >= strftime('%s', 'now') + 0 " +
            "AND start_date <= strftime('%s', 'now') + 0")
    List<Objective> getActive();

    /* rest of the code goes here... */
}

问题

我的问题在于,当我调用此方法时,返回的是一个空列表,而不是预期的活动目标列表 (至少这发生在我尝试过的各种测试中运行)。

(请参阅底部的编辑以了解此问题有何问题。)


额外信息

我还将包括我的 EntityTypeConverterRoomDatabase 和测试代码,以防万一它可以帮助您。

实体

@Entity(tableName = "objectives")
public class Objective {
    @PrimaryKey(autoGenerate = true)
    private int id;
    
    /* 
        I feel like I don't need to 
        include the whole thing, just the part that matters.
    */
    
    @ColumnInfo(name = "start_date")
    private LocalDate startDate;

    @ColumnInfo(name = "end_date")
    private LocalDate endDate;

    public Objective() {
        this("", ObjectiveType.OBJECTIVE_DO, 0, LocalDate.now(), LocalDate.now().plusDays(1));
    }

    public Objective(String title, ObjectiveType type, int quantity, LocalDate startDate, LocalDate endDate) {
        this.title = title;
        this.type = type;
        this.quantity = quantity;
        this.startDate = startDate;
        this.endDate = endDate;
        id = 0;
    }

    /* rest of the code goes here...*/
}

TypeConverters

public class Converters {
    @TypeConverter
    public static LocalDate fromTimestamp(Long value) {
        return value == null ? null : LocalDate.ofEpochDay(value);
    }

    @TypeConverter
    public static Long localDateToTimestamp(LocalDate date) {
        return date == null ? null : date.toEpochDay();
    }
    /* rest of the code goes here...*/
}

房间数据库

@Database(entities = {Objective.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract ObjectiveDao getObjectiveDao();
}

仪器测试

class TestUtil {
    static Objective createObjective() {
        Objective objective = new Objective();
        objective.setTitle("Test Objective");
        objective.setType(ObjectiveType.OBJECTIVE_DO);
        objective.setQuantity(10);
        objective.setStartDate(LocalDate.now());
        objective.setEndDate(LocalDate.now().plusDays(1));

        return objective;
    }
}

public class ObjectivesInstrumentedTest {
    private ObjectiveDao objectiveDao;
    private AppDatabase db;

    @Before
    public void createDb() {
        Context context = ApplicationProvider.getApplicationContext();
        db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build();
        objectiveDao = db.getObjectiveDao();
    }

    @After
    public void closeDb() throws IOException {
        db.close();
    }

    @Test
    public void objectiveIsInsertedIntoDatabase() {
        Objective objective = TestUtil.createObjective();
        /*
            id is set to 1 because, otherwise, Room automatically sets the ID to 1,
            and when the objects are compared they do not match. (a value of 0 counts as null).
        */
        objective.setId(1);
        objectiveDao.insert(objective);
        List<Objective> objectives = objectiveDao.getAll();
        assertThat(objectives.get(0), equalTo(objective));
    }

    @Test
    public void objectiveIsActive() {
        Objective objective = TestUtil.createObjective();
        objective.setId(1);
        objectiveDao.insert(objective);
        List<Objective> objectives = objectiveDao.getActive();
        assertThat(objectives.get(0), equalTo(objective));
    }
}

以防你想知道,第一个测试 运行 很好,但是 运行 第二个测试时我得到 IndexOutOfBoundsException

希望你能帮我解决这个问题,提前感谢你花时间阅读本文并思考任何可能的解决方案。

编辑

正如@MikeT 指出的那样,我存储的这些日期不是秒数,也不是 unix 时间戳,而是自 1970 年 1 月 1 日以来经过的天数。

Strftime 的 %s returns 以秒为单位的日期时间,ofEpochDay returns 自 1970-01-01 以来的天数。所以你也需要比较一下。

我相信你可以使用:-

@Query("SELECT * FROM objectives " +
            "WHERE end_date >= CAST(strftime('%J','now') - strftime('%J','1970-01-01') AS INTEGER) " +
            "AND start_date <= CAST(strftime('%J','now') - strftime('%J','1970-01-01') AS INTEGER);")

基于 strftime and LocalDate 但我不确定是否存在差异。我建议不要以这种笨拙的格式存储数据,而是以 SQLite 识别为日期时间的格式存储数据(根据下面的 link)