3

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());
Alex Spurling
  • 54,094
  • 23
  • 70
  • 76
  • 4
    That looks to be the expected complexity of the solution – Chris Gerken Sep 27 '16 at 11:18
  • 2
    It looks fine - if performance is not a concern you could do it via strings: `OffsetDateTime.parse(ISODateTimeFormat.dateTime().fmt(jodaDateTime), DateTimeFormatter.ISO_OFFSET_DATE_TIME);` - not sure it's less clumsy though... – assylias Sep 27 '16 at 11:34
  • 2
    I would suggest you just use one or the other in your code. Using both joda.time and java-time you can get into complications and confusions in your code. The other solution you could do is to use a formatter to output your time from joda to string, then deserialize it using a different JavaTime Formatter. – Bojan Petkovic Mar 03 '17 at 18:05

1 Answers1

6

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).