计算规则
费用 = 数量 * 单价。数量根据开始日期和结束日期计算,例如日期区间为2021-09-05~2021-12-08,9月5日-10月4日这种为一个月,不足一个月则数量 = 天数 / 自然月天数,则数量 = 3 + 4 / 31
由于每个月天数不一样,2月又比较特殊,可能出现的情况比较多,下表列出所有可能的情况,并列出计算规则
| 开始日期 | 结束日期 | 数量计算规则 | 备注 |
|---|---|---|---|
| 2021-11-10 | 2021-12-09 | 1 | |
| 2021-11-10 | 2021-12-08 | (30 - 10 + 1) / 30 + 8 / 31 | |
| 2021-11-10 | 2021-11-30 | (30 - 10 + 1) / 30 | |
| 2021-11-10 | 2021-12-12 | 1 + (12 - 9) / 31 | |
| 2021-11-10 | 2022-01-09 | 2 | |
| 2021-11-10 | 2022-01-08 | 1 + (31 - 10 + 1) / 31 + 8 / 31 | (31 - 10 + 1) / 31指12月份 |
| 2021-11-10 | 2022-02-08 | 2 + (31 - 10 + 1) / 31 + 8 / 28 | (31 - 10 + 1) / 31指1月份 |
| 2021-11-10 | 2022-03-08 | 3 + (28 - 10 + 1) / 28 + 8 / 31 | (28 - 10 + 1) / 28指2月份 |
| 2021-11-10 | 2022-01-12 | 2 + (12 - 9) / 31 | |
| 2021-11-10 | 2022-02-12 | 3 + (12 - 9) / 28 | |
| 2021-01-31 | 2021-02-27 | 1 | 1月28、29、30、31 加1个月减去1天后,都等于2月27日 |
| 2021-01-30 | 2021-02-27 | 1 | |
| 2021-01-29 | 2021-02-27 | 1 | |
| 2021-01-28 | 2021-02-27 | 1 | |
| 2021-01-31 | 2021-02-28 | 1 + (28 - 27) / 28 | |
| 2021-01-30 | 2021-02-28 | 1 + (28 - 27) / 28 | |
| 2021-01-29 | 2021-02-28 | 1 + (28 - 27) / 28 | |
| 2021-01-28 | 2021-02-28 | 1 + (28 - 27) / 28 | |
| 2021-01-27 | 2021-02-28 | 1 + (28 - 26) / 28 | |
| 2021-02-01 | 2021-02-28 | 1 |
代码实现
import moment from 'moment';
export default {
methods: {
/**
* 11.5-12.4为一个月
*/
calcAmountAndSum(startTime, endTime) {
let amount = '';
let momentStart = moment(startTime), momentEnd = moment(endTime);
// 开始、结束年、月、日、月天数
let startYear = momentStart.year(), startMonth = momentStart.month(), startDate = momentStart.date();
let endYear = momentEnd.year(), endMonth = momentEnd.month(), endDate = momentEnd.date(), endDaysInMonth = momentEnd.daysInMonth();
// 计算两个日期相差月份
let start = moment([startYear, startMonth, startDate]);
let end = moment([endYear, endMonth, endDate]);
let diff = end.diff(start, 'months', true); // 两个日期相差月份
// 日期:开始月+相差月 用于与结束日期做比较
let startAddDiff = moment(startTime).add(Math.ceil(diff), 'months').subtract(1, 'days');
let startAddDiffDate = startAddDiff.date();
// 日期(结束月上一个月):开始月+(相差月-1)
let lastEnd = moment(startTime).add(Math.ceil(diff) - 1, 'months').subtract(1, 'days');
// 结束月上一个月日期 自然月天数
let lastEndDate = lastEnd.date(), lastEndDaysInMonth = lastEnd.daysInMonth();
// 开始月+相差月日期 === 结束月日期 则数量 = 相差月份
if (startAddDiffDate === endDate) {
amount = Math.ceil(diff);
}
// 开始月+相差月日期 < 结束月日期 则数量 = 相差月份 + (结束日期 - (开始月+相差月日期)) / 结束月自然月天数
else if (startAddDiffDate < endDate) {
amount = Math.floor(diff) + (endDate - startAddDiffDate) / endDaysInMonth;
}
// 开始月+相差月日期 > 结束月日期 则数量 = 相差月份 + (结束月自然月天数 - 结束月上一个月日期) / 结束月自然月天数 + 结束日期 / 结束月自然月天数
else {
amount = Math.floor(diff) + (lastEndDaysInMonth - lastEndDate) / lastEndDaysInMonth + endDate / endDaysInMonth;
}
return this.getRound(amount, 2);
},
/**
* 四舍五入
*/
getRound(num, len) {
if (isNaN(num)) {
return 0;
}
const p1 = Math.pow(10, len + 1);
const p2 = Math.pow(10, len);
return Math.round(num * p1 / 10) / p2;
},
}
}
```