android - SimpleDateFormat以奇怪的方式解析数据。错误的月份或/和年份

时间:2016-09-16 15:23:51

标签: java android date time simpledateformat

我有以下代码段:

final Date d = format.parse(value);
LOGGER.debug("Compare:\nOriginal: {}, Format: {}, Result: {}", value, format.toPattern(), d);
return d;

value是来自json的字符串值,

format是java.text.SimpleDateFormat,

d是从value

解析的日期

有时它工作正常,但有时会返回奇怪的日期。

来自logcat的示例:

D/App: 20:14:47.309 com.example.backend.BackendHelper - Compare:
     Original: 2016-09-16 13:45:00.000+0200, Format: yyyy-MM-dd HH:mm:ss.SSSZ, Result: Fri Jan 01 05:00:00 GMT+07:00 2016
D/App: 20:14:47.309 com.example.backend.BackendHelper - Compare:
     Original: 2016-09-16 13:20:00.000+0200, Format: yyyy-MM-dd HH:mm:ss.SSSZ, Result: Fri Jan 01 18:20:00 GMT+07:00 2016
D/App: 20:14:47.338 com.example.backend.BackendHelper - Compare:
     Original: 2016-09-16 15:20:00.000+0200, Format: yyyy-MM-dd HH:mm:ss.SSSZ, Result: Thu Jan 01 05:00:00 GMT+07:00 1970

正如您所看到的,它为String值返回了错误的日期(错误的年份或/和月份或/和小时),这些值具有完全相同的格式,并且仅按小时和分钟相互不同。

问题是:为什么

1 个答案:

答案 0 :(得分:5)

您的格式模式是正确的。而且这里的语言环境不相关。

嗯,您还在问题中提供了输入,以便我们调查是否存在任何不可打印的字符。没有(并且JSON不会产生这样的废话 - 非常不可能)。

因此,对于观察到的不可预测行为的解释是缺乏线程安全性。 SimpleDateFormat不是线程安全的,不幸的是(并且还有许多其他缺点)。因此,只存储一个SimpleDateFormat实例作为静态类字段确实很危险。

如何规避SimpleDateFormat的限制?

  • 将调用同步到parse() - 方法(导致性能损失)
  • SimpleDateFormat - 对象存储到ThreadLocal(更好)
  • 使用FastDateFormat(性能可与ThreadLocale解决方案相媲美,前缀" Fast"现在有点过时了)
  • 使用ThreetenABP - 库(围绕Java-8中包含的新时间库包java.time的后端的Android适配),提供不可变的解析器),例如:OffsetDateTime.parse(input, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ"))
  • 使用Joda-Time-Android(比ThreetenABP更快的解析,也是不可变的),例如:DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSSZ").parseDateTime(input)
  • 或试用我的库Time4A(恕我直言,最快的解决方案,也是不可变的),例如:ChronoFormatter.ofMomentPattern("yyyy-MM-dd HH:mm:ss.SSSZ", PatternType.CLDR, Locale.ROOT, ZonalOffset.UTC).parse(input)

选择不可变格式化程序/解析器无疑是多线程环境中最好,最现代的方法。对于Android,Apache Commons和ThreetenABP库比Joda-Time或Time4A更快的替代品更紧凑。您必须自己评估哪些对您来说更重要,无论是大小还是性能(或者您需要的其他功能)。