Android平台如何正确实现日期解析、格式化等全流程操作
Android Kotlin 基于java.time的日期全流程处理指南
前置兼容说明
Android 8.0(API 26)以下系统默认不内置java.time包,需要开启核心库脱糖(Core Library Desugaring)兼容低版本,在模块级build.gradle中添加配置即可:
android { compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' }
java.time包下的所有格式化类都是线程安全的,完全规避了SimpleDateFormat多线程使用的崩溃风险。
时区处理说明
时区是日期处理最容易出问题的环节,不同场景的处理规则如下:
- 设备本地展示的日期时间:必须使用设备当前时区,比如用户看到的当前时间、x天前的相对时间,都要和系统时区对齐
- 后端传输的日期时间:优先要求后端返回带时区偏移的标准ISO 8601格式(如
2024-05-20T14:30:00+08:00)或UTC时间戳,如果后端仅返回无偏移的纯日期字符串,必须提前和后端约定固定传输时区(比如统一用UTC或东八区),禁止默认用本地时区解析后端返回值 - 注意:不要用无时区信息的
LocalDateTime存储、传输跨时区的时间,仅用于本地用户输入、本地展示的无歧义场景
全流程处理示例
1. 日期时间解析
解析后端返回的标准格式字符串
// 解析带时区的ISO 8601字符串 val backendTimeStr = "2024-05-20T14:30:00+08:00" val zonedDateTime = ZonedDateTime.parse(backendTimeStr) // 转为设备本地时区的时间,用于后续展示 val localZonedTime = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault())
解析后端返回的约定固定时区的无偏移字符串
// 假设和后端约定传输时区为东八区 val noOffsetStr = "2024-05-20 14:30:00" val backendParseFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") .withZone(ZoneId.of("Asia/Shanghai")) val instant = Instant.from(backendParseFormatter.parse(noOffsetStr))
解析用户本地输入的日期时间
// 用户输入的是本地无歧义的时间,用LocalDateTime解析即可 val userInputStr = "2024-05-20 16:00:00" val userInputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") val userInputTime = LocalDateTime.parse(userInputStr, userInputFormatter)
2. 日期时间操作
完全替代原有Calendar的操作逻辑,API更直观易用:
// 获取7天前的本地日期 val sevenDaysAgo = LocalDate.now().minusDays(7) // 获取下一个月的第一天 val nextMonthFirstDay = LocalDate.now().plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()) // 计算两个日期的间隔天数 val dayDiff = ChronoUnit.DAYS.between(startDate, endDate) // 判断当前时间是否在指定时间段内 val isInRange = LocalTime.now().isBetween(startTime, endTime)
3. 日期时间格式化
格式化为本地用户友好的展示字符串
自动适配系统语言和时区,无需手动写固定格式:
val displayFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT) .withLocale(Locale.getDefault()) .withZone(ZoneId.systemDefault()) val userDisplayStr = displayFormatter.format(instant)
格式化为约定格式传给后端
val backendSendFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") .withZone(ZoneId.of("Asia/Shanghai")) // 和后端约定的传输时区 val sendToBackendStr = backendSendFormatter.format(LocalDateTime.now())
4. 日期校验
// 校验日期字符串格式是否合法 fun isDateStrValid(str: String, pattern: String): Boolean { return try { LocalDate.parse(str, DateTimeFormatter.ofPattern(pattern)) true } catch (e: DateTimeParseException) { false } } // 校验输入日期是否在合法范围(今天到未来30天内) val inputDate: LocalDate = getUserInputDate() val start = LocalDate.now() val end = start.plusDays(30) val isValid = !inputDate.isBefore(start) && !inputDate.isAfter(end)
旧API互转(兼容存量代码)
如果项目中仍有使用Date、Calendar的旧代码,可通过以下方式互转:
// Instant 转 Date val date = Date.from(instant) // Date 转 Instant val instant = date.toInstant() // LocalDateTime 转 Calendar(指定时区) val calendar = Calendar.getInstance() calendar.time = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant())
内容的提问来源于stack exchange,提问作者JD0minguezzz
相关产品推荐
相关产品推荐

