Reputation: 3910
I need to format the Java Date object into a String like yyyyMMdd
(round to day). For e.g, 20180129
. I have the following implementation:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);
The code works most the time, but sometimes it'll generate results like 2018129
, which is not what I want. So I'll have both 20180129
and 2018129
in my database.
The app consumes messages from a MQ and ummarshalls the timestamp in the message into a Java Date object. And it formats the date into a the above String.
The issue is that I cannot reproduce the issue in debug mode. It always produces the expected results in the debugger. But after I ran it on a server (in Docker) for some time, I see such corrupted data.
I wonder why the SimpleDateFormat
could have such undetermined behavior given a valid Date object? Any idea will be appreciated.
Upvotes: 0
Views: 843
Reputation: 338604
Use the thread-safe java.time classes instead.
Specifically, use LocalDate
and DateTimeFormatter.BASIC_ISO_DATE
.
LocalDate.parse(
"2018129" ,
DateTimeFormatter.BASIC_ISO_DATE
)
2018-01-29
LocalDate.now()
.format( DateTimeFormatter.BASIC_ISO_DATE )
20180129
You do not provide enough information to diagnose your problem. I would guess either:
timestamp in the message into a Java Date object.
You are putting a date-only value into a date-with-time-of-day type. Square peg, round hole.
Instead, use a date-only type for a date-only value: LocalDate
.
Your desired format YYYYMMDD happens to be defined in the ISO 8601 standard, as the “basic” variant where the use of delimiters is minimized.
Java provides a DateTimeFormatter
object for this purpose: DateTimeFormatter.BASIC_ISO_DATE
. So no need to define a formatting pattern.
String input = "2018129" ;
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;
To generate such a string, use the same formatter.
LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
By the way, I recommend using the full-length versions of ISO 8601 formats rather than the compact “basic” variants. The few bytes saved are not worth giving up the readability and reduced ambiguity, in my experience. Plus, the java.time classes use the full-length ISO 8601 formats by default when parsing/generating String
objects, so you can dispense with DateTimeFormatter
objects entirely.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Upvotes: 1