信贷分期等额本息,等额本金等还款计划计算方式

核算类:



/**
 * 信贷分期核算计息工具类
 * @author XiaoBin Shang
 * @date 2018-09-18
 * @version 1.0 增加等额本金计算方式 增加等额本息计算方式
 * @version 2.0 本金,利息一律保留四位小数
 * @version 2.0 本金,剩余本金两位小数(解决差一分的问题),利息一律保留二位小数
 *
 */
public class LoanPrincipalAndInerestCaculateUtils {
	
	
	
	/**
	 * 按月利率 等本等息计算工具方法
	 * @param calPutoutDayInterestDay 放款日是否起息
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param dayInterestRate  日利率
	 * @param loanDate 贷款时间
	 * @return
	 * @throws ParseException 
	 */
	public static List<InstallmentResult> equalityPrincipalEqualityInterestOfMonthInterestRate(int calPutoutDayInterestDay,int termRate,double loanAmt,double dayInterestRate,String loanDate) throws ParseException {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		double monthInterestRate = Arith.div(dayInterestRate*365/100, 12, Arith.FOUR_SCALE);//月利率
		//剩余应还本金
		Double balance = loanAmt;
		//计算每期应还本金
		double principalAmt = Arith.div(loanAmt, termRate,Arith.TWO_SCALE);
		String payDate = null;
		//计算每期利息,剩余本金
		InstallmentResult installMentResult = null;
		for(int i = 0 ;i < termRate;i++) {
			installMentResult = new InstallmentResult();
			double interestAmt = Arith.mul(loanAmt, monthInterestRate, Arith.TWO_SCALE);
			if(i == 0){
				double v1 = Arith.mul(loanAmt,dayInterestRate,Arith.FOUR_SCALE);
				v1 = Arith.div(v1,100);
				v1 = Arith.mul(v1, calPutoutDayInterestDay,Arith.TWO_SCALE);
				interestAmt = Arith.add(v1, interestAmt);
			}
			payDate = DateHelper.addMonth(loanDate,1+i);
			Double sumPrincipalAndInterestAmt = Arith.add(principalAmt, interestAmt);
			double balance1 = Arith.sub(loanAmt, Arith.mul(i+1, principalAmt));
			balance = balance1 < 0 ? 0.00d : Arith.round(balance1, Arith.FOUR_SCALE);
			if( i + 1 == termRate) {//补全最后一期金额
				principalAmt = Arith.add(principalAmt , balance, Arith.FOUR_SCALE);
				balance =0.0;
			}
			installMentResult.setPrincipalAmt(Arith.round(principalAmt, Arith.TWO_SCALE));
			installMentResult.setInterestAmt(Arith.round(interestAmt,Arith.TWO_SCALE));
			installMentResult.setPrincipalAndInterestAmt(Arith.round(sumPrincipalAndInterestAmt,Arith.TWO_SCALE));
			installMentResult.setBalance(Arith.round(balance,Arith.TWO_SCALE));
			installMentResult.setPeriod(i+1);
			installMentResult.setPayDate(payDate);
			installmentResultList.add(installMentResult);
		}
		return installmentResultList;
	}
	
	
	/**
	 * 按日利率 等本等息计算工具方法
	 * @param calPutoutDayInterestDay 放款日是否起息
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param dayInterestRate  日利率
	 * @param loanDate 贷款时间
	 * @return
	 * @throws ParseException 
	 */
	public static List<InstallmentResult> equalityPrincipalEqualityInterestOfDayInterestRate(int calPutoutDayInterestDay,int termRate,double loanAmt,double dayInterestRate,String loanDate) throws ParseException {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		dayInterestRate = Arith.div(dayInterestRate, 100);
		//剩余应还本金
		Double balance = loanAmt;
		
		//计算每期应还本金
		double principalAmt = Arith.div(loanAmt, termRate,Arith.TWO_SCALE);
		String payDate = null;
		//计算每期利息,剩余本金
		InstallmentResult installMentResult = null;
		for(int i = 0 ;i < termRate;i++) {
			installMentResult = new InstallmentResult();
			payDate = DateHelper.addMonth(loanDate,1+i);
			String startDate = DateHelper.subMonth(payDate);
			int days = DateHelper.getDays(startDate, payDate);
			if(i == 0) {
				days += calPutoutDayInterestDay;
			}
			double v1 = Arith.mul(loanAmt, days); 
			double interestAmt = Arith.mul(v1,dayInterestRate,Arith.TWO_SCALE);
			double sumPrincipalAndInterestAmt = Arith.add(principalAmt, interestAmt);
			double balance1 = Arith.sub(loanAmt, Arith.mul(i+1, principalAmt));
			balance = balance1 < 0 ? 0.00d : Arith.round(balance1, Arith.TWO_SCALE);
			if( i + 1 == termRate) {//补全最后一期金额
				principalAmt = Arith.round(Arith.add(principalAmt, balance) , Arith.TWO_SCALE);
				balance =0.0;
			}
			installMentResult.setPrincipalAmt(principalAmt);
			installMentResult.setInterestAmt(interestAmt);
			installMentResult.setPrincipalAndInterestAmt(Arith.round(sumPrincipalAndInterestAmt, Arith.TWO_SCALE));
			installMentResult.setBalance(Arith.round(balance, Arith.TWO_SCALE));
			installmentResultList.add(installMentResult);
			installMentResult.setPeriod(i+1);
			installMentResult.setPayDate(payDate);
		}
		return installmentResultList;
	}

