Starting with Android Studio 4, the great java.time API is available to Android.
In my project, I want to migrate gradually from java.util.Date to the new API.
How can I convert between the two formats?
First of all, I want to point out the differences, which are severe.
The java.time API does a great job in being explicit about different concepts of time, e.g. if you want to represent a certain point in time or a Duration.
In the first case, you can choose if you want to represent a date, time, or both and if you want it to be time zone aware or not, e.g.
LocalDate (date, no time, no time zone)LocalDateTime (date, time, no time zone)ZonedDateTime (date, time, time zone)An Instant represents a timestamp (nanoseconds since 01.01.1970 in UTC). So it's a machine representation of time but also a building block for other classes.
To see all classes see the java.time API documentation.
The methods of Date suggest it represents a date and time. Internally, it stores only a timestamp (milliseconds since 01.01.1970 UTC) and no time zone.
The recommended way to create it is using the time zone aware Calendar class. However, the Date itself is generated by implicitly using the time zone the computer is running on.
Calling toString() the formatted output might show a time zone but it is obtained externally from a Calendar instance, which leads to the confusion Date would store a time zone.
All in all, the API is poorly designed and can be confusing. java.time is far superior and should be used if available.
How are the two APIs connected then? -> via Instant.
In java 8 java.util.Date was extended with two methods:
public static Date from(Instant instant)public Instant toInstant()This is the built-in bridge between both APIs!
We can built further adapter functions on top of that.
Here is an example (in Kotlin) with conversion for the classes LocalDate and LocalDateTime:
/**
* java.util.Date has no explicit time zone but implicitly uses the system's time zone
*/
private val dateZoneId: ZoneId = ZoneId.systemDefault()
fun Date.toLocalDate(): LocalDate = toInstant().atZone(dateZoneId).toLocalDate()
fun LocalDate.toDate(): Date = Date.from(atStartOfDay(dateZoneId).toInstant())
fun Date.toLocalDateTime(): LocalDateTime = toInstant().atZone(dateZoneId).toLocalDateTime()
fun LocalDateTime.toDate(): Date = Date.from(atZone(dateZoneId).toInstant())
java.util.Date directly corresponds to an instant measured in milliseconds since Unix epoch. Well, its method toString() prints the instant as date and time in the default time zone which causes a lot of confusion.Date is a timestamp.