在 Kotlin 中高级处理日期和时间
\n\n在现代 Kotlin 开发中,妥善处理日期和时间不仅是便利,更是必要。在高级层面,开发者需要处理时区、周期、持续时间和复杂的格式化操作。在本文中,我们将介绍关键工具和技巧,帮助您编写可靠且高效的代码。
\n\n1. 核心类:LocalDate、LocalTime、LocalDateTime 和 Instant
\n\nKotlin 完全继承了强大的 java.time 库(JSR-310),该库已成为 Java 8 及以上版本中处理日期和时间的事实标准。对于 Kotlin Multiplatform,存在 kotlinx-datetime 库,但在 JVM 项目中,最常用的仍然是 java.time。
LocalDate、LocalTime、LocalDateTime
\n这些类表示不绑定时区的日期和时间。它们非常适合存储生日、日程安排以及其他时区无关的数据。
\n\nimport java.time.LocalDate\nimport java.time.LocalTime\nimport java.time.LocalDateTime\n\nfun main() {\n val date = LocalDate.now()\n val time = LocalTime.of(14, 30, 0)\n val dateTime = LocalDateTime.of(date, time)\n \n println("日期: $date")\n println("时间: $time")\n println("日期和时间: $dateTime")\n \n // 加减天数\n val tomorrow = date.plusDays(1)\n println("明天: $tomorrow")\n}\n\nInstant — 机器时间戳
\nInstant 表示 UTC 时间轴上的一个点。它对于日志记录、服务器间数据交换以及 API 操作不可或缺。
import java.time.Instant\n\nfun main() {\n val now = Instant.now()\n println("当前 UTC 时刻: $now")\n \n // 从毫秒转换\n val fromEpoch = Instant.ofEpochMilli(1_700_000_000_000)\n println("从毫秒转换: $fromEpoch")\n}\n\n2. 时区:ZonedDateTime 和 OffsetDateTime
\n\n当应用程序需要服务不同地区的用户时,必须考虑时区。为此,存在 ZonedDateTime(包含完整的时区信息)和 OffsetDateTime(仅包含与 UTC 的偏移量)。
import java.time.ZonedDateTime\nimport java.time.ZoneId\nimport java.time.ZoneOffset\n\nfun main() {\n // 纽约当前时间\n val newYork = ZonedDateTime.now(ZoneId.of("America/New_York"))\n println("纽约: $newYork")\n \n // 从 UTC 转换\n val utcNow = ZonedDateTime.now(ZoneOffset.UTC)\n val moscowTime = utcNow.withZoneSameInstant(ZoneId.of("Europe/Moscow"))\n println("莫斯科: $moscowTime")\n \n // 用于简单偏移的 OffsetDateTime\n val offsetTime = java.time.OffsetDateTime.now(ZoneOffset.ofHours(3))\n println("+3 小时: $offsetTime")\n}\n\n重要提示: 对于用户界面,始终使用 ZonedDateTime,以便正确处理夏令时/冬令时切换。OffsetDateTime 适用于固定偏移量,例如在处理日志时。
3. 日期之间的差异:Period 和 Duration
\n\n为了计算时间差,Kotlin 提供了两个类:Period(用于日期,以天/月/年为单位)和 Duration(用于精确的时间间隔,以秒/纳秒为单位)。
Period — 处理日历单位
\nimport java.time.LocalDate\nimport java.time.Period\n\nfun main() {\n val birthDate = LocalDate.of(1990, 5, 15)\n val today = LocalDate.now()\n val age = Period.between(birthDate, today)\n \n println("年龄: ${age.years} 年, ${age.months} 月, ${age.days} 天")\n \n // 给日期添加一个周期\n val nextMonth = today.plus(Period.ofMonths(1))\n println("一个月后: $nextMonth")\n}\n\n