【问题标题】:Compare only date without time using Android Room使用 Android Room 仅比较没有时间的日期
【发布时间】:2021-08-03 16:14:46
【问题描述】:

我正在使用 Room 的 TypeConverter 将 Date 对象保存到数据库中。它工作得很好。但是,我想进行一个查询,仅比较 Date 对象的“日期”部分与时间戳的“日期”部分。我希望时间被忽略。我尝试使用 SQLite 上可用的 date() 函数,但我想我用错了。

@Query("SELECT * FROM event WHERE date(event_date) = date(:date)")
fun loadEventsByDate(date: Date): Flow<List<Event>>
class DateConverter {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time
    }
}

【问题讨论】:

    标签: android date kotlin android-room


    【解决方案1】:

    问题/说明

    您的问题是您正在转换为/从(并因此存储)一个以毫秒为单位的 unix 日期时间,但 SQLite date 函数(以及所有 SQLite 日期/时间函数) 需要日期/time 以匹配其中一种可识别的格式。

    这是一个使用类型转换器(日期列)如何存储数据的示例(使用劫持项目和用户表):-

    13 位数字

    因此,date 函数返回 NULL(对于 WHERE 子句的两边),并且在 SQLite 中,NULL 不等于 NULL,因此您什么也得不到(如果 NULL 等于 NULL,您将获得所有行而不是选择) .

    根据上述数据考虑以下解释性查询(修复 WHERE 子句):-

    @Query("SELECT *, :date AS passed_date, coalesce(date(date),'ouch') AS cnv_date, coalesce(date(:date),'ouch') AS cnv_passed_date FROM user WHERE date(date / 1000,'unixepoch') = date(:date / 1000,'unixepoch');")
    

    结果(使用上面的示例数据)将是(将其写入日志后):-

    2021-08-04 08:02:42.324 D/MYINFO: User = Susan date is Wed Aug 04 08:02:42 GMT+10:00 2021 passed date is 1628028162323 converted date is ouch converted passed date is ouch
    2021-08-04 08:02:42.325 D/MYINFO: User = Fred date is Wed Aug 04 08:02:42 GMT+10:00 2021 passed date is 1628028162323 converted date is ouch converted passed date is ouch
    2021-08-04 08:02:42.325 D/MYINFO: User = Mary date is Wed Aug 04 08:02:42 GMT+10:00 2021 passed date is 1628028162323 converted date is ouch converted passed date is ouch
    
    • 即Room 已成功提取日期。但是:-
    • 通过参数传递的日期是13位,所以不是日期。因此:-
    • 日期函数都返回 NULL(由 coalesce 函数转换为 ouch),因为传递的值是 1 个 13 位无法识别的日期/时间值。

    /A 修复

    上面的 where 子句包含一个修复程序,可确保向日期函数传递一个适合两者的值。即 13 位数字除以 1000 以去除毫秒,然后应用 unixepoch 修饰符。

    因此,您可以尝试/使用:-

    @Query("SELECT * FROM event WHERE date(event_date / 1000,'unixepoch') = date(:date / 1000,'unixepoch')")
    fun loadEventsByDate(date: Date): Flow<List<Event>>
    

    【讨论】:

    • 非常感谢您的详细解释。它工作正常。我不需要使用时间戳来保存日期。我这样做是因为这是文档中推荐的内容:developer.android.com/training/data-storage/room/… 如果我希望能够按日期过滤,是否有更好的方法来保存它?
    • @unadivadantan,保存为时间戳(Long)的好处是效率更高; 如果您不需要使用毫秒,那么如果您除以 1000 来减少毫秒,则空间会更小。存储为字符串(只是日期时间)最少需要 10 个字节,而 Long 最多需要 8 个字节。简而言之,“问题”无意成为批评。
    • 哦,当然!不用担心。我只是想知道是否有更好的方法来存储这个用例的值。非常感谢;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 2021-09-20
    • 2011-01-21
    • 1970-01-01
    • 2021-11-19
    • 2012-07-22
    相关资源
    最近更新 更多