首页 文章

在Android SQLite中使用日期的最佳方式[关闭]

提问于
浏览
217

我在使用SQLite的Android应用程序上处理日期时遇到了一些麻烦 . 我有几个问题:

  • 我应该使用什么类型在SQLite中存储日期(文本,整数,...)?

  • 给出了存储日期的最佳方法如何使用ContentValues正确存储它?

  • 从SQLite数据库中检索日期的最佳方法是什么?

  • 如何在SQLite上进行SQL选择,按日期排序结果?

9 回答

  • 30

    您可以使用文本字段在 SQLite 中存储日期 .

    以UTC格式存储日期,如果使用 datetime('now') (yyyy-MM-dd HH:mm:ss) 则默认为允许按日期列进行排序 .

    SQLite 检索日期作为字符串,然后您可以使用Calendar或 android.text.format.DateUtils.formatDateTime 方法将它们格式化/转换为本地区域化格式 .

    这是我使用的区域化格式化方法;

    public static String formatDateTime(Context context, String timeToFormat) {
    
        String finalDateTime = "";          
    
        SimpleDateFormat iso8601Format = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss");
    
        Date date = null;
        if (timeToFormat != null) {
            try {
                date = iso8601Format.parse(timeToFormat);
            } catch (ParseException e) {
                date = null;
            }
    
            if (date != null) {
                long when = date.getTime();
                int flags = 0;
                flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
                flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
                flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
                flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;
    
                finalDateTime = android.text.format.DateUtils.formatDateTime(context,
                when + TimeZone.getDefault().getOffset(when), flags);               
            }
        }
        return finalDateTime;
    }
    
  • 1

    最好的方法是将日期存储为数字,使用“日历”命令接收 .

    //Building the table includes:
    StringBuilder query=new StringBuilder();
    query.append("CREATE TABLE "+TABLE_NAME+ " (");
    query.append(COLUMN_ID+"int primary key autoincrement,");
    query.append(COLUMN_DATETIME+" int)");
    
    //And inserting the data includes this:
    values.put(COLUMN_DATETIME, System.currentTimeMillis());
    

    为什么这样?首先,从日期范围获取值很容易 . 只需将您的日期转换为毫秒,然后进行适当的查询 . 按日期排序同样容易 . 正如我所包含的那样,转换各种格式的调用也同样容易 . 最重要的是,通过这种方法,您可以做任何您需要做的事情,没有问题 . 读取原始值有点困难,但它更容易弥补机器可读和可用的轻微缺点 . 事实上,构建一个阅读器相对容易(我知道有一些阅读器)会自动将时间标签转换为日期,以便于阅读 .

    值得一提的是,由此产生的值应该很长,而不是int . Integer in sqlite可以表示很多东西,从1-8字节开始,但对于几乎所有日期,64位或长,都是有效的 .

    编辑:正如评论中指出的那样,如果你这样做,你必须使用 cursor.getLong() 来正确获取时间戳 .

  • 1
    • 假定为in this comment,我总是使用整数来存储日期 .

    • 对于存储,您可以使用实用程序方法

    public static Long persistDate(Date date) {
        if (date != null) {
            return date.getTime();
        }
        return null;
    }
    

    像这样:

    ContentValues values = new ContentValues();
    values.put(COLUMN_NAME, persistDate(entity.getDate()));
    long id = db.insertOrThrow(TABLE_NAME, null, values);
    
    • 另一种实用方法负责装载
    public static Date loadDate(Cursor cursor, int index) {
        if (cursor.isNull(index)) {
            return null;
        }
        return new Date(cursor.getLong(index));
    }
    

    可以像这样使用:

    entity.setDate(loadDate(cursor, INDEX));
    
    • 按日期排序很简单SQL ORDER clause(因为我们有一个数字列) . 以下将按顺序降序(即最新的日期先行):
    public static final String QUERY = "SELECT table._id, table.dateCol FROM table ORDER BY table.dateCol DESC";
    
    //...
    
        Cursor cursor = rawQuery(QUERY, null);
        cursor.moveToFirst();
    
        while (!cursor.isAfterLast()) {
            // Process results
        }
    

    始终确保存储 UTC/GMT time ,尤其是在使用使用默认(即设备的)时区的 java.util.Calendarjava.text.SimpleDateFormat 时 . java.util.Date.Date() 可以安全使用,因为它创建了一个UTC值 .

  • 194

    SQLite可以使用文本,实数或整数数据类型来存储日期 . 更重要的是,无论何时执行查询,结果都会以 %Y-%m-%d %H:%M:%S 格式显示 .

    现在,如果使用SQLite日期/时间函数插入/更新日期/时间值,您实际上也可以存储毫秒 . 如果是这种情况,则使用格式 %Y-%m-%d %H:%M:%f 显示结果 . 例如:

    sqlite> create table test_table(col1 text, col2 real, col3 integer);
    sqlite> insert into test_table values (
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123')
            );
    sqlite> insert into test_table values (
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
                strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126')
            );
    sqlite> select * from test_table;
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
    

    现在,做一些查询来验证我们是否真的能够比较时间:

    sqlite> select * from test_table /* using col1 */
               where col1 between 
                   strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.121') and
                   strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    

    您可以使用 col2col3 检查相同的 SELECT ,您将得到相同的结果 . 如您所见,不返回第二行(126毫秒) .

    请注意 BETWEEN 是包容性的,因此......

    sqlite> select * from test_table 
                where col1 between 
                     /* Note that we are using 123 milliseconds down _here_ */
                    strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123') and
                    strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
    

    ...将返回相同的集合 .

    尝试使用不同的日期/时间范围,一切都将按预期运行 .

    没有 strftime 函数怎么样?

    sqlite> select * from test_table /* using col1 */
               where col1 between 
                   '2014-03-01 13:01:01.121' and
                   '2014-03-01 13:01:01.125';
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    

    没有 strftime 函数而没有毫秒呢?

    sqlite> select * from test_table /* using col1 */
               where col1 between 
                   '2014-03-01 13:01:01' and
                   '2014-03-01 13:01:02';
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
    

    ORDER BY 怎么样?

    sqlite> select * from test_table order by 1 desc;
    2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    sqlite> select * from test_table order by 1 asc;
    2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
    2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
    

    工作得很好 .

    最后,在处理程序中的实际操作时(不使用sqlite可执行文件......)

    顺便说一句:我正在使用JDBC(不确定其他语言)...来自xerial的sqlite-jdbc驱动程序v3.7.2 - 也许更新版本会改变下面解释的行为...如果你在Android中开发,你就不会需要一个jdbc驱动程序 . 可以使用 SQLiteOpenHelper 提交所有SQL操作 .

    JDBC有不同的方法从数据库中获取实际日期/时间值: java.sql.Datejava.sql.Timejava.sql.Timestamp .

    java.sql.ResultSet 中的相关方法(显然)分别为 getDate(..)getTime(..)getTimestamp() .

    例如:

    Statement stmt = ... // Get statement from connection
    ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_TABLE");
    while (rs.next()) {
        System.out.println("COL1 : "+rs.getDate("COL1"));
        System.out.println("COL1 : "+rs.getTime("COL1"));
        System.out.println("COL1 : "+rs.getTimestamp("COL1"));
        System.out.println("COL2 : "+rs.getDate("COL2"));
        System.out.println("COL2 : "+rs.getTime("COL2"));
        System.out.println("COL2 : "+rs.getTimestamp("COL2"));
        System.out.println("COL3 : "+rs.getDate("COL3"));
        System.out.println("COL3 : "+rs.getTime("COL3"));
        System.out.println("COL3 : "+rs.getTimestamp("COL3"));
    }
    // close rs and stmt.
    

    由于SQLite没有实际的DATE / TIME / TIMESTAMP数据类型,因此所有这3个方法都返回值,就像对象初始化为0一样:

    new java.sql.Date(0)
    new java.sql.Time(0)
    new java.sql.Timestamp(0)
    

    So, the question is: how can we actually select, insert, or update Date/Time/Timestamp objects? 有's no easy answer. You can try different combinations, but they will force you to embed SQLite functions in all the SQL statements. It'更容易定义一个实用程序类来将文本转换为Java程序中的Date对象 . 但请记住,SQLite会将任何日期值转换为UTC 0000 .

    总之,尽管一般规则总是使用正确的数据类型,或者甚至整数表示Unix时间(自纪元以来的毫秒),我发现使用默认的SQLite格式( '%Y-%m-%d %H:%M:%f' 或Java 'yyyy-MM-dd HH:mm:ss.SSS' )更容易,而不是使所有SQL复杂化SQLite函数的语句 . 前一种方法更容易维护 .

    TODO:我会查看结果在Android(API15或更高版本)中使用getDate / getTime / getTimestamp ...也许内部驱动程序与sqlite-jdbc不同...

  • 7

    通常(与我在mysql / postgres中的相同)我将日期存储在int(mysql / post)或text(sqlite)中,以便以时间戳格式存储它们 .

    然后我将它们转换为Date对象并根据用户TimeZone执行操作

  • 42

    SQlite DB 中存储 date 的最佳方法是存储当前的 DateTimeMilliseconds . 以下是要执行此操作的代码段_

    获取DateTimeMilliseconds

    public static long getTimeMillis(String dateString, String dateFormat) throws ParseException {
        /*Use date format as according to your need! Ex. - yyyy/MM/dd HH:mm:ss */
        String myDate = dateString;//"2017/12/20 18:10:45";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat/*"yyyy/MM/dd HH:mm:ss"*/);
        Date date = sdf.parse(myDate);
        long millis = date.getTime();
    
        return millis;
    }
    

    在数据库中插入数据

    public void insert(Context mContext, long dateTimeMillis, String msg) {
        //Your DB Helper
        MyDatabaseHelper dbHelper = new MyDatabaseHelper(mContext);
        database = dbHelper.getWritableDatabase();
    
        ContentValues contentValue = new ContentValues();
        contentValue.put(MyDatabaseHelper.DATE_MILLIS, dateTimeMillis);
        contentValue.put(MyDatabaseHelper.MESSAGE, msg);
    
        //insert data in DB
        database.insert("your_table_name", null, contentValue);
    
       //Close the DB connection.
       dbHelper.close(); 
    
    }
    

    Now, your data (date is in currentTimeMilliseconds) is get inserted in DB .

    下一步是,当您想要从DB检索数据时,您需要将相应的日期时间毫秒转换为相应的日期 . 以下是执行相同操作的示例代码段_

    将日期毫秒转换为日期字符串 .

    public static String getDate(long milliSeconds, String dateFormat)
    {
        // Create a DateFormatter object for displaying date in specified format.
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat/*"yyyy/MM/dd HH:mm:ss"*/);
    
        // Create a calendar object that will convert the date and time value in milliseconds to date.
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(milliSeconds);
        return formatter.format(calendar.getTime());
    }
    

    现在,终于获取数据并查看其工作情况......

    public ArrayList<String> fetchData() {
    
        ArrayList<String> listOfAllDates = new ArrayList<String>();
        String cDate = null;
    
        MyDatabaseHelper dbHelper = new MyDatabaseHelper("your_app_context");
        database = dbHelper.getWritableDatabase();
    
        String[] columns = new String[] {MyDatabaseHelper.DATE_MILLIS, MyDatabaseHelper.MESSAGE};
        Cursor cursor = database.query("your_table_name", columns, null, null, null, null, null);
    
        if (cursor != null) {
    
            if (cursor.moveToFirst()){
                do{
                    //iterate the cursor to get data.
                    cDate = getDate(cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.DATE_MILLIS)), "yyyy/MM/dd HH:mm:ss");
    
                    listOfAllDates.add(cDate);
    
                }while(cursor.moveToNext());
            }
            cursor.close();
    
        //Close the DB connection.
        dbHelper.close(); 
    
        return listOfAllDates;
    
    }
    

    希望这对大家有所帮助! :)

  • 0

    1 - 正如StErMi所说的那样 .

    2 - 请阅读:http://www.vogella.de/articles/AndroidSQLite/article.html

    3 -

    Cursor cursor = db.query(TABLE_NAME, new String[] {"_id", "title", "title_raw", "timestamp"}, 
                    "//** YOUR REQUEST**//", null, null, "timestamp", null);
    

    看这里:

    Query() in SQLiteDatabase

    4 - 见答案3

  • 3

    我更喜欢这个 . 这不是最好的方法,而是快速的解决方案 .

    //Building the table includes:
    StringBuilder query= new StringBuilder();
    query.append("CREATE TABLE "+TABLE_NAME+ " (");
    query.append(COLUMN_ID+"int primary key autoincrement,");
    query.append(COLUMN_CREATION_DATE+" DATE)");
    
    //Inserting the data includes this:
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    values.put(COLUMN_CREATION_DATE,dateFormat.format(reactionGame.getCreationDate())); 
    
    // Fetching the data includes this:
    try {
       java.util.Date creationDate = dateFormat.parse(cursor.getString(0);
       YourObject.setCreationDate(creationDate));
    } catch (Exception e) {
       YourObject.setCreationDate(null);
    }
    
  • 2
    "SELECT  "+_ID+" ,  "+_DESCRIPTION +","+_CREATED_DATE +","+_DATE_TIME+" FROM "+TBL_NOTIFICATION+" ORDER BY "+"strftime(%s,"+_DATE_TIME+") DESC";
    

相关问题