Android使用Joda Time解析日期抛出IllegalArgumentException问题求解
问题背景
方法预期逻辑:从Firestore读取最近一次盘点的日期数据,若距离当前时间间隔满24小时则执行*proceedWithInventoryMode()*方法。
对应实现代码:
private void checkIf24HourReached() { LocalDateTime now = LocalDateTime.now(); LocalDateTime _24hrsBefore = now.minusDays(1); db.collection("Project").document(Prefs.getString("ManageID", GlobalObject._FIRESTORE_ID)) .collection("inventoryMode") .document(GlobalObject._INVENTORY_MODE_DATA_ID) .get() .addOnSuccessListener(documentSnapshot -> { String lastInventoryEndDate = documentSnapshot.getString("date"); Log.d("lastInventoryEndDate: ", lastInventoryEndDate); if (lastInventoryEndDate == null) { proceedWithInventoryMode(); } else { if (lastInventoryEndDate.isEmpty()) { proceedWithInventoryMode(); } LocalDateTime lastInventoryDate = new LocalDateTime(lastInventoryEndDate); if (_24hrsBefore.isAfter(lastInventoryDate)) { proceedWithInventoryMode(); } else { Toast.makeText(getContext(), "Last Inventory ended less than a day ago.", Toast.LENGTH_LONG).show(); Toast.makeText(getContext(), "Last date: " + lastInventoryEndDate, Toast.LENGTH_LONG).show(); } } }) .addOnFailureListener(e -> Toast.makeText(getContext(), "Date couldn't be read.", Toast.LENGTH_LONG).show()); }
运行时抛出IllegalArgumentException异常,onSuccess()回调中打印的lastInventoryEndDate值为"13/07/2022 09:57:11",错误日志如下:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.nati.mvp.flowiusmanage, PID: 18644 java.lang.IllegalArgumentException: Invalid format: "13/07/2022 09:57:11" is malformed at "/07/2022 09:57:11" at org.joda.time.format.DateTimeParserBucket.doParseMillis(DateTimeParserBucket.java:187) at org.joda.time.format.DateTimeFormatter.parseMillis(DateTimeFormatter.java:826) at org.joda.time.convert.StringConverter.getPartialValues(StringConverter.java:87) at org.joda.time.LocalDateTime.<init>(LocalDateTime.java:414) at org.joda.time.LocalDateTime.<init>(LocalDateTime.java:358) at com.nati.mvp.flowiusmanage.fragments.inventoryFragments.InventoryModeFragment.lambda$checkIf24HourReached$2$InventoryModeFragment(InventoryModeFragment.java:157) at com.nati.mvp.flowiusmanage.fragments.inventoryFragments.-$$Lambda$InventoryModeFragment$_kMo6tPuE8p1PpNkIRJgZvJYet8.onSuccess(Unknown Source:6) at com.google.android.gms.tasks.zzm.run(com.google.android.gms:play-services-tasks@@18.0.1:1) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:264) at android.app.ActivityThread.main(ActivityThread.java:7581) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
问题原因
- 直接触发崩溃的原因:代码使用Joda Time的
LocalDateTime(String)构造方法解析日期,该构造方法默认仅支持解析ISO标准格式(类似yyyy-MM-dd'T'HH:mm:ss)的字符串,但从Firestore读取到的日期值为13/07/2022 09:57:11,属于dd/MM/yyyy HH:mm:ss格式(斜杠分隔日/月/年),和默认解析规则不匹配,直接抛出IllegalArgumentException。 - 隐藏逻辑漏洞:判断
lastInventoryEndDate为空字符串的分支中,调用proceedWithInventoryMode()后没有加return终止流程,后续仍会执行日期解析逻辑,空字符串传入解析方法同样会触发格式异常。
修复方案
- 针对现有
dd/MM/yyyy HH:mm:ss格式的日期字符串,手动指定匹配的Joda Time格式化器完成解析,不要直接调用单字符串参数的默认构造方法。 - 补全空值、空字符串判断分支的
return逻辑,避免无效代码继续执行。 - 增加解析异常捕获,避免特殊格式值导致崩溃。
- 长期优化建议:后续在Firestore存储日期时,直接存储Long类型时间戳,读取后可以直接转成
LocalDateTime,完全避免字符串格式不匹配的问题。
修复后的核心解析代码参考:
.addOnSuccessListener(documentSnapshot -> { String lastInventoryEndDate = documentSnapshot.getString("date"); Log.d("lastInventoryEndDate: ", lastInventoryEndDate); // 空值、空字符串直接执行逻辑后返回,不往下走解析流程 if (lastInventoryEndDate == null || lastInventoryEndDate.isEmpty()) { proceedWithInventoryMode(); return; } try { // 指定和存储格式匹配的解析器:dd/MM/yyyy HH:mm:ss DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss"); LocalDateTime lastInventoryDate = LocalDateTime.parse(lastInventoryEndDate, formatter); if (_24hrsBefore.isAfter(lastInventoryDate)) { proceedWithInventoryMode(); } else { Toast.makeText(getContext(), "Last Inventory ended less than a day ago.", Toast.LENGTH_LONG).show(); Toast.makeText(getContext(), "Last date: " + lastInventoryEndDate, Toast.LENGTH_LONG).show(); } } catch (IllegalArgumentException e) { // 捕获格式解析异常,按无有效日期处理 proceedWithInventoryMode(); } })
内容的提问来源于stack exchange,提问作者Alula48
相关产品推荐
相关产品推荐

