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



/**
* 信贷分期核算计息工具类
* @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);
}
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);
}
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();
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 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));
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;
String payDate = DateHelper.addDays(loanDate,loanDays - calPutoutDayInterestDay);
installmentResult = new InstallmentResult(period, principalAmt, interestAmt, principalAndInterestAmt, balance, payDate);
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);
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);
}
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);
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);
interestAmt = Arith.sub(perMonthPayPrinAndIntest, principalAmt);
}
balance = Arith.sub(balance,principalAmt) < 0.01d ? 0d : Arith.sub(balance,principalAmt);
//计算每期应还日
//计算已还本金
period = i;
InstallmentResult installmentResult = new InstallmentResult(period,Arith.round(principalAmt,Arith.TWO_SCALE),Arith.round(interestAmt,Arith.TWO_SCALE)
}
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++) {
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) {
}
String payDate = null;
if(!StringUtils.isEmpty(loanDate)) {
}
installmentResult = new InstallmentResult(i,principalAmt,payDate);
}
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));
}

/**
* 提供精确的减法运算。
*
* @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));
}

/**
* 提供精确的加法运算。
* @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));
}
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(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";// 期限年

/**
* 获取当前营业日期
*
* @return
* @throws Exception
*/
public static String getBusinessDate() throws Exception {
// {
throw new Exception("系统日期未定义，请联系系统管理员设置！");
}

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

/**
* 直接设置系统营业日期
*
* @throws Exception
*/
}

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)) {
} else if (termUnit.equals(DateHelper.TERM_UNIT_MONTH)) {
/********
* 修正超过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)) {
}

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);

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)) {
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
*/
Date busiDate = null;
try {
} catch (Exception e) {
e.printStackTrace();
}

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 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);
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);
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);
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(getDays("2018/11/22", "2018/12/22"));
}

public static Date getDate() throws Exception {
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);
return DateUtils.formatDate(date, AMR_NOMAL_DATE_FORMAT);
}

}


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