Kotlin
Multiplatformで日付を言語ロケールに合わせてフォーマットしたい場合はどうしたらいいでしょうか。
Kotlin Multiplatformで日時を扱うには kotlinx-datetime
ライブラリを利用することが一般的だと思います。このライブラリは基本的な日時操作機能を提供していますが、ロケールに合わせたフォーマット機能はありません。
expect/actualで実装する
現状では expect/actual
機構を使って、各プラットフォーム固有の日時フォーマットを実装するのが現実的です。
以下はその実装例です。
共通モジュールでの定義
まず、共通モジュールに機能を定義します。
// 共通モジュールに定義
class DateTimeFormatter() {
expect fun format(instant: Instant, timeZone: TimeZone): String
}
JVM(Android)実装
JVMプラットフォームではJava標準ライブラリの日時フォーマット機能を使います。
class DateTimeFormatter {
actual private val formatter = java.time.format.DateTimeFormatter
.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)
.withLocale(java.util.Locale.getDefault())
fun format(instant: Instant, timeZone: TimeZone): String {
actual val javaInstant = java.time.Instant.ofEpochSecond(
.epochSeconds, instant.nanosecondsOfSecond.toLong()
instant)
val javaZoneId = java.time.ZoneId.of(timeZone.id)
return formatter.format(java.time.ZonedDateTime.ofInstant(javaInstant, javaZoneId))
}
}
iOS実装
iOS(Native)ターゲットでは、Objective-C/Swiftの日時フォーマットAPI(NSDateFormatter)を使用します。
class DateTimeFormatter {
actual fun format(instant: Instant, timeZone: TimeZone): String {
actual val nsDate = NSDate.dateWithTimeIntervalSince1970(instant.epochSeconds.toDouble())
val formatter = NSDateFormatter().apply {
= NSDateFormatterStyle.NSDateFormatterMediumStyle
dateStyle = NSDateFormatterStyle.NSDateFormatterMediumStyle
timeStyle = NSTimeZone.timeZoneWithName(timeZone.id)
timeZone }
return formatter.stringFromDate(nsDate)
}
}
JavaScript実装
WebやNode.jsなどのJavaScriptターゲットでは、Intl APIを活用します。
class DateTimeFormatter {
actual fun format(instant: Instant, timeZone: TimeZone): String {
actual val date = Date(instant.toEpochMilliseconds())
return date.toLocaleString(undefined, object : DateTimeFormatOptions {
override var timeZone = timeZone.id
override var dateStyle = "medium"
override var timeStyle = "medium"
})
}
}
実際の使用例
上記の実装を実際に呼び出すには下のコードのようにします。
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
fun main() {
val now = Clock.System.now()
val formatter = DateTimeFormatter()
val localTimeZone = TimeZone.currentSystemDefault()
// 現在時刻をローカルのタイムゾーンとロケールでフォーマット
val formattedDateTime = formatter.format(now, localTimeZone)
(formattedDateTime)
println}
この例ではシステムの現在時刻を取得し、ユーザーのシステムデフォルトのタイムゾーンとロケールに合わせてフォーマットしています。
まとめ
Kotlin Multiplatformでのロケール対応の日時フォーマットは、今のことろKotlinの世界だけでは実現できません。今後、kotlinx.datetimeライブラリなどで対応が進められるかもしれません。それまではこの記事で紹介した方法で対応しましょう。