Android 6设备中SimpleDateFormat解析日期字符串遇ParseException问题
问题原因及解决方案
这个问题我之前也碰到过,核心原因是不同Android版本的SimpleDateFormat解析逻辑差异,再加上设备区域设置的影响:
为什么Android 6真机报错,而Android 8和模拟器正常?
- Android 8(API 26)及以上版本,
SimpleDateFormat对AM/PM标识的解析做了兼容性优化,即便设备区域设置不是英文,也能正确识别"AM"/"PM"这类英文标识。 - 但Android 6(API 23)及更低版本的
SimpleDateFormat非常依赖系统当前的区域设置:如果你的真机系统语言不是英文,或者区域设置里的AM/PM缩写不是"AM"/"PM"(比如部分地区用"上午"/"下午"、或者其他语言的本地化缩写),就会因为无法识别字符串里的"AM"而抛出ParseException。 - 模拟器通常默认是英文区域设置,所以能正常解析,这就是为什么模拟器没问题但真机报错的原因。
另外你代码里还有个小问题:var date = formatter.parse(date)里的变量名重复了(date既是输入的字符串变量,又是要赋值的Date对象),虽然编译器可能不会报错,但容易引起混淆,建议修改变量名,比如把输入字符串改成dateString。
解决方案
方案1:给SimpleDateFormat指定英文Locale(快速修复)
创建SimpleDateFormat时明确传入Locale.ENGLISH,强制解析逻辑使用英文的AM/PM规则,这样不管设备的区域设置是什么,都能正确识别"AM"/"PM":
val dateString = "10/10/2016 12:00:00 AM" val formatter = SimpleDateFormat("MM/dd/yyyy hh:mm:ss aa", Locale.ENGLISH) val date = formatter.parse(dateString)
方案2:使用更稳定的日期时间库(推荐)
SimpleDateFormat本身是线程不安全的,而且在不同Android版本的行为不一致,Google官方推荐使用ThreeTenABP(适配Android的JSR-310日期时间库),它能统一所有Android版本的日期解析行为:
- 首先在你的
build.gradle(Module级别)添加依赖:
implementation 'com.jakewharton.threetenabp:threetenabp:1.4.6'
- 在自定义的
Application类的onCreate方法中初始化库:
class MyApplication : Application() { override fun onCreate() { super.onCreate() ThreeTenABP.init(this) } }
- 然后用以下代码解析日期:
val dateString = "10/10/2016 12:00:00 AM" val formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a", Locale.ENGLISH) val localDateTime = LocalDateTime.parse(dateString, formatter) // 如果需要转换为Date对象(兼容旧代码): val date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant())
为什么移除AM/PM能解决问题?
当你去掉格式化字符串里的aa部分后,解析逻辑只需要处理日期和时间的数字部分,不需要识别和区域设置相关的AM/PM标识,自然就不会因为区域不匹配而抛出异常了。
内容的提问来源于stack exchange,提问作者Luis Abreu
相关产品推荐
相关产品推荐

