按自然月计算日期间隔

最近在业务中遇到这种状况:要求根据输入的起止日期,计算其日期间隔。例如:

起日止日期限
2020-12-292021-01-2023天
2020-12-292021-02-041个月零7天
2020-01-202020-03-252个月零6天
2020-12-292021-03-313个月零3天
2020-01-052020-02-041个月
2020-01-012020-01-311个月
2020-01-012020-04-304个月
2020-01-012020-02-292个月

在这里插入图片描述

class Moment{
  constructor(date){
    this.date = this.initDate(date);
  }
  // 初始化日期为数组格式
  initDate(date){
    if(date instanceof Date){
      return [date.getFullYear(), date.getMonth()+1, date.getDate()];
    } else if(/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(date)){
      return date.split('-').map(item=>Number(item));
    }else if(date == undefined){
      var cur = new Date();
      return [cur.getFullYear(), cur.getMonth()+1, cur.getDate()];
    }else{
      throw Error('Invalid Date')
    }
  }
  // 是否为闰年:
  // 能被4整除,且不能被100整除
  // 能被400整除
  isLeapYear = function(year) {
    year = year || this.date[0];
    if (typeof year == "number" || Number(year) !== NaN) {
      if ((year % 4 == 0 && year % 100 !== 0) || year % 400 == 0) {
        return true;
      }
      return false;
    } else {
      throw Error("Invalid Date");
    }
  }
  // 判断传入的日期与当前日期哪个在前,哪个在后
  isSameOrBefore = function(dateStr){
    const [year, month, day] = this.date;
    const [curYear, curMonth, curDay] = this.initDate(dateStr);
    if(year < curYear){
      return true;
    } else if(year > curYear){
      return false;
    } else if(year == curYear){
      if(month < curMonth){
        return true;
      } else if(month > curMonth){
        return false
      } else if(month == curMonth){
        if(day <= curDay){
          return true;
        }else if(day > curDay){
          return false;
        }
      }
    }
  }
  // 获取某个月的最后一天(或理解为:获取某个月共有多少天)
  endOfMonth = function (year = this.date[0], month = this.date[1]) {
    const mons = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (month == 2 && this.isLeapYear(year)) {
      return 29;
    }
    return mons[month - 1];
  }
  // 在当前日期的基础上减去几个月/几天
  subtract = function (num, type ) {
    let [year, month, day] = this.date;
    let lastYear = year, lastMonth = month;
    
    if(type ==  'day'){
      return this.subtractDay(lastYear, lastMonth, day - num, );
    } else if(type == 'month'){
      return this.subtractMonth(lastYear, lastMonth - num, day)
    }
  }

  subtractDay = function(year, month, day){
    if(day <= 0){
      if(month - 1 <= 0) {
        month = 12;
        year --;
      }else{
        month -= 1;
      }
      const lastEndDay = this.endOfMonth(year, month)
      day = lastEndDay - (- day);
      return this.subtractDay(year, month, day);
    }else{
      return [year, month, day]
    }
  }

  subtractMonth = function(year, month, day){
    if(month <= 0){
      year --;
      return this.subtractMonth(year, 12 - (-month), day)
    }else{
      const lastEndDay = this.endOfMonth(year, month)
      if(lastEndDay > day){
        return [year, month, day]
      }else{
        return [year, month, lastEndDay]
      }
    }
  }
}

const diff = function(date1, date2){
  const moment1 = new Moment(date1);
  const moment2 = new Moment(date2);
  const isSameOrBefore = moment1.isSameOrBefore(date2);
  let minuYear, minuMonth, minuDay, // 两日期直接相减的差值
  	  endDay, // 较大日期的最后一天
  	  lastEndDay; // 较大日期的上个月的最后一天
  if(isSameOrBefore){
    [minuYear, minuMonth, minuDay] = moment1.date.map((n,i)=> moment2.date[i] - n);
    endDay = moment2.endOfMonth();
    lastEndDay = new Moment(date2.slice(0,8) + '01').subtract(1, 'day')[2];
  }else{
    throw Error('止日不得小于起日!')
  }
  minuDay ++;
  if(minuDay < 0){
    minuMonth --;
    minuDay = lastEndDay - moment1.date[2] + 1 + moment2.date[2];
  } else if(minuDay == endDay){
    minuMonth += 1;
    minuDay = 0;
  }
  if(minuMonth < 0){
    minuMonth += 12;
    minuYear --;
  }
  // 整理返回值 格式
  minuYear = minuYear ? `${minuYear}年` : '';
  minuMonth = minuMonth ? `${minuMonth}个月` : '';
  minuDay = minuDay ? ((minuMonth || minuYear) && minuDay < 10 ? `零${minuDay}天` : `${minuDay}天`) : '';
  return minuYear + minuMonth + minuDay;
}

接下来按照一开始给出的示例进行测试:

console.log(diff('2020-12-29', '2021-01-20'))
console.log(diff('2020-12-29', '2021-02-04'))
console.log(diff('2020-01-20', '2020-03-25'))
console.log(diff('2020-12-29', '2021-03-31'))
console.log(diff('2020-01-05', '2020-02-04'))
console.log(diff('2020-01-01', '2020-01-31'))
console.log(diff('2020-01-01', '2020-04-30'))
console.log(diff('2020-01-01', '2020-02-29'))

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值