	/**
	 * 单期核算类工具
	 * @param calPutoutDayInterestDay 放款日是否当天起息:0-否,1-是
	 * @param loanAmt 借款金额
	 * @param dayInterestRate 日利率
	 * @param loanDate 借款日期
	 * @param loanDays 借款天数
	 * @return
	 * @throws ParseException
	 */
	public static List<InstallmentResult> onePeriod(int calPutoutDayInterestDay,double loanAmt,double dayInterestRate,String loanDate,int loanDays) throws ParseException {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		InstallmentResult installmentResult = null;
		double balance = 0;
		double principalAmt = loanAmt;
		double v1 = Arith.div(Arith.mul(loanDays,dayInterestRate,Arith.FOUR_SCALE),100);
		double interestAmt = Arith.mul(loanAmt, v1, Arith.TWO_SCALE);
		int period = 1;
		double principalAndInterestAmt = Arith.round(Arith.add(principalAmt, interestAmt),Arith.TWO_SCALE);
		String payDate = DateHelper.addDays(loanDate,loanDays - calPutoutDayInterestDay);
		installmentResult = new InstallmentResult(period, principalAmt, interestAmt, principalAndInterestAmt, balance, payDate);
		installmentResultList.add(installmentResult);
		return installmentResultList;
	}
	
	/**
	 * 按日利率 等额本金计算工具方法
	 * @param calPutoutDayInterestDay 放款日是否当天起息
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param dayInterestRate  日利率
	 * @param loanDate 贷款时间
	 * @return
	 * @throws ParseException 
	 */
	public static List<InstallmentResult> equalityCorpusOfDayInterestRate(int calPutoutDayInterestDay,int termRate,double loanAmt,double dayInterestRate,String loanDate) throws ParseException {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		//剩余应还本金
		Double balance = loanAmt;
		//已还本金
		Double payedBalance = 0d;
		
		//计算每期应还本金
		installmentResultList = caculatePeriodPrincipal(termRate,loanAmt,loanDate);
		
		//计算每期利息,剩余本金
		for(InstallmentResult installMentResult : installmentResultList) {
			Double principalAmt = installMentResult.getPrincipalAmt();
			String startDate = DateHelper.subMonth(installMentResult.getPayDate());
			int days = DateHelper.getDays(startDate, installMentResult.getPayDate());
			if(installMentResult.getPeriod() == 1) {
				//如果为第一期,则需要加上放款日当天利息
				days += calPutoutDayInterestDay;
			}
			double v1 = Arith.mul(days, Arith.div(dayInterestRate, 100), Arith.FOUR_SCALE);
			Double interestAmt = Arith.mul(balance,v1,Arith.TWO_SCALE);
			Double sumPrincipalAndInterestAmt = Arith.add(principalAmt, interestAmt);
			payedBalance = Arith.add(payedBalance, principalAmt);
			balance = Arith.sub(loanAmt,payedBalance);
			installMentResult.setInterestAmt(interestAmt);
			installMentResult.setPrincipalAndInterestAmt(sumPrincipalAndInterestAmt);
			installMentResult.setBalance(balance);
		}
		return installmentResultList;
	}
	
	/**
	 * 按月利率计算等额本金计算工具方法
	 * @param calPutoutDayInterestDay 放款日是否起息
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param dayInterestRate  日利率
	 * @param loanDate 贷款时间
	 * @return
	 */
	public static List<InstallmentResult> equalityCorpusOfMonthInterestRate(int calPutoutDayInterestDay,int termRate,double loanAmt,double dayInterestRate,String loanDate) {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		double monthInterestRate = Arith.div(dayInterestRate*365/100, 12, Arith.FOUR_SCALE);//月利率
		//剩余应还本金
		Double balance = loanAmt;
		//已还本金
		Double payedBalance = 0d;
		
		//计算每期应还本金
		installmentResultList = caculatePeriodPrincipal(termRate,loanAmt,loanDate);
		
		//计算每期利息,剩余本金
		for(InstallmentResult installMentResult : installmentResultList) {
			Double principalAmt = installMentResult.getPrincipalAmt();
			Double interestAmt = Arith.mul(balance,monthInterestRate,Arith.TWO_SCALE);
			if(installMentResult.getPeriod() == 1) {
				double v1 = Arith.mul(loanAmt, dayInterestRate,Arith.FOUR_SCALE);
				v1 = Arith.div(v1, 100);
				interestAmt = Arith.add(interestAmt, v1*calPutoutDayInterestDay, Arith.TWO_SCALE);
			}
			Double sumPrincipalAndInterestAmt = Arith.add(principalAmt, interestAmt);
			payedBalance = Arith.add(payedBalance, principalAmt);
			balance = Arith.sub(loanAmt,payedBalance);
			installMentResult.setInterestAmt(interestAmt);
			installMentResult.setPrincipalAndInterestAmt(sumPrincipalAndInterestAmt);
			installMentResult.setBalance(balance);
		}
		return installmentResultList;
	}
	
