兼容Android API26以下版本的UTC日期转LocalDateTime实现方法
你原有实现无法在API 26以下运行的核心原因是:java.time包下的Instant、ZoneId、LocalDateTime类是Android 8.0(API 26)才内置的系统API,低版本系统不存在这些类。以下是三种可直接落地的兼容方案:
方案1:零依赖原生实现,兼容所有Android版本
你已经写好的convertUtcToDate方法本身是全版本兼容的,它依赖的SimpleDateFormat、Date、TimeZone从API 1就已存在。你只需要基于这套解析逻辑,用同样全版本兼容的Calendar类按本地时区提取时间字段即可,不需要依赖高版本API。
首先自定义一个和高版本API行为一致的LocalDateTime数据结构,避免直接引用系统高版本的类:
data class LocalDateTime( val year: Int, val month: Int, // 存储1-12的自然月数值 val dayOfMonth: Int, val hour: Int, val minute: Int, val second: Int, val millisecond: Int )
重写转换方法:
override fun convertUtcToLocalDateTime(utcVal: String): LocalDateTime { // 复用已有的UTC字符串解析逻辑 val utcDate = convertUtcToDate(utcVal) // 按系统默认时区读取时间字段 val localCalendar = Calendar.getInstance().apply { timeZone = TimeZone.getDefault() time = utcDate } return LocalDateTime( year = localCalendar.get(Calendar.YEAR), month = localCalendar.get(Calendar.MONTH) + 1, // Calendar原生月份从0开始计数,+1转为自然月 dayOfMonth = localCalendar.get(Calendar.DAY_OF_MONTH), hour = localCalendar.get(Calendar.HOUR_OF_DAY), minute = localCalendar.get(Calendar.MINUTE), second = localCalendar.get(Calendar.SECOND), millisecond = localCalendar.get(Calendar.MILLISECOND) ) }
如果你只需要把UTC时间转成本地时间的展示字符串,不需要结构化的LocalDateTime对象,可以直接用以下方法,逻辑更简单:
fun utcToLocalTimeStr(utcVal: String, formatPattern: String = "yyyy-MM-dd HH:mm:ss"): String { val utcDate = convertUtcToDate(utcVal) val formatter = SimpleDateFormat(formatPattern, Locale.getDefault()) formatter.timeZone = TimeZone.getDefault() return formatter.format(utcDate) }
注意:SimpleDateFormat和Calendar都是线程不安全的,不要把它们定义成单例或者静态常量复用,避免多线程下出现时间解析错误。
方案2:开启核心库脱糖,直接复用原有代码(推荐)
如果项目使用的Android Gradle插件版本在4.0及以上,直接开启核心库脱糖即可在API 26以下设备上直接使用java.time包下的所有API,不需要改动原有业务逻辑。
配置方式如下,修改模块级的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' }
配置完成后,直接删除原有方法上的@RequiresApi(Build.VERSION_CODES.O)注解,你之前写的转换逻辑就可以在所有API版本上正常运行,不需要做任何代码修改。
方案3:引入Joda-Time时间库
如果不想调整Gradle配置,也可以引入Joda-Time三方时间库,它本身做了全版本Android兼容,API设计和java.time基本一致,缺点是库体积较大,会增加约300kb左右的方法数和包体积,适合已经在项目中使用Joda-Time的场景。
内容的提问来源于stack exchange,提问作者PewK

