Java SimpleDateFormat没有给出常量结果

时间:2018-02-01 05:21:39

标签: java simpledateformat

我需要将Java Date对象格式化为类似yyyyMMdd的字符串(round to day)。例如,20180129。我有以下实现:

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);

代码大部分时间都有效,但有时它会生成像2018129这样的结果,这不是我想要的。因此,我的数据库中同时包含201801292018129

应用程序使用来自MQ的消息,并且将消息中的时间戳记录为Java Date对象。它将日期格式化为上面的字符串。

问题是我无法在调试模式下重现该问题。它总是在调试器中产生预期的结果。但是在我在服务器上(在Docker中)运行一段时间之后,我看到了这样的损坏数据。

我想知道为什么SimpleDateFormat在给定有效的Date对象的情况下会有这种不确定的行为?任何想法都将不胜感激。

2 个答案:

答案 0 :(得分:4)

SimpleDateFormat不是线程安全的,请参阅this优秀文章。

java.time.format.DateTimeFormatter是核心Java中此功能的现代线程安全实现。

答案 1 :(得分:1)

TL;博士

请改用线程安全的 java.time 类。

具体来说,请使用LocalDateDateTimeFormatter.BASIC_ISO_DATE

LocalDate.parse(
    "2018129" ,
    DateTimeFormatter.BASIC_ISO_DATE
)
  

2018年1月29日

LocalDate.now()
    .format( DateTimeFormatter.BASIC_ISO_DATE )
  

20180129

线程安全性

您没有提供足够的信息来诊断您的问题。我猜也是:

  • 您正在跨线程使用这些旧的日期时间对象,并且它们不是设计为线程安全的。而是使用 java.time 类, 设计为通过immutable objects模式设计为​​线程安全的。
  • 在你所提到的这个神秘的“约会过程”中你所做的事情出了什么问题,你提到但忽略了解释。

数据类型错误

  

消息中的时间戳记为Java Date对象。

您将一个仅限日期的值放入具有时间的日期类型中。方形钉,圆孔。

相反,请将仅限日期的类型用于仅限日期的值:LocalDate

ISO 8601

您想要的格式YYYYMMDD恰好在ISO 8601标准中定义,作为最小化分隔符使用的“基本”变体。

Java为此提供了一个DateTimeFormatter对象:DateTimeFormatter.BASIC_ISO_DATE。所以不需要定义格式化模式。

String input = "2018129" ;
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;

要生成此类字符串,请使用相同的格式化程序。

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;

顺便说一句,我建议使用ISO 8601格式的全长版本,而不是紧凑的“基本”版本。根据我的经验,保存的少量字节不值得放弃可读性和减少歧义。此外, java.time 类在解析/生成String对象时默认使用全长ISO 8601格式,因此您可以完全省略DateTimeFormatter个对象。

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore