问题 将Java 8的LocalDateTime转换为Joda的LocalDateTime的简便方法


有没有简单的方法将Java 8的LocalDateTime转换为Joda的LocalDateTime?

其中一种方法是将其转换为String,然后从该String创建Joda的LocalDateTime。


4503
2017-10-09 04:54


起源

将其转换为ISO格式 String 并再次解析它。从纪元开始将其转换为毫秒 - MadProgrammer
是。我做了同样的事情。 - Naresh
如果您已经使用过,为什么要使用Joda Time java.time? - Tom
我在我的应用程序中使用java.time。我的应用程序依赖于使用Joda时间的库。这是我需要这种转换的特殊情况。 - Naresh


答案:


通过epoch millis转换(基本上是一个 java.util.Date()):

java.time.LocalDateTime java8LocalDateTime = java.time.LocalDateTime.now();

// Separate steps, showing intermediate types
java.time.ZonedDateTime java8ZonedDateTime = java8LocalDateTime.atZone(ZoneId.systemDefault());
java.time.Instant java8Instant = java8ZonedDateTime.toInstant();
long millis = java8Instant.toEpochMilli();
org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime(millis);

// Chained
org.joda.time.LocalDateTime jodaLocalDateTime =
        new org.joda.time.LocalDateTime(
            java8LocalDateTime.atZone(ZoneId.systemDefault())
                              .toInstant()
                              .toEpochMilli()
        );

// One-liner
org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime(java8LocalDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

单线,但很长,所以“容易”?这都是相对的。


10
2017-10-09 05:35





两种localDate类型都包含 (year, month, date),所以只需复制这些值:

public static org.joda.time.LocalDate toJoda(java.time.LocalDate input) {
    return new org.joda.time.LocalDate(input.getYear(),
                                       input.getMonthValue(),
                                       input.getDayOfMonth());
}

2
2017-10-11 13:09



问题是关于LocalDateTime,而不是LocalDate。 - Alex Spurling


稍微短一点的方法:
如果你能逃脱使用 ZoneOffset 代替 ZoneId 那么代码可能会略微缩短。

java.time.LocalDateTime java8LDT = java.time.LocalDateTime.now();
org.joda.time.LocalDateTime jodaLDT = new org.joda.time.LocalDateTime(
    java8LDT.toInstant(ZoneOffset.UTC).toEpochMilli()
);

打电话给 atZone() 可以通过提供时区偏移来删除方法 toInstant() 方法。

更详细的解释
为了澄清,我删除的步骤是创建中间ZonedDateTime对象。在与Joda做任何事之前,序列的这一部分仍然使用Java 8 API。

转换过程首先涉及将Java 8 LocalDateTime转换为自纪元以来的millis数。这可以通过几种不同的方式实现。例如在Andreas的回答中:

LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Instant instant = zdt.toInstant();
long millis = instant.toEpochMilli();

或者我的选择:

LocalDateTime ldt = LocalDateTime.now();
Instant instant = ldt.toInstant(ZoneOffset.UTC);
long millis = instant.toEpochMilli();

不同之处在于我正在跳过创建Java 8 ZonedDateTime,而是将时区偏移量传递给 toInstant() 方法。

从这一点上两个答案是一样的。

org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime(millis);

注意事项
在使用一致偏移进行转换时,这种方法很有效,不会应用夏令时更改。例如,UTC总是+0:00。如果您需要转换为偏移量可以更改的本地时区,那么您需要使用稍长的答案 atZone()

具有两个API(Java 8和Joda)的LocalDateTime是没有时区的DateTime。但是,如果您有自纪元以来的毫秒数,那么您需要一个偏移来获得日期和时间。 Java 8 API要求显式传入偏移量或时区,而如果没有传递,则Joda API将使用系统默认值。

构建Joda LocalDateTime的更精确方法是:

org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime(millis, DateTimeZone.UTC);

这只会在施工期间使用时区来获得正确的日期和时间。一旦构造函数完成,时区将不会形成对象的一部分,因为LocalDateTime没有时区。


-1
2018-02-13 15:02



小心: java8LDT.toInstant(ZoneOffset.UTC).toEpochMilli()导致不同的结果 java8LDT.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 系统没有在systemDefault UTC运行!! - Volker Seibt
你可以得到合适的偏移量 ZoneId.systemDefault().getRules().getOffset(java8LDT), 但我觉得 atZone(..).toInstant()...更容易。 - Volker Seibt
这只是一个例子!在练习中你不会打电话 .now()在Java 8中,当你可以直接从Joda获得当前时间时转换为Joda。您需要知道适用的隐式时区 java8LDT 并使用正确的偏移量。我可以看到为什么这个例子可能会被误导。 - Ben Thurley
.now() 不是重点。不同的是使用 systemDefault 代替 ZoneOffset.UTC。因此,无论哪个时区是systemDefault,所选答案的代码都会在每台计算机上运行。 - Volker Seibt
当然,你不应该总是使用 systemDefault() 我从来没有这么说过 - Volker Seibt