SQLiteを使用するAndroidアプリケーションで日付を操作するときに問題が発生します。いくつか質問があります。
- SQLiteに日付を格納するにはどのタイプを使用する必要がありますか(テキスト、整数など)?
- 日付を保存する最良の方法を考えると、ContentValuesを使用して適切に保存するにはどうすればよいですか?
- SQLiteデータベースから日付を取得する最良の方法は何ですか?
- SQLiteでSQLを選択し、結果を日付順に並べ替えるにはどうすればよいですか?
SQLiteを使用するAndroidアプリケーションで日付を操作するときに問題が発生します。いくつか質問があります。
回答:
テキストフィールドを使用して、内に日付を保存できますSQLite
。
日付をUTC形式で格納します。使用datetime('now')
(yyyy-MM-dd HH:mm:ss)
する場合のデフォルトでは、日付列によるソートが可能になります。
日付を文字列として取得SQLite
すると、カレンダーまたは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;
}
最善の方法は、カレンダーコマンドを使用して受け取った日付を数値として保存することです。
//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ではなく、長くなければならないことに言及する価値があります。sqliteの整数は、1〜8バイトの多くのことを意味しますが、ほとんどすべての日付で64ビットまたは長いデータが機能します。
編集:コメントで指摘されているように、cursor.getLong()
これを行う場合は、を使用してタイムスタンプを適切に取得する必要があります。
保存には、ユーティリティメソッドを使用できます
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句です(数値列があるため)。以下は降順で並べ替えます(つまり、最新の日付が最初になります)。
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時間を必ず保存してください。
UTC値を作成するため、安全に使用できます。java.util.Calendar
java.text.SimpleDateFormat
java.util.Date.Date()
SQLiteはテキスト、実数、または整数のデータ型を使用して日付を格納できます。さらに、クエリを実行するたびに、結果はformatを使用して表示されます%Y-%m-%d %H:%M:%S
。
SQLiteの日付/時刻関数を使用して日付/時刻の値を挿入/更新すると、実際にはミリ秒も格納できます。その場合、結果はformatを使用して表示されます%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
あなたは同じことを確認することができますSELECT
使用するcol2
とcol3
、あなたは同じ結果を得ることができます。ご覧のとおり、2行目(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(いないことを確認、他の言語について)から... sqliteの-JDBCドライバv3.7.2使用していxerialを -多分新しいリビジョンは動作が以下に説明する変更...あなたは、Androidで開発している場合、あなたはしないでくださいjdbc-driverが必要です。すべてのSQL操作は、を使用して送信できますSQLiteOpenHelper
。
JDBCは、データベースから実際の日付/時刻の値を取得するためのさまざまな方法がありますjava.sql.Date
、java.sql.Time
とjava.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時間を表す整数(エポックからのミリ秒)を使用するという一般的な規則にもかかわらず、デフォルトの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とは異なります...
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;
}
- DBにデータを挿入する
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;
}
これがすべてに役立つことを願っています!:)
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);
こちらをご覧ください:
4-回答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);
}