	/**
	 * 等额本金计算工具方法
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param monthInterestRate  月利率
	 * @return
	 */
	public static List<InstallmentResult> equalityCorpus(int termRate,double loanAmt,double monthInterestRate) {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		//剩余应还本金
		Double balance = loanAmt;
		//已还本金
		Double payedBalance = 0d;
		
		//计算每期应还本金
		installmentResultList = caculatePeriodPrincipal(termRate,loanAmt,null);
		
		//计算每期利息,剩余本金
		for(InstallmentResult installMentResult : installmentResultList) {
			Double principalAmt = installMentResult.getPrincipalAmt();
			Double interestAmt = Arith.mul(balance,monthInterestRate);
			Double sumPrincipalAndInterestAmt = Arith.add(principalAmt, interestAmt);
			payedBalance = Arith.add(payedBalance, principalAmt);
			balance = Arith.sub(loanAmt,payedBalance);
			installMentResult.setInterestAmt(interestAmt);
			installMentResult.setPrincipalAndInterestAmt(sumPrincipalAndInterestAmt);
			installMentResult.setBalance(balance);
		}
		return installmentResultList;
	}
	
	
	/**
	 * 等额本息计算工具方法
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param payDayRate  日利率
     * @param loanDate 放款日期
	 * @return
	 */
	public static List<InstallmentResult> equalityCorpusAndInterest(int calPutoutDayInterestDay,int termRate,double loanAmt,double payDayRate,String loanDate) {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		double monthInterestRate = Arith.div(payDayRate*365/100, 12, Arith.FOUR_SCALE);//月利率
		//剩余应还本金
		double balance = loanAmt;
		//已还本金
		double payedBalance = 0d;
		//每期应还本息
		double perMonthPayPrinAndIntest = caculatePeriodPrincipalAndIntest(termRate,loanAmt,monthInterestRate);
		//分期数
		int period = 0;
		//放款日起息分摊到每期的利息
		double v1 = Arith.mul(loanAmt, payDayRate,Arith.FOUR_SCALE);
		v1 = Arith.div(v1, 100);
		v1 = Arith.mul(v1, calPutoutDayInterestDay,Arith.FOUR_SCALE);
		v1 = Arith.div(v1, termRate);
		double putoutDayInterestAmt = Arith.round(v1,Arith.TWO_SCALE);
		//计算每期利息,剩余本金,应还本金
		for(int i = 1; i < termRate + 1; i++) {
			//根据当前剩余应还本金计算对应每期利息
			double interestAmt =  Arith.mul(balance,monthInterestRate,Arith.TWO_SCALE);
			//计算每期本金
			double principalAmt = Arith.sub(perMonthPayPrinAndIntest, interestAmt);
			//计算剩余本金
			
			if(i == termRate && Arith.sub(balance,principalAmt) != 0d ) {
				//对于最后一期,如果余额减去本金不等于0,则需要进行补齐,保证每期本金之和等于放款金额,每期本金+利息等于本息
				double sub = Arith.sub(balance,principalAmt);
				principalAmt = Arith.add(principalAmt, sub);
				interestAmt = Arith.sub(perMonthPayPrinAndIntest, principalAmt);
			}
			balance = Arith.sub(balance,principalAmt) < 0.01d ? 0d : Arith.sub(balance,principalAmt);
			//计算每期应还日
			String payDate = DateUtil.getDateAddMonth(loanDate, i);
			//计算已还本金
			payedBalance = Arith.add(payedBalance, principalAmt);
			period = i;
			interestAmt = Arith.add(interestAmt,putoutDayInterestAmt);
			InstallmentResult installmentResult = new InstallmentResult(period,Arith.round(principalAmt,Arith.TWO_SCALE),Arith.round(interestAmt,Arith.TWO_SCALE)
					,Arith.add(perMonthPayPrinAndIntest,putoutDayInterestAmt),Arith.round(balance,Arith.TWO_SCALE),payDate);
			installmentResultList.add(installmentResult);
		}
		return installmentResultList;
	}

	
	/**
	 * 等额本息计算每期应还本息
	 * 计算公式为:每月等额还本付息额=借款金额*月利率*(1+月利率)^贷款期数/((1+月利率)^-1)
	 * @param termRate 分期数
	 * @param loanAmt 借款金额
	 * @param monthInterestRate 月利率
	 * @return
	 */
	private static double caculatePeriodPrincipalAndIntest(
			int termRate, double loanAmt, double monthInterestRate) {
		double perMonthPayPrinAndIntest = 0d;// 每月等额还本付息额
		double prinMulMonIntest = Arith.mul(monthInterestRate, loanAmt, Arith.FOUR_SCALE);//本金*月利率
		double compoundIntestRate = 1d;//(1+月利率)^还款月数
		for(int i = 0;i < termRate; i++) {
			double v1 = Arith.add(1, monthInterestRate);
			compoundIntestRate = Arith.mul(v1,compoundIntestRate,Arith.FOUR_SCALE);
		}
		double netIntestRate = Arith.sub(compoundIntestRate, 1);//(1+月利率)^还款月数-1 
		double compdIntestPrin = Arith.mul(prinMulMonIntest, compoundIntestRate, Arith.FOUR_SCALE);
		perMonthPayPrinAndIntest = Arith.div(compdIntestPrin, netIntestRate, Arith.TWO_SCALE);
		return perMonthPayPrinAndIntest;
	}
	
	

