We currently in the process of replacing SimpleDateFormat
with DateTimeFormatter
.
During this I came across a weird behavior.
There is a difference in milliseconds which I can't explain to myself.
Here is the code:
val timeString = "2021-09-17T13:37:00.09Z"
val newFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneId.of("UTC"))
val oldFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.US)
val zonedDateTime = newFormatter.parse(timeString)
val newFormatterDate = Date.from(zonedDateTime.toInstant())
val oldFormatterDate = oldFormatter.parse(timeString)
Assert.assertEquals(newFormatterDate, oldFormatterDate) // false
// newFormatterDate.time is 1631885820090 and
// oldFormatterDate.time is 1631885820009
I found a lot of posts here stating that we shouldn't use SimpleDateFormat
anymore.
But can someone explain to me how this could happen? Do we have a bug in our code or misunderstood something?
Edit: The solution provided by @Ole V.V.'s link (How to parse date-time with two or three milliseconds digits in java?) may solve the bug I encounter but it does not answer the question/explain why these two formatters produce different results.
The modern, DateTimeFormatter
considers the digits after seconds as the fraction of a second whereas the legacy, SimpleDateFormat
considers the digits after the seconds as the number of milliseconds.
Let's see how DateTimeFormatter
processes it:
0.09 seconds = 0.09 * 1000 ms = 90 ms
On the other hand, SimpleDateFormat
processes it as 09
milliseconds = 9
milliseconds.
By the way, while using the modern Date-Time API, you do not need to use a DateTimeFormatter
explicitly to parse your Date-Time string because it is already in ISO 8601 format. The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter
object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
Demo:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
System.out.println(Instant.parse("2021-09-17T13:37:00.09Z").toEpochMilli());
}
}
Output:
1631885820090
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
.