两个日期之间的小数月差(Scala或Java)

agyaoht7  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(287)

我想知道两次约会之间有多少个月。我的代码现在是这样的

ChronoUnit.MONTHS.between(d1, d2)

问题是,结果是一个漫长的过程。例如,如果日期只有几天不同,我应该得到类似于0.34而不是0的结果。
此外,我需要我的代码来说明日历,我不能假设每个月有31天。

Diff between 1999-05-12 and 1999-08-24
Assuming all months have 31 days for simplicity

result = (19/31 + 31/31 + 31/31 + 24/31) = 2.793
According to the calendar we replace the 31s with the correct number of days for that specific year and month
mf98qq94

mf98qq941#

以下是我的解决方案:

public static double monthsBetween(LocalDate start, LocalDate end) {
    if (start.isAfter(end)) throw new IllegalArgumentException("Start must be before end!");

    var lastDayOfStartMonth = start.with(TemporalAdjusters.lastDayOfMonth());
    var firstDayOfEndMonth = end.with(TemporalAdjusters.firstDayOfMonth());
    var startMonthLength = (double)start.lengthOfMonth();
    var endMonthLength = (double)end.lengthOfMonth();
    if (lastDayOfStartMonth.isAfter(firstDayOfEndMonth)) { // same month
        return ChronoUnit.DAYS.between(start, end) / startMonthLength;
    }
    long months = ChronoUnit.MONTHS.between(lastDayOfStartMonth, firstDayOfEndMonth);
    double startFraction = ChronoUnit.DAYS.between(start, lastDayOfStartMonth.plusDays(1)) / startMonthLength;
    double endFraction = ChronoUnit.DAYS.between(firstDayOfEndMonth, end) / endMonthLength;
    return months + startFraction + endFraction;
}

其想法是使用时间调节器找到start月份的最后一天(lastDayOfStartMonth)和end月份的第一天(firstDayOfEndMonth)。这两个日期非常重要。您想要的数字是:

  • startlastDayOfStartMonth之间的月份分数
  • lastDayOfStartMonthfirstDayOfEndMonth之间的完整月数。
  • firstDayOfEndMonthend之间的月份分数。

还有一种边缘情况,即两个日期都在同一个月内,这很容易处理。
通过使用这个定义,保持了任意两个月的第一天之间的月数始终是整数的良好性质。
请注意,在第一个计算中,您必须将一天加到lastDayOfStartMonth上,因为ChronoUnit.between将上限视为独占,但我们在这里实际上希望将其视为一天。

cnh2zyt3

cnh2zyt32#

要解决此问题,您需要考虑以下情况:

  • 日期属于同一年和月份;
  • 日期属于不同的年份和/或月份;
  • 日期无效。

如果日期属于同一年和月,则结果是两个日期之间的天数除以这个月的天数,可以使用LocalDate.lengthOfMonth()找到。
在一般情况下,日期范围可以分为三个部分:

**两个小数部分在给定日期范围的开始和结束处(对于最简单的情况,当两个数据属于相同的年/月*时,都可以使用该方法进行计算)
*全部,我们可以用ChronoUnit.MONTHS.between()来计算它。

下面是实现的方式(d1-包括,d2-不包括):

public static double getFractionalMonthDiff(LocalDate d1, LocalDate d2) {
    if (d1.isAfter(d2)) throw new IllegalArgumentException(); // or return a value like -1

    if (d1.getYear() == d2.getYear() && d1.getMonth() == d2.getMonth()) { // dates belong to same month and year

        return getFractionalPartOfMonth(d2.getDayOfMonth() - d1.getDayOfMonth(), d1.lengthOfMonth());
    }

    int monthLen1 = d1.lengthOfMonth();

    return getFractionalPartOfMonth(monthLen1 - (d1.getDayOfMonth() - 1), monthLen1) // from the given day of month of the First Date d1 Inclusive to the Last day of month
        + getFractionalPartOfMonth(d2.getDayOfMonth() - 1, d2.lengthOfMonth())       // from the First day of month to given day of month of the Second Date d2 Exclusive (for that reason 1 day was subtracted, and similarly on the previous line 1 day was added)
        + ChronoUnit.MONTHS.between(d1.withDayOfMonth(monthLen1), d2.withDayOfMonth(1));
}

public static double getFractionalPartOfMonth(int daysInterval, int monthLength) {
    return daysInterval / (double) monthLength;
}

相关问题