关于java:Joda时间 – 两个日期之间的月份差异

Joda Time - difference in months between two dates

本问题已经有最佳答案,请猛点这里访问。

我需要得到两个日期之间的月差异,我使用的是Joda Time,问题是:

1
2
3
4
DateTime date1 = new DateTime().withDate(2015, 2, 1);
DateTime date2 = new DateTime().withDate(2015, 1, 1);
Months m = Months.monthsBetween(date1, date2);
int monthDif = m.getMonths();//this return 0

它返回0是因为这两个日期中间没有月份,所以我需要返回月份之间的差额而不是几个月之间的差额,如果日期相同,则添加1会有问题。


将第一个日期更改为2015-02-02,Joda正确返回1个月:

1
2
3
4
5
DateTime date1 = new DateTime().withDate(2015, 2, 2);
DateTime date2 = new DateTime().withDate(2015, 1, 1);

System.out.println(Months.monthsBetween(date2, date1).getMonths());
// Returns 1.

所以我的猜测是,由于你没有提供时间部分,Joda无法准确地确定2015-01-01 date2所指的时间点。你可能已经提到了23:59:59,在这种情况下,从技术上讲,一个完整的月还不会过去。

如果显式地提供零时间部分,它将按您最初预期的方式工作:

1
2
3
4
5
DateTime date1 = new DateTime().withDate(2015, 2, 1).withTime(0, 0, 0, 0);
DateTime date2 = new DateTime().withDate(2015, 1, 1).withTime(0, 0, 0, 0);

System.out.println(Months.monthsBetween(date2, date1).getMonths());
// Returns 1.

因此,我建议您在每个日期中明确指定00:00:00时间部分。


虽然其他答案是正确的,但它们仍然掩盖了真正的问题。

it returns 0 because there is no month in the middle of the two dates

不。它返回0,因为datetime对象有时间部分。创建两个时间间隔的DateTime,用当前时间(小时、分钟、秒和毫秒)填充,然后修改日期部分。如果你只想比较两个日期,就没有理由这么做。改为使用localdate。

1
2
3
4
LocalDate date1 = new LocalDate(2015, 2, 1);
LocalDate date2 = new LocalDate(2015, 1, 1);
Months m = Months.monthsBetween(date1, date2);
int monthDif = Math.abs(m.getMonths());//this return 1

还需要注意一个事实,即尽管几个月的文档对此一无所知,但如果第一个日期在第二个日期之后,Month可以包含负值。所以我们需要用Math.abs来计算两个日期之间的月数。

博士说:

Creates a Months representing the number of whole months between the two specified partial datetimes.

但事实并非如此。它真的计算了几个月的差额。不是月数。


计算方法取决于要使用的业务逻辑。每个月的长度各不相同。一种选择是,在monthsBetween()函数中,获取date1date2的月初,并进行比较。

类似:

1
2
3
DateTime firstOfMonthDate1 = new DateTime(date1.getYear(), date1.getMonthOfYear(), 1, 0, 0);
DateTime firstOfMonthDate2 = new DateTime(date2.getYear(), date2.getMonthOfYear(), 1, 0, 0);
Months m = Months.monthsBetween(firstOfMonthDate1, firstOfMonthDate2)