6

I'm using a client library (third party, not mine, cannot change) which utilizes the ThreeTen date types. My project is Java 11 and uses Java 8 date types. What is the recommended way to convert ThreeTeen objects to their Java 8 counterparts?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Fredrik Rambris
  • 316
  • 3
  • 10
  • Note that there can be subtle differences when converting those because AFAIK the ThreeTen uses its own time zone database, whereas the JDK ones might use a different one (might be OS timezone database or JDK-included database, depending on OS). There's not much you can do about that. – Joachim Sauer Jan 21 '20 at 15:39
  • 2
    @JoachimSauer While I don’t know whether that’s true, it’s not relevant for `OffsetDateTime` since they use no time zone. – Ole V.V. Jan 25 '20 at 08:25
  • 2
    @OleV.V.: that's a good point! Regarding it's sepearate TZ-DB, there's a even a [documentation page about updating it](https://www.threeten.org/threetenbp/update-tzdb.html). – Joachim Sauer Jan 26 '20 at 08:04

3 Answers3

6

There seems to be no built-in way to convert one instance to the other.

I think you have write your own converters, like one of the following:

Part-by-part conversion:

public static java.time.OffsetDateTime convertFrom(org.threeten.bp.OffsetDateTime ttOdt) {
    // convert the instance part by part...
    return java.time.OffsetDateTime.of(ttOdt.getYear(), ttOdt.getMonthValue(),
            ttOdt.getDayOfMonth(), ttOdt.getHour(), ttOdt.getMinute(),
            ttOdt.getSecond(), ttOdt.getNano(),
            // ZoneOffset isn't compatible, create one using the seconds of the given
            java.time.ZoneOffset.ofTotalSeconds(ttOdt.getOffset().getTotalSeconds());
}

Parsing the formatted output of the other instance:

public static java.time.OffsetDateTime convertFrom(org.threeten.bp.OffsetDateTime ttOdt) {
    // convert the instance by parsing the formatted output of the given instance
    return java.time.OffsetDateTime.parse(
            ttOdt.format(org.threeten.bp.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}

Haven't tested which one is more efficient...

deHaar
  • 17,687
  • 10
  • 38
  • 51
  • 1
    This is what I ended up doing. I was hoping for a built-in way of doing it. – Fredrik Rambris Jan 22 '20 at 12:20
  • 1
    Just nitpicking, if you really want to do it part by part without formatting and parsing back, using `java.time.ZoneOffset.ofTotalSeconds(ttOdt.getOffset().getTotalSeconds())` could be seen as more consistent. It’s very nice that you give both options. – Ole V.V. Jan 25 '20 at 08:29
4

It may seem that this need has not been foreseen in the design. No really good and natural option exists for this seemingly simple requirement.

I like to have something to choose from. deHaar has already provided two options that are as good as we can get. So just as a supplement here’s a third one: convert via seconds and nanoseconds since the epoch and total offset seconds.

    org.threeten.bp.OffsetDateTime fromThirdParty
            = org.threeten.bp.OffsetDateTime.of(2020, 1, 25, 23, 34, 56, 123456789,
                    org.threeten.bp.ZoneOffset.ofHours(1));

    java.time.Instant jtInstant = java.time.Instant
            .ofEpochSecond(fromThirdParty.toEpochSecond(), fromThirdParty.getNano());
    java.time.ZoneOffset jtOffset = java.time.ZoneOffset.ofTotalSeconds(
            fromThirdParty.getOffset().getTotalSeconds());
    java.time.OffsetDateTime converted
            = java.time.OffsetDateTime.ofInstant(jtInstant, jtOffset);

    System.out.println("From " + fromThirdParty);
    System.out.println("To   " + converted);

Output from this snippet is:

From 2020-01-25T23:34:56.123456789+01:00
To   2020-01-25T23:34:56.123456789+01:00

Possible advantages include: We are transferring 3 numerical fields (vs 7 in deHaar’s first conversion), thus reducing the risk of transferring a wrong value by error. And we still avoid formatting into a string and parsing back (which feels like a waste to me but is nice and short).

And please wrap it into a method with a nice name like deHaar has done.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Great! I didn't consider this option... Thanks! – deHaar Jan 25 '20 at 10:04
  • 1
    @deHaar The fourth option would be converting via `ZonedDateTime` and `GregorianCalendar`. I don’t want to do that. Better avoid `GregorianCalendar`. At least converting via `String` (your second option) is better. – Ole V.V. Jan 25 '20 at 19:11
4

Actually conversion is simple using parse. I was looking for a solution and landed on this thread. Upon inspection I figured there is an easy way so posted here.

java.time.OffsetDateTime odt = java.time.OffsetDateTime.now();
org.threeten.bp.OffsetDateTime ODT = org.threeten.bp.OffsetDateTime.parse(odt.toString());

Similarly to convert vice versa

org.threeten.bp.OffsetDateTime ODT = org.threeten.bp.OffsetDateTime.now();
java.time.OffsetDateTime odt = java.time.OffsetDateTime.parse(ODT.toString());
Prasad
  • 41
  • 1