如何从 org.joda.time.DateTime 转换为 java.time.ZonedDateTime
How to convert from org.joda.time.DateTime to java.time.ZonedDateTime
我有一个数据源,其中存储了 joda 时间 DateTime 对象。我需要将它们转换成 java ZonedDateTime 对象,保持原来的时区。
仅保留偏移量是不够的,因为某些 DateTime 对象表示日常重复性任务,并且这些任务必须在每个日期的特定时区的特定时间发生。因此,它们必须遵循指定的时区转换,例如夏令时和冬令时。我不知道 DateTime 对象的最终用途,所以我需要保留所有对象的时区信息以确保安全。
如何将org.joda.time.DateTime转换为java.time.ZonedDateTime?
将全部
ord.joda.time.DateTimeZone.getId()
映射到
中可用的 ID
java.time.ZoneId
并非 Joda-Time 中的所有时区字符串都匹配 java.time
,但绝大多数会匹配,因为它们都基于 IANA tz 数据。比较 DateTimeZone.getAvailableIDs()
to ZoneId.getAvailableZoneIds()
to determine the mismatch. Additional identifiers can be mapped using ZoneId.of(String, Map)
.
要以最有效的方式进行主要转换,您必须传入每个字段:
ZonedDateTime zdt = ZonedDateTime.ofLocal(
LocalDateTime.of(
dt.getYear(),
dt.getMonthOfYear(),
dt.getDayOfMonth(),
dt.getHourOfDay(),
dt.getMinuteOfHour(),
dt.getSecondOfMinute(),
dt.getMillisOfSecond() * 1_000_000),
ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS),
ZoneOffset.ofTotalSeconds(dt.getZone().getOffset(dt) / 1000));
注意在这种情况下使用 ZoneId.SHORT_IDS
作为 Map
。
对于处理大多数用例但性能较低的更简单的解决方案,请使用:
ZonedDateTime zdt = dt.toGregorianCalendar().toZonedDateTime();
如果您正在使用夏令时转换,则应避免单独提供每个字段。改为使用 epochMillis 进行转换,如下例所示。
Instant instant = Instant.ofEpochMilli(dt.getMillis());
ZoneId zoneId = ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
否则您将在转换日期损失一小时。例如,德国于 2017 年 10 月 29 日 03:00 GMT+2 从夏令时 (GMT+2) 过渡到冬令时 (GMT+1),变为 02:00 GMT+1。那天,您有 2 个 02:00 实例 - 一个较早的 GMT+2 和一个较晚的 GMT+1。
由于您使用的是 ZoneIds 而不是偏移量,因此无法知道您需要 2 个实例中的哪一个。默认情况下,在转换期间假定第一个。如果您提供 hourOfDay
和 ZoneId,02:00 GMT+2 和 02:00 GMT+1 都将转换为 02:00 GMT+2。
我有一个数据源,其中存储了 joda 时间 DateTime 对象。我需要将它们转换成 java ZonedDateTime 对象,保持原来的时区。
仅保留偏移量是不够的,因为某些 DateTime 对象表示日常重复性任务,并且这些任务必须在每个日期的特定时区的特定时间发生。因此,它们必须遵循指定的时区转换,例如夏令时和冬令时。我不知道 DateTime 对象的最终用途,所以我需要保留所有对象的时区信息以确保安全。
如何将org.joda.time.DateTime转换为java.time.ZonedDateTime?
将全部
ord.joda.time.DateTimeZone.getId()
映射到
中可用的 IDjava.time.ZoneId
并非 Joda-Time 中的所有时区字符串都匹配 java.time
,但绝大多数会匹配,因为它们都基于 IANA tz 数据。比较 DateTimeZone.getAvailableIDs()
to ZoneId.getAvailableZoneIds()
to determine the mismatch. Additional identifiers can be mapped using ZoneId.of(String, Map)
.
要以最有效的方式进行主要转换,您必须传入每个字段:
ZonedDateTime zdt = ZonedDateTime.ofLocal(
LocalDateTime.of(
dt.getYear(),
dt.getMonthOfYear(),
dt.getDayOfMonth(),
dt.getHourOfDay(),
dt.getMinuteOfHour(),
dt.getSecondOfMinute(),
dt.getMillisOfSecond() * 1_000_000),
ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS),
ZoneOffset.ofTotalSeconds(dt.getZone().getOffset(dt) / 1000));
注意在这种情况下使用 ZoneId.SHORT_IDS
作为 Map
。
对于处理大多数用例但性能较低的更简单的解决方案,请使用:
ZonedDateTime zdt = dt.toGregorianCalendar().toZonedDateTime();
如果您正在使用夏令时转换,则应避免单独提供每个字段。改为使用 epochMillis 进行转换,如下例所示。
Instant instant = Instant.ofEpochMilli(dt.getMillis());
ZoneId zoneId = ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
否则您将在转换日期损失一小时。例如,德国于 2017 年 10 月 29 日 03:00 GMT+2 从夏令时 (GMT+2) 过渡到冬令时 (GMT+1),变为 02:00 GMT+1。那天,您有 2 个 02:00 实例 - 一个较早的 GMT+2 和一个较晚的 GMT+1。
由于您使用的是 ZoneIds 而不是偏移量,因此无法知道您需要 2 个实例中的哪一个。默认情况下,在转换期间假定第一个。如果您提供 hourOfDay
和 ZoneId,02:00 GMT+2 和 02:00 GMT+1 都将转换为 02:00 GMT+2。