How to create a Bank Calendar with 30 days each mo

2019-05-11 01:57发布

问题:

For calculating annuity loan with german I need a calendar where every month has exactly 30 days. Every year has 360 days. There are no leap years.

The interest is allways calculated on a basis of 30 day (That's the german interest method)

I'm using Java 8. What possibilities do I have with the new java.time API to accomplish my requirements?

回答1:

What you describe is a day count not a calendar system. A day count is a mechanism for converting the period between two dates into a year fraction.

OpenGamma OG-Commons includes implementations of many day counts, including 30E/360 which may be the method you need.



回答2:

With Java-8 there are in principle two options for implementing any calendar:

  • Using the interfaces ChronoLocalDate and Chronology as starting point
  • Using the interface Temporal

In my honest opinion, both options are a no-go in your use case. The first option using the java.time.chrono-package forces you to bother with era, year-of-era etc. which is not relevant at all for 360-day-calendars. The second option is too abstract and simple to offer any surplus value compared with just implementing your calendar from the scratch.

A first starting point would be to study the literature and internet, for example in extreme short Wikipedia. It is also important to recognize and take into your design considerations that such a 360-day-"calendar" is not a calendar in strict sense because it does not define a unique and bijective mapping from the calendar date to julian days (several equal dates might belong to different real days! - another important reason to reject the use of chrono-package). The practical consequence would be only to define conversion/factory methods like

Financial360DayCalendar f360 = Financial360DayCalendar.of(LocalDate date);

but not the reverse direction. Beyond the question of mapping/conversion, the calculation of the duration in days between two such dates is the main issue in this "calendar". If you solve both aspects then your task is done. More stuff is probably not needed unless you need formatting. For formatting purposes, you might consider implementing the Java-8-interface TemporalAccessor.

An (incomplete) idea:

class Financial360DayCalendar {
  private final int year;
  private final int month;
  private final int dayOfMonth;

  private Financial360DayCalendar(int year, int month, int dayOfMonth) {
    this.year = year;
    this.month = month;
    this.dayOfMonth = dayOfMonth;
  }

  public static Financial360DayCalendar of(LocalDate date) {
    int year = date.getYear();
    int month = date.getMonthValue();
    int dayOfMonth = date.getDayOfMonth();

    if (dayOfMonth == 31) {
      dayOfMonth = 30;
    }

    return new Financial360DayCalendar(year, month, dayOfMonth);
  }

  public int durationInDaysUntil(Financial360DayCalendar other) {
    // check also if other is not before this instance
    // ...
    // special algorithm (handling all intervening months as 30 days long)
    int interestDays = 30 - this.dayOfMonth(); // current day excluded
    int monthDelta = other.getMonthCount() - this.getMonthCount();
    if (monthDelta > 0) {
      monthDelta--;
    }
    interestDays += (30 * monthDelta + other.dayOfMonth);
    return interestDays;
  }

  public double getYearFraction(Financial360DayCalendar other) {
    return durationInDaysUntil(other) / 360.0;
  }

  private int getMonthCount() {
    return this.year * 12 + this.month;
  }
}

So it is rather a method for calculating interests, not a real calendar system. You can also refer to this website (in German) to see the details how to calculate the duration.



回答3:

You should use standard calendar, there is no need to make a custom one. If you need to calculate a days between two dates based on 30 days month, use something like this method:

public int calculateDays(Date d1, Date d2) {

    int months = 0;
    int days = 0;

    months = Months.monthsBetween(new DateTime(d1), new DateTime(d2)).getMonths();

    int endOfMonth = d1.getDate() == 31 ? 31 : 30;

    if(d1.getDate() > d2.getDate()){
        days = endOfMonth - d1.getDate() + d2.getDate();
    }else{
        days = d2.getDate() - d1.getDate();
    }
    months = months * 30;
    days = months + days;

    return days;
}

I used JodaTime to simplify implementation.