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