版权声明:本文为博主原创文章,如有错误劳烦指正。转载请声明出处,便于读取最新内容。——Bestcxx https://blog.csdn.net/bestcxx/article/details/87106971
前言
利息计算是一种常见的需求,尤其在现在这种分期还款场景比较常见的情况下。
需求描述
用户可以分期归还利息
多期,每一期利率不同,天数不同
利息计算以本金为基准,不设置利滚利
可以设置免息日,免息日内不计算利息
第一期和免息日起始时间是同一天
对于超于最后一个利率规则的天数按照最后一个利率规则计算利息
思路描述
1、为分期利率设置数据结构,比如第几期,利率,计息天数
2、使用循环遍历的方式判断
2.1、每一期内的计息天数
2.2、每一期内的免息天数
2.3、如果是最后一期,则需要考虑多余的天数也按照这个利率进行计算
代码实现
利率规则实体
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* 分期利率信息实体
* @author jie.wu
*/
public class Rates{
private int index;//第几阶段利率
private int days;//本利率执行天数 比如 第1-10天,1%;第11-20天,2%;第21-30天,3%
private String rates;//利率值
public Rates(){}
public Rates(int index,int days,String rates){
this.index=index;
this.days=days;
this.rates=rates;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getDays() {
return days;
}
public void setDays(int days) {
this.days = days;
}
public String getRates() {
return rates;
}
public void setRates(String rates) {
this.rates = rates;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
工具方法-计算第 j 阶段前(0到j-1)阶段一共几天
比如第一阶段10天,第二阶段10天,则第三阶段这个方法返回20
/**
* 计算本阶段之前一共有几天
* @param j
* @param ratesArray
* @return
*/
private static int getForeDays(int j,Rates[] ratesArray){
int foreDays=0;
for(int i=0;i<j;i++){
foreDays+=ratesArray[i].getDays();
}
return foreDays;
}
- 计算第 j 阶段需要计算的利息天数
需要考虑免息日的情况
/**
* 计算第 j 阶段需要计算利息的天数
* 对于垫资天数超过所有设定阶段天数总和的,多余的天数按照最后一个利率进行计算
* @param j 第几阶段-从0计数
* @param freeDays 免息日
* @param fullDays 总垫资日
* @param ratesArray 利率设定数组
* @return
*/
private static BigDecimal getTemDays(int j,int freeDays,int fullDays,Rates[] ratesArray){
//如果是第一阶段
if(j==0){
//本阶段减去免息日
//如果为正值则取该值
//如果为负值,则本阶段不计算利息
return new BigDecimal(ratesArray[j].getDays()-freeDays>0?ratesArray[j].getDays()-freeDays:0);
}
//如果是最后一个阶段
if(j==ratesArray.length-1){
//计算之前几个阶段的天数和-不包括本阶段
int foreDays=getForeDays(j,ratesArray);
//计算本阶段以及之后阶段免息日天数
int temfreeDays=freeDays-foreDays>0?freeDays-foreDays:0;
//计算本阶段垫资的天数
int temDays=fullDays-foreDays>0?fullDays-foreDays:0;
//将本阶段之后的天数也作为本阶段来考虑
//将本阶段免息日期考虑进来
temDays=temDays-temfreeDays>0?temDays-temfreeDays:0;
return new BigDecimal(temDays);
}else{
//计算之前几个阶段的天数和-不包括本阶段
int foreDays=getForeDays(j,ratesArray);
//计算本阶段以及之后阶段免息日天数
int temfreeDays=freeDays-foreDays>0?freeDays-foreDays:0;
//计算本阶段垫资的天数
int temDays=fullDays-foreDays>0?fullDays-foreDays:0;
//考虑总垫资天数超过本阶段的情况,则本阶段仅取本阶段的天数
if(temDays>ratesArray[j].getDays()){
temDays=ratesArray[j].getDays();
}
//将本阶段免息日期考虑进来
temDays=temDays-temfreeDays>0?temDays-temfreeDays:0;
return new BigDecimal(temDays);
}
}
测试方法
@Test
public void testMethod(){
long beginDate=new Date().getTime();
//今天距离垫资日天数
int fullDays=987;
//免息日为 3 天
int freeDays=2;
//本金
BigDecimal principal=new BigDecimal("100");
//分期利率规则 json 字符串
String arrayStr="[{\"days\":10,\"index\":1,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":2,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":3,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":4,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":5,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":6,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":7,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":8,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":9,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":10,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":11,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":12,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":13,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":14,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":15,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":16,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":17,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":18,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":19,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":20,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":21,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":22,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":23,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":24,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":25,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":26,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":27,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":28,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":29,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":30,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":31,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":32,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":33,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":34,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":35,\"rates\":\"0.01\"},"
+ "{\"days\":10,\"index\":36,\"rates\":\"0.01\"}]";
//将字符串转化为 JSONArray 对象
JSONArray array=JSONArray.fromObject(arrayStr);
//数组长度
int size=array.size();
Rates[] ratesArray=new Rates[size];
//按照排序将利率存放到数组
for(int i=0;i<array.size();i++){
Rates rates=(Rates)JSONObject.toBean((JSONObject) array.get(i),Rates.class);
ratesArray[rates.getIndex()-1]=rates;
}
//程序运行到这里,利率已经按照先后顺序排列好了
//利息总金额
BigDecimal sumInterest=new BigDecimal("0");
for(int j=0;j<ratesArray.length;j++){
//都只计算本阶段都利率
//现在是第 j 阶段
System.out.print("现在是第"+j+"阶段;");
//计算借款天数在本阶段借款天数-需要考虑免息日第情况
//如果是最后一个利率阶段,垫资天数还在延续,则将多余天数计算到最后一个利率中
BigDecimal temDays=getTemDays(j,freeDays,fullDays,ratesArray);
//本阶段的利息
BigDecimal temInterest=new BigDecimal("0");
temInterest=new BigDecimal(ratesArray[j].getRates()).multiply(temDays).multiply(principal);
System.out.println("本阶段的利息为:"+temInterest);
sumInterest=sumInterest.add(temInterest);
}
long endDate=new Date().getTime();
System.out.println("最后利息总额:"+sumInterest+";耗时:"+(endDate-beginDate));
}