kotlinx-datetime 用于 Kotlin:完整指南及示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程
\n

kotlinx-datetime:Kotlin 中的跨平台日期和时间处理

\n\n
\n

1. 这是什么以及为什么需要它

\n

\n kotlinx-datetime 是 JetBrains 为 Kotlin 生态系统提供的官方日期和时间处理库。其主要特点是跨平台:同一份代码可在 JVM、JS(浏览器和 Node.js)、Native(iOS、macOS、Windows、Linux)和 Wasm 上运行。这使开发者无需编写平台相关的包装器或为不同目标使用不同的库。\n

\n

\n 为什么需要它?Kotlin/JVM 的标准库使用 java.time,但该库在其他平台上不可用。对于 Kotlin/Native 和 Kotlin/JS,开发者要么使用平台 API(NSDate、Date),要么引入第三方库。kotlinx-datetime 通过提供基于 ISO-8601 规范的统一 API 解决了这个问题。它包含表示时间点(Instant)、无时间日期(LocalDate)、无日期时间(LocalTime)、日期时间(LocalDateTime)、时区(TimeZone)和时间段(DateTimePeriod)的类。\n

\n

\n 该库非常适合使用 Kotlin Multiplatform (KMP) 的项目、基于 Ktor 的服务器应用程序、Android 应用程序(作为 java.time 的替代品),甚至脚本和控制台工具。它轻量级、无外部依赖,并得到社区的积极维护。\n

\n
\n\n
\n

2. 安装

\n

\n 该库通过 Maven Central 分发。要使用它,您需要在 build.gradle.kts(或 build.gradle)文件中添加依赖项。以下是 Gradle Kotlin DSL 的准确代码。\n

\n
// build.gradle.kts\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    // 主库\n    implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")\n\n    // 如果您使用多平台项目,请添加到 commonMain:\n    // commonMain.dependencies {\n    //     implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")\n    // }\n}\n
\n

\n 重要提示: 0.6.1 版本是撰写本文时的最新稳定版本。请查看 GitHub 发布页面 以获取最新版本。对于 Gradle Groovy DSL,命令类似,但字符串不带引号。\n

\n

\n 如果您使用 Maven,请添加到 pom.xml:\n

\n
<dependency>\n    <groupId>org.jetbrains.kotlinx</groupId>\n    <artifactId>kotlinx-datetime</artifactId>\n    <version>0.6.1</version>\n</dependency>\n
\n

\n 对于 Gradle Kotlin DSL 的多平台项目 (KMP),请添加到 commonMain:\n

