KotlinでDateやTimeを扱う方法について

採用はこちら

Kotlinで日時を扱う場合、単に「今の日時を取得する」だけでは不十分です。

タイムゾーン、DB保存、API通信、表示フォーマットなど、用途ごとに適切な型を選ばなければ、後から修正困難な不具合を生みます。

本記事では、Kotlinにおける日時処理を「どの型を、どの目的で使うべきか」 という観点から、体系的に解説します。

目次

Kotlinでの日時処理:結論から

2026年現在、Kotlinでの日時処理は以下の方針がベストプラクティスです。

  • 基本は java.time API
  • Kotlin Multiplatform(KMP)では kotlinx-datetime
  • java.util.Date / Calendar は互換用途に限定

この前提を理解しておくと、設計で迷うことがほぼなくなります。

なぜ java.util.Date は推奨されないのか

val date = Date()

一見シンプルですが、java.util.Date には以下の問題があります。

  • 可変オブジェクトである(スレッドセーフでない)
  • API設計が直感的でない
  • タイムゾーンの扱いが曖昧
  • Java 8以降、公式には java.time への移行が推奨されている

重要なのは、「使えない」わけではないという点です。

外部ライブラリや古いAPIとの互換性のために Date を扱う場面は今でも存在します。

ただし、新規設計や内部ロジックでは、

Date を直接扱わず、Instant に変換してから処理する

というスタンスが安全です。

Kotlinで最も標準的な日時API:java.time

Java 8以降、日時処理の中心は java.time パッケージです。

KotlinはJavaと完全互換なので、そのまま利用できます。

主なクラスと役割

クラス役割
LocalDate日付のみ(誕生日・締日)
LocalTime時刻のみ(営業時間)
LocalDateTime日付+時刻(タイムゾーンなし)
ZonedDateTimeタイムゾーン付き日時
InstantUTC基準の瞬間

日付のみを扱う:LocalDate

import java.time.LocalDate

val today = LocalDate.now()
val specificDate = LocalDate.of(2026, 2, 17)
  • 誕生日
  • 締日
  • カレンダー上の日付

といった 「時刻やタイムゾーンが不要な情報」 に最適です。

時刻のみを扱う:LocalTime

import java.time.LocalTime

val now = LocalTime.now()
val openTime = LocalTime.of(9, 0)
  • 営業開始時刻
  • アラーム時刻

など、日付と独立した時間情報に使います。

日付+時刻:LocalDateTime(注意点あり)

import java.time.LocalDateTime

val now = LocalDateTime.now()

LocalDateTimeタイムゾーンを持ちません

そのため、

  • DBに「その地域のローカル日時」を保存したい場合
  • 日本国内限定サービス

などでは有効ですが、

  • 多地域展開
  • サマータイム対応

が将来的に必要になる場合は、設計時点で慎重に検討する必要があります。

タイムゾーンを含める:ZonedDateTime

import java.time.ZonedDateTime
import java.time.ZoneId

val tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"))
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
  • 国際サービス
  • 予約・イベント管理
  • 表示用の「現地時刻」

では必須となるクラスです。

内部基準の最適解:Instant

import java.time.Instant

val now = Instant.now()

Instant は「UTC基準の一点」を表します。

Instant が強い理由

  • タイムゾーン差異を完全に排除できる
  • API通信・ログ・イベント時刻に最適
  • Date と相互変換しやすい

多くのシステムでは、

内部処理・保存:Instant
表示・業務処理:ZonedDateTime / LocalDateTime

という役割分担が安定します。

フォーマット・パース(文字列変換)

日時 → 文字列

import java.time.format.DateTimeFormatter

val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")
val text = LocalDateTime.now().format(formatter)

文字列 → 日時

val parsed = LocalDateTime.parse(
    "2026/02/17 16:00",
    formatter
)

日本向けUIでは yyyy/MM/dd 形式が一般的です。

日付計算・差分処理(重要)

日付の加減算

val tomorrow = LocalDate.now().plusDays(1)
val lastMonth = LocalDate.now().minusMonths(1)

日付差分(総日数)

Period.days は「日数部分」なので、総日数を求める用途には向きません。

import java.time.temporal.ChronoUnit

val start = LocalDate.of(2026, 1, 1)
val end = LocalDate.of(2026, 2, 17)

val daysBetween = ChronoUnit.DAYS.between(start, end)

Kotlin Multiplatform向け:kotlinx-datetime

KMPでは java.time が使えないため、kotlinx-datetime が標準選択肢になります。

import kotlinx.datetime.*

val now = Clock.System.now()
val local = now.toLocalDateTime(TimeZone.currentSystemDefault())

注意点

  • フォーマットAPIが最小限
  • 表示用は別ライブラリや自前処理が必要な場合が多い

実務での代表的な設計パターン

用途推奨型
内部基準・ログInstant
DB保存(瞬間)Instant
DB保存(地域日時)LocalDateTime
API通信ISO-8601 + Instant
画面表示ZonedDateTime
誕生日・締日LocalDate

Androidでの注意点

AndroidではAPIレベルによって java.time がそのまま使えない場合がありますが、Core Library Desugaring を有効にすれば、多くの環境で問題なく利用可能です。

まとめ

  • 新規開発では java.time を第一選択
  • 内部基準は Instant
  • タイムゾーンを扱う設計を避けない
  • Date は互換用途に限定
  • KMPでは kotlinx-datetime

この設計を守れば、「後から壊れない日時処理」 を実現できます。

以上、KotlinでDateやTimeを扱う方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次