https://github.com/Kotlin/kotlinx-datetime 根据 README 整理一份 kotlinx-datetime 的使用指南
以下是基于官方 README 整理的 kotlinx-datetime 使用指南。该库为 Kotlin 多平台提供了没有遗留负担的日期时间 API,完全基于 ISO 8601 并独立于平台(无 java.time 依赖)。
1. 简介
kotlinx-datetime 是 Kotlin 官方开发的跨平台日期时间库,支持 JVM、Android、Native、JS 等平台。它提供了一套清晰、不可变的数据类型,用于表示和处理日期、时间、时刻及时区。
2. 添加依赖
在 build.gradle.kts 中添加:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
}
}
}
(版本号请以 Maven Central 最新版为准)
3. 核心类型概览
| 类型 | 描述 | 示例值 |
|---|---|---|
Instant | 世界时间线上的一个点(UTC+0 时刻) | 2024-01-15T10:30:00Z |
LocalDate | 不带时区的日期(年-月-日) | 2024-01-15 |
LocalTime | 不带日期的时间(时-分-秒-纳秒) | 10:30:00 |
LocalDateTime | 不带时区的日期+时间 | 2024-01-15T10:30:00 |
TimeZone | 时区(如 Europe/Paris 或固定偏移) | TimeZone.of("Asia/Tokyo") |
DateTimePeriod | 日期与时间的组合跨度(年/月/日/时/分/秒/纳秒) | DateTimePeriod(years=1, months=2, days=3, hours=4, minutes=5, seconds=6, nanoseconds=7) |
DatePeriod | 仅日期部分(年/月/日)的跨度 | DatePeriod(years=1, months=2, days=3) |
4. 创建实例
4.1 获取当前时刻
val now: Instant = Clock.System.now()
4.2 从字符串解析(ISO 8601 格式)
val instant = Instant.parse("2024-03-21T12:00:00Z")
val localDate = LocalDate.parse("2024-03-21")
val localTime = LocalTime.parse("14:30:15.5")
val localDateTime = LocalDateTime.parse("2024-03-21T14:30:00")
4.3 直接构造
val date = LocalDate(2024, 3, 21) // 年,月,日
val time = LocalTime(14, 30, 15, 500_000_000) // 时,分,秒,纳秒
val dateTime = LocalDateTime(date, time)
4.4 从 Instant 转换为本地日期时间(需指定时区)
val instant = Clock.System.now()
val timeZone = TimeZone.currentSystemDefault()
val localDateTime = instant.toLocalDateTime(timeZone)
5. 日期时间计算与区间
5.1 加减时间段
val date = LocalDate(2024, 3, 21)
// 使用 DatePeriod 仅改变日期部分
val nextMonth = date + DatePeriod(months = 1) // 2024-04-21
// 使用 DateTimePeriod 同时改变日期和时间
val dateTime = LocalDateTime(2024, 3, 21, 10, 0)
val later = dateTime + DateTimePeriod(hours = 3, days = 1) // 2024-03-22T13:00
5.2 两个日期之间的差
val start = LocalDate(2024, 1, 1)
val end = LocalDate(2024, 3, 1)
val period: DatePeriod = end - start // 得到 DatePeriod(months=2)
Instant 相减得到 Duration(仅时间跨度):
val duration: Duration = instant2 - instant1
5.3 区间与迭代
val from = LocalDate(2024, 1, 1)
val to = LocalDate(2024, 1, 5)
if (date in from..to) { /* 在区间内 */ }
// 按天迭代(需使用 plus 和条件)
var current = from
while (current <= to) {
println(current)
current = current.plus(DatePeriod(days = 1))
}
6. 格式化与解析
库内置了 ISO 8601 的默认格式。如需自定义格式,可配合 kotlinx-datetime 的扩展或使用字符串操作。官方推荐使用 toString() 和 parse() 处理标准格式。
若需复杂格式(如 dd.MM.yyyy),可以转换后使用平台相关的工具(如 JVM 上的 DateTimeFormatter 但会破坏跨平台性)。跨平台格式化建议自行编写扩展函数或使用第三方库(如 kotlinx-datetime-format 实验性模块)。
示例:将 LocalDate 转为自定义字符串
fun LocalDate.formatToDMY(): String = "${dayOfMonth}.${monthNumber}.${year}"
7. 时区处理
7.1 获取时区
val defaultTz = TimeZone.currentSystemDefault()
val tokyoTz = TimeZone.of("Asia/Tokyo")
val utcTz = TimeZone.UTC
7.2 时区转换
val instant = Clock.System.now()
val parisTime = instant.toLocalDateTime(TimeZone.of("Europe/Paris"))
val tokyoTime = instant.toLocalDateTime(TimeZone.of("Asia/Tokyo"))
7.3 本地日期时间转为 Instant
val local = LocalDateTime(2024, 3, 21, 10, 0)
val instantInTokyo = local.toInstant(TimeZone.of("Asia/Tokyo")) // 东京时间10:00对应的UTC时刻
8. 常用操作速查表
| 目的 | 代码示例 |
|---|---|
| 获取当前 UTC 时刻 | Clock.System.now() |
| 当前系统时区的日期 | Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date |
| 提取日期部分 | instant.toLocalDateTime(tz).date |
| 提取时间部分 | localDateTime.time |
| 修改某字段 | localDate.copy(month = 12) |
| 比较两个时刻 | instant1 < instant2 |
| 计算两个日期的月份差 | (endDate - startDate).months |
| 检查闰年 | localDate.year.isLeap |
9. 与 java.time 的互操作(仅限 JVM)
虽然 kotlinx-datetime 不依赖 java.time,但在 JVM 上你可以轻松转换:
// kotlinx-datetime → java.time
val localDateKt: LocalDate = ...
val javaLocalDate = java.time.LocalDate.of(localDateKt.year, localDateKt.monthNumber, localDateKt.dayOfMonth)
// java.time → kotlinx-datetime
val javaInstant = java.time.Instant.now()
val kotlinInstant = Instant.fromEpochSeconds(javaInstant.epochSecond, javaInstant.nano)
注意:跨平台代码中应避免此类转换。
10. 最佳实践
- 优先使用
Instant存储时刻(如数据库、网络传输),只在展示给用户或输入时转换为LocalDateTime+TimeZone。 - 避免使用
LocalDateTime表示具体时刻,因为它没有时区信息,转换到Instant时依赖外部时区。 - 所有类型都是不可变的,加减操作会返回新实例。
- 注意
DatePeriodvsDateTimePeriod:DatePeriod只能加减日期字段(年/月/日),且会正确处理月份长度不同的问题(例如 1月31日 + 1个月 → 2月29日或28日)。DateTimePeriod还可处理时间部分。 - 性能:该库专为多平台设计,不依赖系统时钟缓存,适合绝大多数应用。