1

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?

1 Answer 1

3

First of all, I want to point out the differences, which are severe.

java.time

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.

java.util.Date

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.

Adapter for Legacy Code

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())
Sign up to request clarification or add additional context in comments.

2 Comments

"A Date represents a date and time." - Hm, rather not, a 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.
Thanks for point this out. I edited the section to clarify that the internal state of Date is a timestamp.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.