Reputation: 419
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.
Upvotes: 2
Views: 961
Reputation: 79550
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
.
Upvotes: 3
Reputation: 152917
Your input data has two digits for fractional seconds. Your input patterns have three. The implementations interpret differently what 09
fractional seconds mean when three digits are expected.
If possible, fix either your input data or your input pattern to agree on the number of fractional digits. If you need to accept both two or three digits of fractional seconds, have a look at How to parse date-time with two or three milliseconds digits in java?
Upvotes: 1