9

At the 4th line of code (ignore whitespace & comments) and beyond I'm calculating the month difference between 2 dates. This works, but looks a bit hacky. Is there a better way?

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;
}
Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • One question, though off topic: is `allowance` constan? If not, `final int totalAllowance = allowance * allowanceMonths;` might produce different results for `allowanceMonths > 1` compared to running that whole part `allowanceMonths` times. – Thomas Jul 27 '11 at 12:21
  • Define constant. Its value depends on the subscription type of the user, which can change somewhere in that period of 2 months. It doesn't change in any other way though. So I suppose if the process fails to run for 2 months and the user decides to upgrade the subscription the day before it runs again, he gets more allowance than intended. That's fine though, it's not a fatal error and it's highly unlikely `allowanceMonths` will ever really be > 1 – Bart van Heukelom Jul 27 '11 at 12:26
  • With constant I meant "can the value change between two runs and would the result depend on the credits or similar"? Since you seem have a constant allowance (unless the user changes the subscription type) this might be fine. You could also do that for every month and get the subscription type for each month to be more accurate. – Thomas Jul 27 '11 at 12:32
  • @Thomas: I could, but it's currently impossible to find user's past subscriptions, and not really worth the effort to make it possible. – Bart van Heukelom Jul 27 '11 at 12:44

3 Answers3

27
Months.monthsBetween(
     start.withDayOfMonth(1),
     end.withDayOfMonth(1)).getMonths()
Elhanan Mishraky
  • 2,736
  • 24
  • 26
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
2

This is pretty similar to Bozho's solution:

  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();
  }
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
1

This is the solution I came up with when commenting on Bozho

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;
}
Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301