how to convert from ZonedDateTime to Joda DateTime
Asked Answered
A

3

13

I've switched to threeten for date times but I've still got a 3rd party tool that uses joda to write timestamp with timezone to the database and I need to convert from one to the other. What's the best way? As a workaround I tried DateTime.parse(zdt.toString) but it falls over because joda doesn't like the zone format

Invalid format: "2015-01-25T23:35:07.684Z[Europe/London]" is malformed at "[Europe/London]"

Anderaanderea answered 25/1, 2015 at 23:40 Comment(0)
A
9
ZonedDateTime zdt = 
  ZonedDateTime.of(
    2015, 1, 25, 23, 35, 7, 684000000, 
    ZoneId.of("Europe/London"));

System.out.println(zdt); // 2015-01-25T23:35:07.684Z[Europe/London]
System.out.println(zdt.getZone().getId()); // Europe/London
System.out.println(zdt.toInstant().toEpochMilli()); // 1422228907684

DateTimeZone london = DateTimeZone.forID(zdt.getZone().getId());
DateTime dt = new DateTime(zdt.toInstant().toEpochMilli(), london);
System.out.println(dt); // 2015-01-25T23:35:07.684Z

In case the zone id transformation might crash for any unsupported or unrecognized id, I recommend to

  • catch and log it,
  • do updates of tz-repositories (for Joda: update to latest version, for JDK: use tz-updater-tool)

That is usually the better strategy than to just silently fall back to any arbitrary tz-offset like UTC.

Asyndeton answered 26/1, 2015 at 5:33 Comment(1)
To the downvoters, think twice before you are going to use TimeZone.getTimeZone(...) as suggested in the answer of James Ding. Switching back to UTC for unsupported ids is probably worse than a crash.Asyndeton
S
22

Please notice that using DateTimeZone.forID(...) is not safe, which might throw DateTimeParseException as usually ZoneOffset.UTC has a ID "Z" which cannot be recognized by DateTimeZone.

What I would recommend in order to convert ZonedDateTime to DateTime is:

return new DateTime(
    zonedDateTime.toInstant().toEpochMilli(),
    DateTimeZone.forTimeZone(TimeZone.getTimeZone(zonedDateTime.getZone())));
Stutman answered 19/5, 2016 at 23:2 Comment(3)
This should be the accepted answer. We ran into this exact issue!Warta
@Warta There is no perfect transformation of zone identifiers in every case. While the expression TimeZone.getTimeZone(zoneId) might better work for Z-literals (representing UTC) than Joda-Time, such an expression can silently fail for other ids, but not with an exception, instead with arbitrary fallback to UTC (which is even worse), see the API-doc: "Returns:the specified TimeZone, or the GMT zone if the given ID cannot be understood", my answer just addresses the special example the OP presented in the question, but I don't pretend it to work for every zone id.Asyndeton
The main problem of this suggested answer is that it pretends to work for all identifiers although unrecognized ids can just be switched to UTC by the expression TimeZone.getTimeZone(zoneId) - without any exception. The underlying timezone repositories of Joda-Time and JDK know different sets of valid ids, and this fact cannot be cured by any "genious" or "smart" transformation code.Asyndeton
A
9
ZonedDateTime zdt = 
  ZonedDateTime.of(
    2015, 1, 25, 23, 35, 7, 684000000, 
    ZoneId.of("Europe/London"));

System.out.println(zdt); // 2015-01-25T23:35:07.684Z[Europe/London]
System.out.println(zdt.getZone().getId()); // Europe/London
System.out.println(zdt.toInstant().toEpochMilli()); // 1422228907684

DateTimeZone london = DateTimeZone.forID(zdt.getZone().getId());
DateTime dt = new DateTime(zdt.toInstant().toEpochMilli(), london);
System.out.println(dt); // 2015-01-25T23:35:07.684Z

In case the zone id transformation might crash for any unsupported or unrecognized id, I recommend to

  • catch and log it,
  • do updates of tz-repositories (for Joda: update to latest version, for JDK: use tz-updater-tool)

That is usually the better strategy than to just silently fall back to any arbitrary tz-offset like UTC.

Asyndeton answered 26/1, 2015 at 5:33 Comment(1)
To the downvoters, think twice before you are going to use TimeZone.getTimeZone(...) as suggested in the answer of James Ding. Switching back to UTC for unsupported ids is probably worse than a crash.Asyndeton
C
2

here's a kotlin extension to do the same (in case you code that way)

fun ZonedDateTime.toDateTime(): DateTime =
    DateTime(this.toInstant().toEpochMilli(), 
        DateTimeZone.forTimeZone(TimeZone.getTimeZone(this.zone)))
Celibate answered 17/11, 2016 at 16:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.