\n
kotlin {\n    sourceSets {\n        commonMain.dependencies {\n            implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")\n        }\n    }\n}\n
\n
\n\n
\n

3. 快速入门

\n

\n 最小工作示例:获取当前时间点、格式化并输出到控制台。\n

\n
import kotlinx.datetime.*\n\nfun main() {\n    // 获取当前 UTC 时间点\n    val now: Instant = Clock.System.now()\n    println("当前 UTC 时间点:$now")\n\n    // 转换为本地日期和时间(使用系统时区)\n    val localDateTime: LocalDateTime = now.toLocalDateTime(TimeZone.currentSystemDefault())\n    println("本地日期时间:$localDateTime")\n\n    // 手动创建日期\n    val date: LocalDate = LocalDate(2024, 12, 25)\n    println("圣诞节:$date")\n}\n
\n

\n 此示例演示了三个关键操作:获取当前时间、转换为本地时间以及创建特定日期。所有操作均跨平台且无需额外配置。\n

\n
\n\n
\n

4. 主要方法及示例

\n

\n 以下是 kotlinx-datetime 中最常用的方法和类,附有详细说明和代码示例。\n

\n\n

4.1. Instant:时间点

\n

\n Instant 表示 UTC 时间轴上的一个特定点。它不包含时区信息,但可以转换为任何时区的本地时间。\n

\n
import kotlinx.datetime.*\n\nfun instantExamples() {\n    // 当前时间\n    val now = Clock.System.now()\n    println("当前时间:$now")\n\n    // 从字符串解析\n    val parsed = Instant.parse("2024-12-25T10:30:00Z")\n    println("解析后的时间:$parsed")\n\n    // 从纪元秒数创建\n    val fromEpoch = Instant.fromEpochSeconds(1_700_000_000)\n    println("从纪元秒数创建:$fromEpoch")\n\n    // 转换为纪元毫秒数\n    val epochMillis = now.toEpochMilliseconds()\n    println("纪元毫秒数:$epochMillis")\n\n    // 比较\n    val earlier = Instant.parse("2024-01-01T00:00:00Z")\n    val later = Instant.parse("2024-12-31T23:59:59Z")\n    println("earlier < later:${earlier < later}") // true\n}\n
\n\n

4.2. LocalDate:无时间日期

\n

\n LocalDate 表示日期(年、月、日),不包含时间和时区。适用于生日、假期等。\n

\n
import kotlinx.datetime.*\n\nfun localDateExamples() {\n    // 创建日期\n    val date = LocalDate(2024, 12, 25)\n    println("日期:$date")\n\n    // 解析\n    val parsed = LocalDate.parse("2024-12-25")\n    println("解析后的日期:$parsed")\n\n    // 当前日期(系统时区)\n    val today = Clock.System.todayIn(TimeZone.currentSystemDefault())\n    println("今天:$today")\n\n    // 日期运算\n    val tomorrow = today.plus(1, DateTimeUnit.DAY)\n    println("明天:$tomorrow")\n\n    val nextWeek = today.plus(1, DateTimeUnit.WEEK)\n    println("下周:$nextWeek")\n\n    // 日期差\n    val daysUntil = today.periodUntil(parsed).days\n    println("距离圣诞节还有 $daysUntil 天")\n\n    // 星期几\n    println("星期几:${today.dayOfWeek}") // MONDAY, TUESDAY, ...\n}\n
\n\n

4.3. LocalTime:无日期时间

\n

\n LocalTime 表示一天中的时间(时、分、秒、纳秒),不包含日期。\n

\n
import kotlinx.datetime.*\n\nfun localTimeExamples() {\n    // 创建时间\n    val time = LocalTime(14, 30, 0)\n    println("时间:$time")\n\n    // 解析\n    val parsed = LocalTime.parse("14:30:00")\n    println("解析后的时间:$parsed")\n\n    // 当前时间\n    val now = Clock.System.now()\n    val localTime = now.toLocalDateTime(TimeZone.currentSystemDefault()).time\n    println("当前时间:$localTime")\n\n    // 时间运算\n    val later = time.plus(1, DateTimeUnit.HOUR)\n    println("一小时后:$later")\n\n    // 比较\n    val morning = LocalTime(8, 0)\n    val evening = LocalTime(20, 0)\n    println("早上 < 晚上:${morning < evening}") // true\n}\n
\n\n

4.4. LocalDateTime:日期时间

\n

\n LocalDateTime 结合了日期和时间,但不包含时区。通常用于用户界面。\n

\n
import kotlinx.datetime.*\n\nfun localDateTimeExamples() {\n    // 创建\n    val dt = LocalDateTime(2024, 12, 25, 10, 30, 0)\n    println("日期时间:$dt")\n\n    // 解析\n    val parsed = LocalDateTime.parse("2024-12-25T10:30:00")\n    println("解析后的日期时间:$parsed")\n\n    // 从 Instant 转换\n    val now = Clock.System.now()\n    val local = now.toLocalDateTime(TimeZone.currentSystemDefault())\n    println("本地日期时间:$local")\n\n    // 转换为 Instant(需要时区)\n    val instant = local.toInstant(TimeZone.UTC)\n    println("UTC 时间点:$instant")\n\n    // 组件提取\n    println("年:${dt.year}, 月:${dt.monthNumber}, 日:${dt.dayOfMonth}")\n    println("时:${dt.hour}, 分:${dt.minute}, 秒:${dt.second}")\n}\n
\n\n

4.5. TimeZone:时区

\n

\n TimeZone 表示时区。支持 IANA 时区标识符(如 "Europe/Moscow"、"America/New_York")和 UTC 偏移量。\n

\n
import kotlinx.datetime.*\n\nfun timeZoneExamples() {\n    // 系统时区\n    val systemTz = TimeZone.currentSystemDefault()\n    println("系统时区:$systemTz")\n\n    // 按 ID 获取\n    val moscow = TimeZone.of("Europe/Moscow")\n    println("莫斯科时区:$moscow")\n\n    // UTC 偏移量\n    val utcPlus3 = TimeZone.of("UTC+3")\n    println("UTC+3:$utcPlus3")\n\n    // 可用时区列表\n    val ids = TimeZone.availableZoneIds\n    println("可用时区数量:${ids.size}")\n    println("前 5 个时区:${ids.take(5)}")\n\n    // 时区偏移量\n    val offset = moscow.offsetAt(Clock.System.now())\n    println("莫斯科当前偏移量:$offset") // 例如 +03:00\n}\n
\n\n

4.6. DateTimePeriod:时间段

\n

\n DateTimePeriod 表示时间段,包含天、小时、分钟、秒和纳秒。用于日期时间运算。\n

\n
import kotlinx.datetime.*\n\nfun periodExamples() {\n    // 创建时间段\n    val period = DateTimePeriod(days = 10, hours = 5, minutes = 30)\n    println("时间段:$period")\n\n    // 日期时间运算\n    val start = LocalDateTime(2024, 1, 1, 0, 0)\n    val end = start.plus(period, TimeZone.UTC)\n    println("开始:$start, 结束:$end")\n\n    // 两个日期时间之间的差\n    val diff = start.periodUntil(end, TimeZone.UTC)\n    println("差:$diff") // 10 天 5 小时 30 分钟\n\n    // 组件提取\n    println("天:${diff.days}, 小时:${diff.hours}, 分钟:${diff.minutes}")\n}\n
\n\n

4.7. 格式化和解析

\n

\n kotlinx-datetime 通过 toString() 支持 ISO-8601 格式,并通过 parse() 方法支持解析。对于自定义格式,可以使用 DateTimeFormat(实验性 API)。\n

\n
import kotlinx.datetime.*\n\nfun formattingExamples() {\n    val instant = Instant.parse("2024-12-25T10:30:00Z")\n\n    // ISO-8601 格式\n    println("ISO 格式:$instant") // 2024-12-25T10:30:00Z\n\n    // 自定义格式(实验性)\n    // 注意:此 API 在 0.6.1 中为实验性,未来版本可能更改\n    // val formatter = DateTimeFormat.byPattern(\"yyyy-MM-dd HH:mm\")\n    // val formatted = formatter.format(instant.toLocalDateTime(TimeZone.UTC))\n    // println(\"自定义格式:$formatted\")\n\n    // 解析自定义格式\n    // val parsed = formatter.parse(\"2024-12-25 10:30\")\n    // println(\"解析后的自定义格式:$parsed\")\n}\n
\n
\n\n
\n

5. 最佳实践

\n
    \n
  • 存储和传输使用 Instant: 在数据库、API 和文件之间交换数据时,始终使用 Instant(UTC)。这避免了时区问题。
  • \n
  • 显示使用 LocalDateTime: 在用户界面中,使用 LocalDateTime 并转换为用户的时区。
  • \n
  • 避免平台特定 API: 在 KMP 项目中,不要使用 java.time、NSDate 或 Date。仅使用 kotlinx-datetime。
  • \n
  • 注意实验性 API: 自定义格式和某些操作(如 DateTimeFormat)标记为 @ExperimentalDateTimeFormat。在生产中使用前请检查版本。
  • \n
  • 测试时区: 始终使用不同的时区测试您的代码,以确保正确性。
  • \n
\n
\n\n
\n

6. 结论

\n

\n kotlinx-datetime 是 Kotlin 生态系统中处理日期和时间的强大且便捷的工具。其跨平台特性使其成为 KMP 项目的理想选择,而简洁的 API 则降低了错误风险。从简单的日期运算到复杂的时区转换,该库提供了所有必要的工具。\n

\n

\n 开始使用 kotlinx-datetime,告别平台特定的日期时间代码!\n

\n
\n

推荐