	/**
	 * 等额本金计算每期应还本金,还款日期
	 * @param termRate 分期数
	 * @param loanAmt  借款金额
	 * @param loanDate 还款日期
	 * @return
	 */
	private static List<InstallmentResult> caculatePeriodPrincipal(
			int termRate, double loanAmt, String loanDate) {
		List<InstallmentResult> installmentResultList = new ArrayList<InstallmentResult>();
		Double principalAmt = Arith.div(loanAmt, termRate,Arith.TWO_SCALE);
		Double newLoanAmt = Arith.mul(termRate,principalAmt);
		//计算新本金和实际本金的差值
		double diffAmt = Arith.sub(loanAmt, newLoanAmt);
		InstallmentResult installmentResult = null;
		
		for(int i = 1; i < termRate + 1; i++) {
			if(i == termRate) {
				principalAmt = Arith.add(principalAmt, diffAmt);
			}
			String payDate = null;
			if(!StringUtils.isEmpty(loanDate)) {
				payDate = DateUtil.getDateAddMonth(loanDate, i);
			}
			installmentResult = new InstallmentResult(i,principalAmt,payDate);
			installmentResultList.add(installmentResult);
		}
		return installmentResultList;
	}
	

	public static void main(String[] args) throws ParseException {
//		System.out.println(365*0.05/100);
//		double monthInterestRate = Arith.div(0.04785, 12);
//		List<InstallmentResult> installmentResultList = equalityCorpus(12,1d,monthInterestRate);
//		for(InstallmentResult installmentResult :installmentResultList) {
//			System.out.println(installmentResult.toString());
//		}
//		System.out.println(caculatePeriodPrincipal(360,120000,0.18/12));
		List<InstallmentResult> installmentResultList = null;
		//T放款日起息
//		installmentResultList = equalityCorpusOfDayInterestRate(1,3, 10, 0.05, "2019/01/01");//按日利率计算等额本金
//		installmentResultList = equalityCorpusOfMonthInterestRate(1,3, 10, 0.05, "2019/01/01");//按月利率计算等额本金
//		installmentResultList = equalityCorpusOfDayInterestRate(1,3, 9, 0.05, "2019/01/01");//按日利率计算等额本金
//		installmentResultList = equalityCorpusOfMonthInterestRate(1,3, 9, 0.05, "2019/01/01");//按月利率计算等额本金
//		installmentResultList = onePeriod(1,15, 0.05, "2019/11/07", 14);//单期计算
//		installmentResultList = equalityPrincipalEqualityInterestOfDayInterestRate(1,3, 9, 0.05, "2019/01/01");//等本等息按日利率
//		installmentResultList = equalityPrincipalEqualityInterestOfMonthInterestRate(1,3, 900, 0.05, "2019/01/01");//等本等息按月利率
		installmentResultList = equalityCorpusAndInterest(1,3,900,0.05,"2019/01/01");//等额本息
		for(InstallmentResult installmentResult : installmentResultList) {
			System.out.println("分期数:" + installmentResult.getPeriod() + ",本金:" + installmentResult.getPrincipalAmt() 
					+ ",利息:" + installmentResult.getInterestAmt() + ",本息:" + installmentResult.getPrincipalAndInterestAmt()
					+ ",剩余本金:" + installmentResult.getBalance() + ",应还日: " +  installmentResult.getPayDate());
		}
		//T+1放款日起息
//		installmentResultList = onePeriod(0,100, 0.06, "2019/11/07", 7);
//		installmentResultList = equalityCorpusOfDayInterestRate(0,3, 10, 0.05, "2019/01/01");//按日利率计算等额本金
//		installmentResultList = equalityCorpusOfMonthInterestRate(0,3, 10, 0.05, "2019/01/01");//按月利率计算等额本金
//		installmentResultList = equalityCorpusOfMonthInterestRate(0,3, 9, 0.05, "2019/01/01");//按月利率计算等额本金
//		installmentResultList = equalityPrincipalEqualityInterestOfDayInterestRate(6, 100, 0.05, "2019/11/07");
//		installmentResultList = equalityPrincipalEqualityInterestOfMonthInterestRate(6, 100, 0.5, "2019/11/07");
//		installmentResultList = equalityCorpusOfDayInterestRate(0,3,100,0.06,"2019/01/07");
//		installmentResultList = equalityCorpusOfMonthInterestRate(0,3,2,0.06,"2019/11/07");
//		installmentResultList = onePeriod(0,15, 0.05, "2019/11/07", 14);//单期计算
//		installmentResultList = equalityPrincipalEqualityInterestOfDayInterestRate(0,3, 9, 0.05, "2019/01/01");
//		installmentResultList = equalityPrincipalEqualityInterestOfMonthInterestRate(0,3, 900, 0.05, "2019/01/01");
		installmentResultList = equalityCorpusAndInterest(0,3,900,0.05,"2019/01/01");//等额本息
		for(InstallmentResult installmentResult : installmentResultList) {
			System.out.println("分期数:" + installmentResult.getPeriod() + ",本金:" + installmentResult.getPrincipalAmt() 
					+ ",利息:" + installmentResult.getInterestAmt() + ",本息:" + installmentResult.getPrincipalAndInterestAmt()
					+ ",剩余本金:" + installmentResult.getBalance() + ",应还日: " +  installmentResult.getPayDate());
		}
	}
	@Test
	public void testCaculatePeriodPrincipal() {
		List<InstallmentResult> list = caculatePeriodPrincipal(12,1,"2018/01/31");
		for(InstallmentResult installmentResult : list) {
			System.out.println(installmentResult.toString());
		}
	}
	
}

金额计算工具类:


