我需要将Java Date对象格式化为类似yyyyMMdd
的字符串(round to day)。例如,20180129
。我有以下实现:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);
代码大部分时间都有效,但有时它会生成像2018129
这样的结果,这不是我想要的。因此,我的数据库中同时包含20180129
和2018129
。
应用程序使用来自MQ的消息,并且将消息中的时间戳记录为Java Date对象。它将日期格式化为上面的字符串。
问题是我无法在调试模式下重现该问题。它总是在调试器中产生预期的结果。但是在我在服务器上(在Docker中)运行一段时间之后,我看到了这样的损坏数据。
我想知道为什么SimpleDateFormat
在给定有效的Date对象的情况下会有这种不确定的行为?任何想法都将不胜感激。
答案 0 :(得分:4)
SimpleDateFormat
不是线程安全的,请参阅this优秀文章。
java.time.format.DateTimeFormatter
是核心Java中此功能的现代线程安全实现。
答案 1 :(得分:1)
请改用线程安全的 java.time 类。
具体来说,请使用LocalDate
和DateTimeFormatter.BASIC_ISO_DATE
。
LocalDate.parse(
"2018129" ,
DateTimeFormatter.BASIC_ISO_DATE
)
2018年1月29日
LocalDate.now()
.format( DateTimeFormatter.BASIC_ISO_DATE )
20180129
您没有提供足够的信息来诊断您的问题。我猜也是:
消息中的时间戳记为Java Date对象。
您将一个仅限日期的值放入具有时间的日期类型中。方形钉,圆孔。
相反,请将仅限日期的类型用于仅限日期的值:LocalDate
。
您想要的格式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 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance 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的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。