【问题标题】:How to correctly use strftime and datetime using Room library?如何使用 Room 库正确使用 strftime 和 datetime?
【发布时间】:2018-01-07 04:50:44
【问题描述】:

我有一个实体Memo 类。我使用@TypeConverterGregorianCalendar 转换为Long

备忘录.java

@Entity
public class Memo {
    @Ignore
    public static final int TYPE_EXPENSE = 0;
    @Ignore
    public static final int TYPE_INCOME = 1;

    @PrimaryKey(autoGenerate = true)
    public int id;

    public int type;
    @ColumnInfo(name = "item_name")
    public String itemName;
    @ColumnInfo(name = "category_name")
    public String categoryName;
    public String note;
    public double dollar;
    public GregorianCalendar date;
    public String photoPath;

    @Ignore
    public Memo(int type) {
        this.type = type;
        itemName = "";
        categoryName = "";
        note = "";
        dollar = 0d;
        date = new GregorianCalendar();
        photoPath = "";
    }

    public Memo() {
        this(TYPE_EXPENSE);
    }

    @Ignore
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("id = " + id);
        builder.append(", itemName = " + itemName);
        builder.append(", type = " + type);
        builder.append(", categoryName = " + categoryName);
        builder.append(", note = " + note);
        builder.append(", date = " + date.getTimeInMillis());
        return builder.toString();
    }
}

Converters.java

public class Converters {
    @TypeConverter
    public static GregorianCalendar fromTimestamp(Long value) {
        if (value == null)
            return new GregorianCalendar();
        else {
            GregorianCalendar calendar = new GregorianCalendar();
            calendar.setTimeInMillis(value);
            return calendar;
        }
    }

    @TypeConverter
    public static Long millisToTimestamp(GregorianCalendar calendar) {
        return calendar == null ? null : calendar.getTimeInMillis();
    }
}

我想获取数据库中的第一条和最后一条记录,结果得到MemosWithTimestamp对象。

public class MemoWithTimestamp {
    public int year;
    public int month;
    @Embedded
    public Memo memo;

    @Ignore
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("year=" + year);
        builder.append(", month=" + month);
        builder.append(", memo=[ "+memo.toString()+"]");
        return builder.toString();
    }
}

查询方法:

    @Query("SELECT *, CAST(strftime('%Y', datetime(date)) AS int) AS year, CAST(strftime('%m', datetime(date)) AS int) AS month FROM memo ORDER BY date DESC LIMIT 1")
    MemoWithTimestamp getTheLastMemo();

    @Query("SELECT *, CAST(strftime('%Y', datetime(date)) AS int) AS year, CAST(strftime('%m', datetime(date)) AS int) AS month FROM memo ORDER BY date ASC LIMIT 1")
    MemoWithTimestamp getTheFirstMemo();

Logcat中数据库中的数据:

id = 1, itemName = memo-2015-1-0, type = 0, categoryName = , note = , date = 1422634536401 <=first
....
id = 197, itemName = memo-2017-12-9, type = 0, categoryName = , note = , date = 1515428136414 <=last

Logcat中查询后的结果:

firstMemo= year=0, month=0, memo=[ id = 1, itemName = memo-2015-1-0, type = 0, categoryName = , note = , date = 1422634536401]

lastMemo= year=0, month=0, memo=[ id = 197, itemName = memo-2017-12-9, type = 0, categoryName = , note = , date = 1515428136414]

但是无论有没有CAST,年月字段总是为0。

如何解决这个问题?

【问题讨论】:

    标签: android sqlite android-sqlite android-room


    【解决方案1】:

    你在这里错过了两件事:

    1) datetime() 函数获取秒数,而您正在传递毫秒数。将值除以 1000。

    2) 您应该将第二个参数作为“unixepoch”传递给datetime() 函数。

    所以,您的查询是这样固定的:

    CAST(strftime('%Y', datetime(date/1000, 'unixepoch')) AS int) AS year
    

    一个月也一样:

    CAST(strftime('%m', datetime(date/1000, 'unixepoch')) AS int) AS month 
    

    【讨论】:

    • 我更改了查询,但它返回lastMemo= year=2018, month=1, memo=[ id = 197, itemName = memo-2017-12-9, type = 0, categoryName = , note = , date = 1515428136414]
    • 另一个问题:CAST 真的需要吗?系统是否已经将 String 值(strftime 函数)转换为 Int?
    • 一切都正确,你有:date = 1515428136414,现在是 2018 年 1 月 8 日 (year=2018, month=1),所以你查询的年份和月份是正确的。 itemName 不同可能是因为它已更新(它是字符串)。但是从您的日期字段(时间戳)中提取年份和月份在我的回答中是正确的。关于第二个问题,你不需要 CAST 到 int 因为 %Y 给你 string 数字,它会被正确转换。但是该函数通常会为您提供字符串,例如strftime(%Y-%m) 会给你'2018-01'
    • 感谢您的帮助。我忘记在 itemName 中添加 1 到月份。
    • 只是一个简短的说明。如果将STRFTIME 的返回值与int 进行比较,则需要CAST
    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2016-07-12
    相关资源
    最近更新 更多