🕘
【Android】MediaStore の DATE_TAKEN / DATE_ADDED について
Media.DATE_TAKEN
とDATE_ADDED
カラムのタイムスタンプについて勘違いしていることがあったので、まとめておきたいと思います。
DATE_TAKEN
: ミリ秒 / DATE_ADDED
: 秒
UNIXエポック(1970年1月1日午前0時0分0秒(UTC))
を基準に、DATE_TAKEN
は経過日数をミリ秒で、DATE_ADDED
は秒で表したタイムスタンプを持っています。
DATE_TAKEN
とDATE_ADDED
のタイムスタンプは、以下のようになっています
-
DATE_TAKEN
: 1111295661000 -
DATE_ADDED
: 1602652291
DATE_TAKEN
は、Android 10(Android Q/API Level 29)
から追加されたカラムなので、使用するとき以下のような判定が必要です。
val column = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.DATE_TAKEN
} else {
MediaStore.Images.Media.DATE_ADDED
}
タイムスタンプに関する単語について
UTC
- Coordinated Universal Time の略
- 協定世界時のこと
- 世界標準で使われている時間
- 日本(JST/日本標準時)との時差は「9時間」で、UTC が「09:00」なら日本は「18:00」になる
UNIX タイムスタンプ
- 1970年1月1日午前0時0分0秒を基準にして、経過日数を秒で表したもの
UNIX エポック
- 1970年1月1日午前0時0分0秒のこと
実装例 : 日時を指定して端末に保存されている写真を取得する
特定の日時以降に撮影された写真の URI を取得する実装です。
日時の取り扱いには ThreeTenABP ライブラリを使用しています。
app / build.gradle
implementation 'com.jakewharton.threetenabp:threetenabp:1.3.0'
fun loadPhotoUris(context: Context, dateTime: LocalDateTime): List<Uri> {
val uris = mutableListOf<Uri>()
// 取得したいカラムを指定する
val projection: Array<String> = arrayOf(MediaStore.Images.Media._ID)
// 検索条件 : 特定の日時以降に保存された画像を取得する
val selection = "${MediaStore.Images.Media.DATE_ADDED} >= ?"
val timestamp = toTimestamp(dateTime).toString()
// selection の「?」に入る値
val selectionArgs: Array<String> = arrayOf(timestamp)
// DATE_ADDED で昇順にする
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} ASC"
context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
).use { cursor ->
cursor ?: return@use
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
val imageId = cursor.getLong(columnIndex)
val uri = Uri.withAppendedPath(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageId.toString()
)
uris.add(uri)
}
}
return uris
}
private fun toTimestamp(dateTime: LocalDateTime): Long {
// JST に変換
val zonedDateTime = dateTime.atZone(ZoneId.of("UTC+09:00"))
return zonedDateTime.toEpochSecond()
}
Discussion