如何使用 Android Room 比较两个日期?
How to compare two dates using Android Room?
总结
我正在制作一个 Android 应用程序,我有一个名为 Objective
的 Room 实体,其中存储了它的 startDate
和 endDate
。
我想做一个查询,我可以在其中检索“活动”目标,或者换句话说,已经开始但尚未结束的目标。
这是我目前得到的:
查询
@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... */
}
问题
我的问题在于,当我调用此方法时,返回的是一个空列表,而不是预期的活动目标列表
(至少这发生在我尝试过的各种测试中运行)。
(请参阅底部的编辑以了解此问题有何问题。)
额外信息
我还将包括我的 Entity
、TypeConverter
、RoomDatabase
和测试代码,以防万一它可以帮助您。
实体
@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)
总结
我正在制作一个 Android 应用程序,我有一个名为 Objective
的 Room 实体,其中存储了它的 startDate
和 endDate
。
我想做一个查询,我可以在其中检索“活动”目标,或者换句话说,已经开始但尚未结束的目标。
这是我目前得到的:
查询
@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... */
}
问题
我的问题在于,当我调用此方法时,返回的是一个空列表,而不是预期的活动目标列表 (至少这发生在我尝试过的各种测试中运行)。
(请参阅底部的编辑以了解此问题有何问题。)
额外信息
我还将包括我的 Entity
、TypeConverter
、RoomDatabase
和测试代码,以防万一它可以帮助您。
实体
@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)