/**
 * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 确的浮点数运算,包括加减乘除和四舍五入。
 */
public class Arith {
	// 默认除法运算精度
	private static final int DEF_DIV_SCALE = 10; // 这个类不能实例化
	private static int ROUND_HALF_EVEN = BigDecimal.ROUND_HALF_EVEN;// 银行家舍入法
	//利息保留位数
	public final static int INTEREST_SCALE = 4;
	//保留两位小数
	public final static int TWO_SCALE = 2;
	
	//保留四位小数
	public final static int FOUR_SCALE = 4;
	
	
	private Arith() {
	}

	/**
	 * 提供精确的加法运算。
	 * 
	 * @param v1
	 *            被加数
	 * @param v2
	 *            加数
	 * @return 两个参数的和
	 */
	public static double add(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.add(b2).doubleValue();
	}

	/**
	 * 提供精确的减法运算。
	 * 
	 * @param v1
	 *            被减数
	 * @param v2
	 *            减数
	 * @return 两个参数的差
	 */
	public static double sub(double v1, double v2, int scale) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.subtract(b2).setScale(scale,BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	
	/**
	 * 提供精确的减法运算。
	 * 
	 * @param v1
	 *            被减数
	 * @param v2
	 *            减数
	 * @return 两个参数的差
	 */
	public static double sub(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.subtract(b2).doubleValue();
	}

	/**
	 * 提供精确的乘法运算。
	 * 
	 * @param v1
	 *            被乘数
	 * @param v2
	 *            乘数
	 * @return 两个参数的积,默认保留小数点后两位
	 */
	public static double mul(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.multiply(b2).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	/**
	 * 提供精确的乘法运算。
	 * 
	 * @param v1
	 *            被乘数
	 * @param v2
	 *            乘数
	 * @return 两个参数的积
	 */
	public static double mul(double v1, double v2, int scale) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.multiply(b2).setScale(scale,BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
	 * 
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @return 两个参数的商
	 */
	public static double div(double v1, double v2) {
		return div(v1, v2, DEF_DIV_SCALE);
	}

	/**
	 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
	 * 
	 * @param v1
	 *            被除数
	 * @param v2
	 *            除数
	 * @param scale
	 *            表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static double div(double v1, double v2, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 银行家舍入法
	 *
	 * 1. 被修约的数字小于5时,该数字舍去; 2. 被修约的数字大于5时,则进位; 3.
	 * 被修约的数字等于5时,要看5前面的数字,若是奇数则进位,若是偶数则将5舍掉,即修约后末尾数字都成为偶数;
	 * 若5的后面还有不为“0”的任何数,则此时无论5的前面是奇数还是偶数,均应进位。 举例,用上述规则对下列数据保留小数点后两位数据: 9.8249=9.82,
	 * 9.82671=9.83 9.8350=9.84, 9.8351 =9.84 9.8250=9.82, 9.82501=9.83
	 * 
	 * @param v
	 *            需要四舍五入的数字
	 * @param scale
	 *            小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round1(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_EVEN).doubleValue();
	}
	
	/**
	 * @param v
	 *            需要四舍五入的数字
	 * @param scale
	 *            小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 提供精确的加法运算。
	 * 
	 * @param v1
	 *            被加数
	 * @param v2
	 *            加数
	 * @param scale 
	 *           小数点后保留几位
	 * @return 两个参数的和
	 */
	public static Double add(double v1, double v2, int scale) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return round(b1.add(b2).doubleValue(),scale);
	}
	
	/**
	 * 提供精确的加法运算。
	 * @param values 
	 *             可变加数
	 * @param scale 
	 *           小数点后保留几位
	 * @return 两个参数的和
	 */
	public static Double add(double ...values) {
		BigDecimal b1 = new BigDecimal("0");
		for(double value:values) {
			BigDecimal b2 = new BigDecimal(Double.toString(value));
			b1 = b1.add(b2);
		}
		return b1.doubleValue();
	}
	
	
	
	/**
	 * 金额格式化为小数点后两位,使用银行家舍入法
	 * @param value
	 * @return
	 */
	public static String format(double value) {
		DecimalFormat decimalFormat = new DecimalFormat("######0.00");
		String amount = decimalFormat.format(getBigDecimalForStrReturnDouble(value,2));
		return amount;
	}
	/**
	 * 将数字字符串转化为double,并保留指定小数位
	 *
	 * @param str
	 *            数字字符串
	 * @param scale
	 *            指定要保留的小数位(可为空)
	 *
	 * @return double
	 */
	public static double getBigDecimalForStrReturnDouble(double value,
			Integer scale) {
		BigDecimal one = new BigDecimal(Double.toString(value));
		if (null != scale) {
			return one.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
		}
		return one.doubleValue();
	}
	
	public static void main(String[] args) {
		System.out.println(0.7/100);
		System.out.println(mul(15,0.7/100,20));
		System.out.println(add(4,0.1,0.2,1,0.55));
		System.out.println(0.35/100);
		System.out.println(mul(0.35/100,10,3));
		System.out.println(Arith.div(0.35, 100));
		System.out.println(mul(Arith.div(0.35, 100),10,2));
		System.out.println(format(0.135));
		System.out.println(format(1.125));
		System.out.println("11.125:" + format(11.125));
		System.out.println("11.1251:" + format(11.1251));
		System.out.println("11.135:" + format(11.135));
		System.out.println("1111.15:" + format(1111.15));
		System.out.println("11.100:" + format(11.100));
		System.out.println();
		System.out.println(round(0.00,2));
		System.out.println(round(1.00,2));
		System.out.println(round(11.125,2));
		System.out.println(round(11.1251,2));
		System.out.println(round(11.135,2));
		System.out.println(round(15+0.075+0.1,2));
		System.out.println(round(11.100,2));
		System.out.println(15+0.075+0.1);
		
	}
			
}

日期类:

/**
 * 核算日期处理
 * 
 * @author XiaoBin Shang
 *
 */
@Service
public class DateHelper {
	

	private static ClSystemSetupService systemSetupService;
	@Autowired
	public void setSystemSetupService(ClSystemSetupService systemSetupService) {
		DateHelper.systemSetupService = systemSetupService;
	}

	// 日期格式
	public static final String AMR_NOMAL_TIME_FORMAT = "HH:mm:ss";
	public static final String AMR_NOMAL_DATE_FORMAT = "yyyy/MM/dd";
	public static final String AMR_NOMAL_DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss";
	public static final String AMR_NOMAL_FULLDATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS";
	public static final String AMR_NOMAL_FULLTIME_FORMAT = "HH:mm:ss.SSS";

	public static final String TERM_UNIT_DAY = "D";// 期限天
	public static final String TERM_UNIT_MONTH = "M";// 期限月
	public static final String TERM_UNIT_YEAR = "Y";// 期限年

	private static String businessDate;

	/**
	 * 获取当前营业日期
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String getBusinessDate() throws Exception {
		// if(businessDate==null||"".equals(businessDate) ||
		// businessDate.length() != 10)
		// {
		businessDate = systemSetupService.getBusinessDate();
		if (StringUtils.isEmpty(businessDate))
			throw new Exception("系统日期未定义,请联系系统管理员设置!");
		return businessDate;
	}

	public static String getBusinessTime() throws Exception {
		return getBusinessDate() + " "
				+ DateUtils.formatDate(new Date(), AMR_NOMAL_TIME_FORMAT);
	}

	/**
	 * 直接设置系统营业日期
	 * 
	 * @param BusinessDate
	 * @throws Exception
	 */
	public static void setBusinessDate(String BusinessDate) throws Exception {
		DateHelper.businessDate = BusinessDate;
	}

	public static String getRelativeDate(String date, String termUnit, int term)
			throws Exception {
		return DateHelper.getRelativeDate(date, date, termUnit, term);
	}

	public static String getRelativeDate(String baseDate, boolean endOfMonth,
			String date, String termUnit, int term) throws Exception {
		if (term == 0) {
			return date;
		}

		if (!TERM_UNIT_DAY.equals(termUnit)
				&& !TERM_UNIT_MONTH.equals(termUnit)
				&& !TERM_UNIT_YEAR.equals(termUnit)) {
			throw new Exception("期数单位无法识别:" + termUnit);
		}

		Calendar cal = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);
		cal.setTime(formatter.parse(date));
		if (termUnit.equals(DateHelper.TERM_UNIT_DAY)) {
			cal.add(Calendar.DATE, term);
		} else if (termUnit.equals(DateHelper.TERM_UNIT_MONTH)) {
			cal.add(Calendar.MONTH, term);
			/********
			 * 修正超过28号时的情况
			 */
			int baseday = Integer.parseInt(baseDate.substring(8, 10));
			if (cal.get(Calendar.DATE) > 28 && baseday > 28) {
				if (!DateHelper.monthEnd(formatter.format(cal.getTime()))) {// 如果不是月末,则使用baseDate的日期
					cal.set(Calendar.DATE, baseday);
				}
			}
			if (DateHelper.monthEnd(baseDate) && endOfMonth) {
				String s = formatter.format(cal.getTime());
				return DateHelper.getEndDateOfMonth(s);
			}

		} else if (termUnit.equals(DateHelper.TERM_UNIT_YEAR)) {
			cal.add(Calendar.YEAR, term);
		}

		return formatter.format(cal.getTime());
	}

	public static String getRelativeDate(String baseDate, String date,
			String termUnit, int step) throws Exception {
		return DateHelper
				.getRelativeDate(baseDate, false, date, termUnit, step);
	}

	
	
	/**
	 * 获得和给定日期BeginDate和EndDate相差的期数(取整,直接抛掉小数位)
	 */
	public static double getTermPeriod(String BeginDate, String EndDate,
			String termUnit, int step) throws Exception {
		if (step <= 0) {
			throw new Exception("step必须大于0,step:" + step);
		}
		if (!TERM_UNIT_DAY.equals(termUnit)
				&& !TERM_UNIT_MONTH.equals(termUnit)
				&& !TERM_UNIT_YEAR.equals(termUnit)) {
			throw new Exception("期数单位无法识别:" + termUnit);
		}
		double result = 0d;
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);
		cal.setTime(formatter.parse(BeginDate));
		if (termUnit.equals(DateHelper.TERM_UNIT_DAY)) {
			result = getDays(BeginDate, EndDate) / (step * 1.0);
		} else if (termUnit.equals(DateHelper.TERM_UNIT_MONTH)) {
			result = getMonths(BeginDate, EndDate) / (step * 1.0);
		} else {
			result = getYears(BeginDate, EndDate) / (step * 1.0);
		}

		return Arith.round(result, 5);
	}

