Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to convert a org.joda.time.DateTime to a java.time.OffsetDateTime?

The following works, but it seems a little clumsy to convert the time to a long, and then an Instant as well as converting the timezone to a TimeZone and then a ZoneId. Is there a cleaner way to do this?

java.time.Instant instant = java.time.Instant.ofEpochMilli(jodaDateTime.getMillis());
OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(instant,
        jodaDateTime.getZone().toTimeZone().toZoneId());
like image 888
Alex Spurling Avatar asked Oct 23 '25 04:10

Alex Spurling


1 Answers

That seems to be the general way of doing such conversion.

As the classes from both API's are not interoperable with each other (you can't use Joda's DateTime with Java Time's DateTimeFormatter and so on), the common factor between them seems to be the long epochMilli value.

So I see no better way than creating a java.time.Instant and then converting it to OffsetDateTime using the timezone from Joda's object.

Well, I think there's one thing that can be slightly improved. This code:

jodaDateTime.getZone().toTimeZone().toZoneId()

The toTimeZone() method creates a java.util.Timezone instance, which is used to create a java.time.ZoneId via toZoneId() method.

You can avoid the creation of this temporary TimeZone object by doing:

ZoneId.of(jodaDateTime.getZone().getID())

This code doesn't create the temporary TimeZone object, and creates the ZoneId directly. As Joda's DateTimeZone doesn't work with short IDs (like IST or PST), we can assume that the ID will be recognizable by ZoneId class (as it also works with long ID names, such as Europe/London). It also works if the Joda's DateTimeZone ID is an offset (such as +01:00).

Not sure if avoiding the creation of one temporary object is cleaner enough, but anyway it's an improvement (a tiny one, but it still is).

So, the final code will be very similar to yours, with only the change proposed above:

// java.time.Instant
Instant instant = Instant.ofEpochMilli(jodaDateTime.getMillis());

// create the OffsetDateTime
OffsetDateTime.ofInstant(instant, ZoneId.of(jodaDateTime.getZone().getID()));

There's another alternative (very similiar, but not sure if cleaner): get the total offset (instead of the timezone) and use it to create a java.time.ZoneOffset:

long millis = jodaDateTime.getMillis();
// java.time.Instant
Instant instant = Instant.ofEpochMilli(millis);

// get total offset (joda returns milliseconds, java.time takes seconds)
int offsetSeconds = jodaDateTime.getZone().getOffset(millis) / 1000;
OffsetDateTime.ofInstant(instant, ZoneOffset.ofTotalSeconds(offsetSeconds));

You can also use the suggestion made by @assylias' comment, but I'm not sure if formatting to a String and then parsing it to OffsetDateTime is cleaner than this (although it also works).


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!