Joda时间和Java8时间差

Joda时间和Java8时间差,java,java-8,jodatime,date-difference,jsr310,Java,Java 8,Jodatime,Date Difference,Jsr310,我正在寻找一个解决方案来计算两个日期之间的月份。我认为joda或java8 time可以做到这一点。但当我比较它们时,我发现了一些非常奇怪的东西 import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.ut

我正在寻找一个解决方案来计算两个日期之间的月份。我认为joda或java8 time可以做到这一点。但当我比较它们时,我发现了一些非常奇怪的东西

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import org.joda.time.Months;

public class DateMain {
    public static void main(String[] args) throws ParseException {

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    Date d1 = simpleDateFormat.parse("2017-01-28 00:00:00.000");
    Date d2 = simpleDateFormat.parse("2017-02-28 00:00:00.000");

    System.out.println("Test Cast 1");
    System.out.println("joda time api result: " + monthsBetweenJoda(d1, d2) + " month");
    System.out.println("java8 time api result: " + monthsBetweenJava8(d1, d2) + " month");

    Date dd1 = simpleDateFormat.parse("2017-01-29 00:00:00.000");
    Date dd2 = simpleDateFormat.parse("2017-02-28 00:00:00.000");

    System.out.println("Test Cast 2");
    System.out.println("joda time api result: " + monthsBetweenJoda(dd1, dd2) + " month");
    System.out.println("java8 time api result: " + monthsBetweenJava8(dd1, dd2) + " month");
}

public static int monthsBetweenJoda(Date fromDate, Date toDate) {
    if (fromDate == null || toDate == null) {
        throw new IllegalArgumentException();
    }
    org.joda.time.LocalDateTime fromLocalDateTime = org.joda.time.LocalDateTime
        .fromDateFields(fromDate);
    org.joda.time.LocalDateTime toLocalDateTime = org.joda.time.LocalDateTime
        .fromDateFields(toDate);
    Months months = Months.monthsBetween(fromLocalDateTime, toLocalDateTime);
    return months.getMonths();
}

public static long monthsBetweenJava8(Date fromDate, Date toDate) {
    if (fromDate == null || toDate == null) {
        throw new IllegalArgumentException();
    }
    LocalDateTime ldt1 = fromDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    LocalDateTime ldt2 = toDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    return ChronoUnit.MONTHS.between(ldt1, ldt2);
}

}
结果如下:

Test Cast 1
joda time api result: 1 month
java8 time api result: 1 month
Test Cast 2
joda time api result: 1 month
java8 time api result: 0 month
我对测试用例2感到非常困惑,哪一个是合理的


对不起,这是我的第一个问题。已完成的代码附加。

Joda Time和Java 8
Java.Time.
有不同的算法来确定两个时间之间的月数

java.time.*
只声明一个月的某一天(或下一个月)过了一个月。从
2017-01-29
2017-02-28
很明显,月份的第二天(28)比第一天(29)短,因此一个月尚未完成

Joda Time声明一个月已经过去,因为向
2017-01-29
添加一个月将产生
2017-02-28


两者都是合理的算法,但我相信
java.time.*
算法更符合人们的期望(这就是为什么我在编写
java.time.*
时选择了不同的算法)。

Joda在我看来是错的。它的文档显示了整月数,但您的测试与此不一致。@JoeC:我怀疑它取的是最大的数,例如
fromDate.plusMonths(x)您使用的是
java.sql.Date
还是
java.util.Date
?请记录这一事实,并说明如何生成作为参数对传递的
Date
对象。并显示如何生成输出字符串。您的输出与
java.sql.Date
java.util.Date
上的
toString
方法的输出不匹配。为我们提供一个新的解决方案。所示代码不完整,因此我们无法复制您的scenario.Hm。没有明确提到该方法如何处理可变长度的单位(如
或几乎所有这些单位)。我的实现最终调用的是(非基于时间的单位)反过来调用的单位。然而,如果
end.time.isBefore(time)
,它可能会将结束日期缩短一天-也许在您的测试中就是这样(尽管从您的输出来看它与此不同)?让我不安的是,这是Java8时间中的决定。因此,每次我们有一个2月28日,从1月29日到3月1日只有一个月的时间——对我来说似乎是错误的,特别是因为在2月28日将一个月添加到1月29日的结果。我该如何处理这件事,这样我就可以告诉自己“让它去吧”?