在Android SQLite中处理日期的最佳方法

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

  1. 我应该使用什么类型存储日期在SQLite(文本,整数,…)?
  2. 给出了存储日期的最佳方式,我如何使用ContentValues正确存储它?
  3. 从SQLite数据库中检索日期的最佳方法是什么?
  4. 如何在SQLite上进行sql选择,按日期排序结果?
206389 次浏览

可以使用文本字段在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;
}

通常(与我在mysql/postgres中所做的一样),我将日期存储在int(mysql/post)或文本(sqlite)中,以时间戳格式存储它们。

然后,我将它们转换为日期对象,并根据用户时区执行操作

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 . sh

4 -见答案3

最好的方法是将日期存储为使用Calendar命令接收的数字。

//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());

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

值得一提的是,这个函数的值应该是long,而不是int。sqlite整数可以表示很多东西,从1-8字节的任何东西,但对于几乎所有日期来说,64位或长字节是有效的。

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

  1. 正如假定的在这个评论中,我总是使用整数来存储日期。
  2. 对于存储,您可以使用实用程序方法

    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);
    
  3. Another utility method takes care of the loading

    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));
    
  4. Ordering by date is simple SQL ORDER clause (because we have a numeric column). The following will order descending (that is newest date goes first):

    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
    }
    

Always make sure to store the UTC/GMT time, especially when working with java.util.Calendar and java.text.SimpleDateFormat that use the default (i.e. your device's) time zone. java.util.Date.Date() is safe to use as it creates a UTC value.

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

现在,如果您使用SQLite日期/时间函数插入/更新日期/时间值,您实际上也可以存储毫秒。 如果是这样,结果将使用格式%Y-%m-%d %H:%M:%f显示。 例如:< / p >
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毫秒)没有返回。< / p >

注意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可执行文件…)

BTW:我正在使用JDBC(不确定其他语言)…来自xerial的sqlite-jdbc驱动程序v3.7.2 -也许更新的版本会改变下面解释的行为… 如果您在Android上开发,则不需要jdbc驱动程序。所有SQL操作都可以使用SQLiteOpenHelper.

. 0提交

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)
这个问题没有简单的答案。 您可以尝试不同的组合,但它们将迫使您在所有SQL语句中嵌入SQLite函数。在Java程序中定义一个实用程序类来将文本转换为Date对象要容易得多。但是请记住,SQLite将任何日期值转换为UTC+0000.

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

我将检查结果时使用getDate/getTime/getTimestamp在Android (API15或更好)…也许内部驱动程序与sqlite-jdbc不同…

我更喜欢这个。这不是最好的方法,但却是一个快速的解决方案。

//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);
}
"SELECT  "+_ID+" ,  "+_DESCRIPTION +","+_CREATED_DATE +","+_DATE_TIME+" FROM "+TBL_NOTIFICATION+" ORDER BY "+"strftime(%s,"+_DATE_TIME+") DESC";

< >强SQlite数据库< / >强中存储__abc0的最佳方法是存储当前的DateTimeMilliseconds。下面是执行so_的代码片段

  1. 获取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;
}
  1. 在数据库中插入数据
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检索数据时,您需要将各自的日期时间毫秒转换为相应的日期。下面是执行相同操作的示例代码片段_

  1. 将日期毫秒转换为日期字符串。
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());
}
  1. 现在,最后获取数据,看看它的工作…
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;


}

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