分期利息计算——考虑免息日期和多利率设定的思路设计和代码实现

前言

利息计算是一种常见的需求,尤其在现在这种分期还款场景比较常见的情况下。

需求描述

用户可以分期归还利息
多期,每一期利率不同,天数不同
利息计算以本金为基准,不设置利滚利
可以设置免息日,免息日内不计算利息
第一期和免息日起始时间是同一天
对于超于最后一个利率规则的天数按照最后一个利率规则计算利息

思路描述

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));
		
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值