	public static boolean monthEnd(String date) throws ParseException {
		return date.equals(getEndDateOfMonth(date));
	}

	/**
	 * 得到月底
	 */
	public static String getEndDateOfMonth(String curDate)
			throws ParseException {
		if (curDate == null || curDate.length() != 10) {
			return null;
		}
		curDate = curDate.substring(0, 8) + "01";
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);
		cal.setTime(formatter.parse(curDate));
		int maxDays = cal.getActualMaximum(Calendar.DATE);// 得到该月的最大天数
		cal.set(Calendar.DATE, maxDays);
		return formatter.format(cal.getTime());
	}

	public static Date getDate(String curDate) throws ParseException {
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);
		cal.setTime(formatter.parse(curDate));
		return cal.getTime();
	}

	/**
	 * @param date
	 *            yyyy/MM/dd
	 * @param type
	 *            1 返回数字 2 返回中文 3 返回英文 返回星期 1 星期一 、2 星期二 、3星期三、4 星期四、5 星期五、6
	 *            星期六、7 星期日
	 */
	public static String getWeekDay(String date, String format)
			throws ParseException {
		String[] sWeekDates = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		String[] sWeekDatesE = { "Sunday", "Monday", "Tuesday", "Wednesday",
				"Thursday", "Friday", "Saturday" };
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
		cal.setTime(formatter.parse(date));
		if (format.equals("2")) {
			return sWeekDates[cal.get(Calendar.DAY_OF_WEEK) - 1];
		} else if (format.equals("3")) {
			return sWeekDatesE[cal.get(Calendar.DAY_OF_WEEK) - 1];
		} else {
			return String.valueOf(cal.get(Calendar.DAY_OF_WEEK) - 1);
		}
	}

	/**
	 * @param beginDate
	 * @param endDate
	 * @return 
	 * 相差天数<0:sBeginDate>sEndDate
	 * 相差天数=0:sBeginDate=sEndDate
	 * 相差天数>0:sBeginDate<sEndDate
	 * @throws ParseException
	 *             获取两个日期之间的天数
	 */
	public static int getDays(String sBeginDate, String sEndDate) {
		Date startDate = java.sql.Date.valueOf(sBeginDate.replace('/', '-'));
		Date endDate = java.sql.Date.valueOf(sEndDate.replace('/', '-'));

		int iDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000L);
		return iDays;
	}

	/**
	 * 获取两个日期之间的月数,采用小数表示。 用户可根据使用场景确定是向上、向下取整,取整时请注意正负数
	 * 
	 * @param beginDate
	 * @param endDate
	 * @return
	 * @throws ParseException
	 * @author xjzhao@amarsoft.com
	 */
	public static double getMonths(String beginDate1, String endDate1)
			throws ParseException {
		Date beginDate = getDate(beginDate1);
		Date endDate = getDate(endDate1);
		Calendar former = Calendar.getInstance();
		Calendar latter = Calendar.getInstance();
		former.setTime(beginDate);
		latter.setTime(endDate);

		int monthCounter = (latter.get(Calendar.YEAR) - former
				.get(Calendar.YEAR))
				* 12
				+ latter.get(Calendar.MONTH)
				- former.get(Calendar.MONTH);

		former.add(Calendar.MONTH, monthCounter);

		int dayCounter = latter.get(Calendar.DAY_OF_MONTH)
				- former.get(Calendar.DAY_OF_MONTH);
		int maxDays = latter.getActualMaximum(Calendar.DATE);

		return monthCounter * 1.0 + dayCounter * 1.0 / maxDays * 1.0;
	}
	
	/**
	 * 获取两个日期之间的月数,采用整数表示
	 * 
	 * @param beginDate
	 * @param endDate
	 * @return
	 * @throws ParseException
	 * @author xjzhao@amarsoft.com
	 */
	public static int getMonthsForInt(String beginDate1, String endDate1)
			throws ParseException {
		double months = getMonths(beginDate1, endDate1);
		if(months%1 > 0.000001d) {
			return (int)months/1+1;
		}
		return (int)months/1;
	}

	/**
	 * 获取两个日期之间的年数 add by xjzhao 2011/04/06
	 * 
	 * @param beginDate
	 * @param endDate
	 * @return
	 * @throws ParseException
	 * @throws ParseException
	 * 
	 */
	public static int getYears(String beginDate1, String endDate1)
			throws ParseException {
		Date beginDate = getDate(beginDate1);
		Date endDate = getDate(endDate1);
		Calendar former = Calendar.getInstance();
		Calendar latter = Calendar.getInstance();
		former.clear();
		latter.clear();
		boolean positive = true;
		if (beginDate.after(endDate)) {
			former.setTime(endDate);
			latter.setTime(beginDate);
			positive = false;
		} else {
			former.setTime(beginDate);
			latter.setTime(endDate);
		}

		int yearCounter = 0;
		while (former.get(Calendar.YEAR) != latter.get(Calendar.YEAR)) {
			former.add(Calendar.YEAR, 1);
			yearCounter++;
		}

		if (positive)
			return yearCounter;
		else
			return -yearCounter;
	}

	/**
	 * 判断是否为闰年
	 * 
	 * @param year
	 *            (int)
	 * @return
	 */
	public static boolean isLeapYear(int year) {
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 判断是否为闰年
	 * 
	 * @param date
	 *            (String)yyyy/mm/dd
	 * @return
	 */
	public static boolean isLeapYear(String date) throws Exception {
		return isLeapYear(Integer.parseInt(date.split("/")[0]));
	}

	/**
	 * 获取下一营业日
	 * @return
	 * @throws Exception 
	 */
	public static String getNextBusinessDate(String businessDate) throws Exception {
		Date busiDate = null;
		try {
			busiDate = DateUtils.parseDate(businessDate, AMR_NOMAL_DATE_FORMAT);
		} catch (Exception e) {
			e.printStackTrace();
			return getNextBusinessDate(getBusinessDate());
		}
		busiDate = DateUtils.addDays(busiDate, 1);
		
		return DateUtils.formatDate(busiDate, AMR_NOMAL_DATE_FORMAT);
	}

	/**
	 * 获取下一批量日期
	 * @return
	 * @throws Exception 
	 */
	public static String getNextBatchDate(String batchDate) throws Exception {
		Date batDate = null;
		try {
			batDate = DateUtils.parseDate(batchDate, AMR_NOMAL_DATE_FORMAT);
		} catch (Exception e) {
			e.printStackTrace();
			return getNextBatchDate(getBusinessDate());
		}
		batDate = DateUtils.addDays(batDate, 1);
		
		return DateUtils.formatDate(batDate, AMR_NOMAL_DATE_FORMAT);
	}

	/**
	 * 比较两个日期的大小<br>
	 * 0 - date1 等于 date2<br>
	 * 1 - date1 大于 date2<br>
	 * -1 - date1 小于 date2
	 * <br>
	 * @param date1
	 * @param date2
	 * @throws ParseException 
	 */
	public static int compareDate(String date1Str, String date2Str) throws ParseException {
		Date date1 = DateUtils.parseDate(date1Str, AMR_NOMAL_DATE_FORMAT);
		Date date2 = DateUtils.parseDate(date2Str, AMR_NOMAL_DATE_FORMAT);
		return date1.compareTo(date2);
	}
	
	/**** 
     * 传入具体日期 ,返回具体日期增加一个月。
     * 默认格式:yyyy/mm/dd 
     * @param date 日期(2017-04-13) 
     * @return 2017-05-13
     * @throws ParseException 
     */  
	public static String addMonth(String date) throws ParseException {  
        SimpleDateFormat sdf = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);  
        Date dt = sdf.parse(date);  
        Calendar rightNow = Calendar.getInstance();  
        rightNow.setTime(dt);  
        rightNow.add(Calendar.MONTH, 1);  
        Date dt1 = rightNow.getTime();  
        String reStr = sdf.format(dt1);  
        return reStr;  
    }
	
	/**** 
     * 传入具体日期 ,返回具体日期增加指定月数。
     * 默认格式:yyyy/mm/dd 
     * @param date 日期(2017-04-13) 
     * @return 2017-05-13
     * @throws ParseException 
     */  
	public static String addMonth(String date,int count) throws ParseException {  
        SimpleDateFormat sdf = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);  
        Date dt = sdf.parse(date);  
        Calendar rightNow = Calendar.getInstance();  
        rightNow.setTime(dt);  
        rightNow.add(Calendar.MONTH, count);  
        Date dt1 = rightNow.getTime();  
        String reStr = sdf.format(dt1);  
        return reStr;  
    }
    
    /**** 
     * 传入具体日期 ,返回具体日期减一个月。
     * 默认格式:yyyy/mm/dd 
     * @param date 日期(2017-04-13) 
     * @return 2017-05-13
     * @throws ParseException 
     */  
    public static String subMonth(String date) throws ParseException {  
        SimpleDateFormat sdf = new SimpleDateFormat(AMR_NOMAL_DATE_FORMAT);  
        Date dt = sdf.parse(date);  
        Calendar rightNow = Calendar.getInstance();  
        rightNow.setTime(dt);  
        rightNow.add(Calendar.MONTH, -1);  
        Date dt1 = rightNow.getTime();  
        String reStr = sdf.format(dt1);  
        return reStr;  
    }


	public static void main(String[] args) throws ParseException {
		String month = subMonth("2018/03/31");
		System.out.println(month);
		int days = getDays("2018/05/31", "2018/04/03");
		System.out.println(days);
		days = getDays("2018/03/31", "2018/04/03");
		System.out.println(days);
		System.out.println(getMonthsForInt("2018/03/31", "2018/05/15"));
		System.out.println(getMonths("2018/03/31", "2018/05/15"));
		System.out.println(addDays("2018/03/31", 3));
		System.out.println(getDays("2018/11/22", "2018/12/22"));
	}

	public static Date getDate() throws Exception {
		String date = getBusinessDate() + " " + getBusinessTime();
		return DateUtils.parseDate(date,AMR_NOMAL_FULLDATETIME_FORMAT);
	}

	/**
	 * 获取批量日期
	 * @return
	 */
	public static String getBatchDate() {
		// TODO Auto-generated method stub
		return null;
	}

	 /**
     * 增加指定天数
     * @param date
     * @param days
     * @return
	 * @throws ParseException 
     */
    public static String addDays(String dateStr,int days) throws ParseException {
    	Date date = DateUtils.parseDate(dateStr, AMR_NOMAL_DATE_FORMAT);
    	date = DateUtils.addDays(date, days);
    	return DateUtils.formatDate(date, AMR_NOMAL_DATE_FORMAT);
    }

}

 

发布了17 篇原创文章 · 获赞 7 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览