At this point, you might wonder: what’s the difference between Instant and ZonedDateTime?
Like the class Instant, also ZonedDateTime represents a moment in time. But, unlike Instant, ZonedDateTime provides functionality about timezones. But first, let’s describe the commonalities.
Both classes represent a moment in time and use UTC. Both classes can be used for storing an event in a database. So when should I use one instead of the other? Well, as we said before, ZonedDateTime provides more functionalities. In particular, it helps you deal with date-based events, like daylight saving time or DST, and present dates to users. This brings us to another big difference. You shouldn’t make calculations with the Instant class. That’s because date-based events aren’t taken into consideration. Let’s write some code to better understand this concept.
In this example, we’ll try to create a date using ZonedDateTime, then we convert it into an Instant and we try to make some calculations. So write:
val romeZone = ZonedDateTime.of(
LocalDateTime.of(2022, 3, 26, 10, 0, 0),
ZoneId.of("Europe/Rome")
)
We got a date with a specific time zone. Let’s print it:
println(romeZone)
Okay, nothing weird until now.
Now we can perform the calculation. We’ll execute the exact same calculation two times. In the first example, we do the calculation, and first and then we convert the result into an Instant, while the second time, we convert romeZone into an Instant, and then we perform the calculation.
So let’s write:
val instant1 = romeZone.plus(1, ChronoUnit.DAYS).toInstant()
val instant2 = romeZone.toInstant().plus(1, ChronoUnit.DAYS)
Now we can print both and check the difference.
println(instant1)
println(instant2)
Why do we have one hour’s difference between instant1 and instant2? In Italy, between the 26th and 27th of March, daylight saving time applies. This moves the clock forward one hour. In this case, one day is 23 hours instead of 24 hours. intant2 is wrong because the Instant class doesn’t take into account such events like DST.
In other cases where you want to make calculations on a date, getting a result that doesn’t depend on the DST, you can perform them directly on the ZonedDateTime instance.
To keep the same example, write:
val zone1 = romeZone.plus(1, ChronoUnit.DAYS)
And print it:
println(zone1)
You can see it returns the same hour, but the time zone has changed.
You can always save an event, like a log, using Instant and convert it into ZonedDateTime later if you need to visualize it within a specific time zone.
To do that, you can simply create an Instant:
val currentInstant = Instant.now()
And convert it calling the method atZone as we did in the previous tutorial:
val ztdFromInstant = currentInstant.atZone(ZoneId.systemDefault())
Let’s print it and see the result:
println("ztdFromInstant: $ztdFromInstant")