Рассчитать месячную разницу во времени Joda

В 4-й строке кода (игнорировать пробелы и комментарии) и далее я вычисляю разницу в месяце между двумя датами. Это работает, но выглядит немного хакерским. Есть ли способ лучше?

int handleAllowance(LocalDate today) {

    int allowance = membership.allowance();
    if (allowance == 0) return 0;

    // if update was last month (or earlier)
    int months = today.monthOfYear().getMaximumValue() - today.monthOfYear().getMinimumValue(); // yeah, 12, but just to be 100% correct :-)
    int curMonth = (today.getYear()               * months) + today.              getMonthOfYear();
    int updMonth = (lastAllowanceUpdate.getYear() * months) + lastAllowanceUpdate.getMonthOfYear();
    if (curMonth > updMonth) {

        // ...and if today is on or past update day
        int updateDay = Math.min(allowanceDay, today.dayOfMonth().getMaximumValue());
        if (today.getDayOfMonth() >= updateDay) {

            // number of months to give allowance (in the rare case this process fails to run for 2 months or more)
            int allowanceMonths = curMonth - updMonth;

            // give credits
            final int totalAllowance = allowance * allowanceMonths;
            giveCredits(totalAllowance);

            // update day
            lastAllowanceUpdate = lastAllowanceUpdate.plusMonths(allowanceMonths);

            // return the allowance given
            return totalAllowance;

        }

    }

    return 0;
}

person Bart van Heukelom    schedule 27.07.2011    source источник
comment
Один вопрос, хоть и не по теме: allowance константа? В противном случае final int totalAllowance = allowance * allowanceMonths; может привести к другим результатам для allowanceMonths > 1 по сравнению с запуском всей части allowanceMonths раз.   -  person Thomas    schedule 27.07.2011
comment
Дайте определение константе. Его значение зависит от типа подписки пользователя, который может измениться где-то за этот период в 2 месяца. Хотя в остальном это не меняется. Поэтому я предполагаю, что если процесс не будет работать в течение 2 месяцев, и пользователь решит обновить подписку за день до ее повторного запуска, он получит больше разрешений, чем предполагалось. Это нормально, это не фатальная ошибка, и маловероятно, что allowanceMonths когда-либо действительно будет › 1   -  person Bart van Heukelom    schedule 27.07.2011
comment
Под константой я имел в виду, может ли значение измениться между двумя прогонами и будет ли результат зависеть от кредитов или чего-то подобного? Поскольку у вас, похоже, есть постоянное пособие (если пользователь не изменит тип подписки), это может быть хорошо. Вы также можете сделать это для каждого месяца и получить более точный тип подписки для каждого месяца.   -  person Thomas    schedule 27.07.2011
comment
@Thomas: Я мог бы, но в настоящее время невозможно найти прошлые подписки пользователя, и на самом деле не стоит усилий, чтобы сделать это возможным.   -  person Bart van Heukelom    schedule 27.07.2011


Ответы (3)


Это очень похоже на решение Божо:

  public static YearMonth toYearMonth(LocalDate localDate) {
    return new YearMonth(localDate.getYear(), localDate.getMonthOfYear());
  }

  public static int monthSwitches(LocalDate date1,LocalDate date2) {
    return Months.monthsBetween(toYearMonth(date1),toYearMonth(date2)).getMonths();
  }
person Sebastien Lorber    schedule 11.10.2013
comment
Это решение работает для таких сценариев, как 29/01/2016 и 01/02/2016! - person Lucas Oliveira; 25.04.2016

Это решение, которое я придумал, когда комментировал Божо

int handleAllowance(LocalDate today) {

    int allowance = membership.allowance();
    if (allowance == 0) return 0;

    // calculate month difference
    int allowanceMonths = Months.monthsBetween(lastAllowanceUpdate.withDayOfMonth(1), today.withDayOfMonth(1)).getMonths();

    // if update was last month or earlier
    if (allowanceMonths > 0) {

        // ...and if today is on or past update day
        int updateDay = Math.min(allowanceDay, today.dayOfMonth().getMaximumValue());
        if (today.getDayOfMonth() >= updateDay) {

            // give credits (multiply with months in the rare case this process consecutively fails to run for 2 months or more)
            final int totalAllowance = allowance * allowanceMonths;
            giveCredits(totalAllowance);

            // update day
            lastAllowanceUpdate = lastAllowanceUpdate.plusMonths(allowanceMonths);

            // return the allowance given
            return totalAllowance;

        }

    }

    return 0;
}
person Bart van Heukelom    schedule 27.07.2011

person    schedule
comment
Разве это не вернет 0, если date1 — 31 января, а date2 — 1 февраля? В основном мне нужно отбросить информацию о дне, а затем вычислить разницу ... о, подождите, вот как я могу это сделать. :п - person Bart van Heukelom; 27.07.2011
comment
Я разместил свое решение как ответ - person Bart van Heukelom; 27.07.2011
comment
Я использовал это и получил это org.joda.time.IllegalFieldValueException: Value 0 for dayOfMonth must be in the range [1,28] - person zeddarn; 23.08.2014
comment
@zeddarn Да. В Yoda Time месяцы начинаются с 1 (и дней), а не с Calendar 0. Не забудьте добавить +1, если вы переходите от Calendar к Yoda. - person Matt Leonowicz; 30.12.2015