JS: 基于moment封装自定义时间显示规则工具类

910 阅读8分钟

简介

官方解释moment.js是JavaScript 日期处理类库,也就是用于日期格式转换的。官网地址:momentjs.cn/

当时再做个关于日期规则转换显示的需求,如下需求: 时间显示规则:

  1. 已当前的时间作为基准,如果是今天的日期显示为:  今天12:00
  2. 如果是昨天的日期显示为:昨天  12:00
  3. 如果是前天的日期显示为:前天  12:00
  4. 如果是前天以前的日期显示为:04-20 12:00
  5. 如果是明天的日期显示为:明天  12:00
  6. 如果是后天的日期显示为:后天  12:00
  7. 如果是后天以后的日期显示为:04-23 12:00
  8. 如果是不在当年的日期显示为:2021–4-20 12:00
  9. 当没有设置时间,不显示
  10. 当只设置了开始时间,只显示开始时间+开始
  11. 当只设置了结束时间,只显示结束时间+截止
  12. 当设置了开始时间和结束时间,显示为:开始时间-结束时间

后面仔细看了下需求文档,好多地方都是用这个规则,索性就把它封装成一个工具类,需要到的时候直接引入即可; 大体的效果如下,录制部分Git

QQ20230206-085142-HD.gif

下载Moment

这里稍微介绍下,moment的下载方式

npm install moment --save   # npm
yarn add moment             # Yarn
Install-Package Moment.js   # NuGet
spm install moment --save   # spm
meteor add momentjs:moment  # meteor
bower install moment --save # bower (废弃)

基础用法

贴一下曾测试过的moment封装的相关方法,并加了备注,后期遇到类似需求可以直接找到

日期格式化
moment().format('MMMM Do YYYY, h:mm:ss a'); // 九月 29日 2022, 5:26:19 下午
moment().format('dddd');                    // 星期四
moment().format("MMM Do YY");               // 9月 29日 22
moment().format('YYYY [escaped] YYYY');     // 2022 escaped 2022
moment().format();                          // 2022-09-29T17:26:19+08:00
相对时间
moment("20111031", "YYYYMMDD").fromNow(); // 11 年前
moment("20120620", "YYYYMMDD").fromNow(); // 10 年前
moment().startOf('day').fromNow();        // 17 小时前
moment().endOf('day').fromNow();          // 7 小时内
moment().startOf('hour').fromNow();       // 26 分钟前
日历时间
moment().subtract(10, 'days').calendar(); // 2022/09/19
moment().subtract(6, 'days').calendar();  // 上星期五17:26
moment().subtract(3, 'days').calendar();  // 上星期一17:26
moment().subtract(1, 'days').calendar();  // 昨天17:26
moment().calendar();                      // 今天17:26
moment().add(1, 'days').calendar();       // 明天17:26
moment().add(3, 'days').calendar();       // 下星期日17:26
moment().add(10, 'days').calendar();      // 2022/10/09
多语言支持
moment.locale();         // zh-cn
moment().format('LT');   // 17:26
moment().format('LTS');  // 17:26:19
moment().format('L');    // 2022/09/29
moment().format('l');    // 2022/9/29
moment().format('LL');   // 2022年9月29日
moment().format('ll');   // 2022年9月29日
moment().format('LLL');  // 2022年9月29日下午5点26分
moment().format('lll');  // 2022年9月29日 17:26
moment().format('LLLL'); // 2022年9月29日星期四下午5点26分
moment().format('llll'); // 2022年9月29日星期四 17:26

需求实现

思路

实现简介中所描述的需求,这里大体跟大家分享下我的个人思路

1、先使用moment转换格式截取 YYYY-MM-DD hh:mm:ss等其中一部分变为字符串,然后再用moment转回成对象

2、需求中,是通过比较年月日这部分时间,来区分今天、明天、后台、前天,所以只需要将原始时间对象截图YYYY-MM-DD这部分即可,但是又因为后续要用到时分HH:MM这部分的数据,所以需要将原始对象给整体保存下来,方便后续的回显;

3、然后用moment中的diff方法只针对截取的部分转换成的时或分或秒进行比对,按照需求规则一一判断。

封装好的代码

formatDateText需要接收一个日期字符串或者moment对象

dateOriginMoment用于保存传入formatDateText的参数

// 比较时间差
export function formatDateText(dateOrigin) {
  console.log(typeof dateOrigin === 'string')
  if(!dateOrigin) return;
  let today = moment(new Date()).format('YYYY-MM-DD')
  let date = null
  let dateOriginMoment = null;
  if(typeof dateOrigin === 'string') {
    date = moment(dateOrigin).format('YYYY-MM-DD')
    dateOriginMoment = moment(dateOrigin);
  } else {
    console.log(dateOrigin)
    date = dateOrigin.format('YYYY-MM-DD')
    dateOriginMoment = dateOrigin;

  }

  today = moment(today)
  date = moment(date)
  console.log(today, date)
 
  // const diff_minute = date.diff(today, "minutes");
  // const diff_hour = date.diff(today, "hours");
  const diff_day = date.diff(today, "days");
  // const diff_month = date.diff(today, "months");
  // const diff_year = date.diff(today, "years");
  // console.log(diff_minute, diff_hour,diff_day,diff_month, diff_year)

  let msg = ''
  switch (diff_day) {
    case 2:
      msg = '后天'
      break;
    case 1:
      msg = '明天'
      break;
    case 0:
      msg = '今天'
      break;
    case -1:
      msg = '昨天'
      break;
    case -2:
      msg = '前天'
      break;
    default:
      break;
  }
  if(msg) {
    return msg+ ' ' + dateOriginMoment.format('HH:mm')
  } 

  // 年份相同需要截取年部分进行比较
  let currentYear = Number(today.format('YYYY'))
  let selectYear = Number(date.format('YYYY'))
  if(currentYear === selectYear) { // 年份相同
    return dateOriginMoment.format('MM-DD HH:mm')
  } else {
    return dateOriginMoment.format('YYYY-MM-DD HH:mm')
  }
}

扩展

1.日期格式化

//moment().format(String)
moment().format(); //moment 2020-03-23T18:20:11+08:00
//年份
moment().format('YYYY'); //2020
//季度
moment().format('Q'); //1
//月份
moment().format('MMMM'); //March
//月份的日期
moment().format('DD'); //24
//年份的日期
moment().format('DDD'); //84
//星期几
moment().format('dddd'); //Monday
//更具体的格式
moment().format('YYYY-MM-DD HH:mm:ss'); //2020-03-23 18:10:54
moment().format('YYYY[测]MM[试]DD HH[时]mm[间]ss'); //2020测03试23 18时25间42
moment().format('YYYY [test] YYYY'); //2020 test 2020
moment().format('YYYY [test] MM'); //2020 test 03
moment().format('YYYY [test] DD'); //2020 test 23

2.时间戳字符串相互转换

moment(1259186487000).format('YYYY-MM-DD HH:mm:ss'); //2009-11-26 06:01:27
moment('2009-11-26 06:01:27').valueOf(); //1259186487000
+moment('2009-11-26 06:01:27'); //1259186487000

3.相对时间

moment('20091126', 'YYYYMMDD').fromNow(); //10 years ago
moment('20091126', 'YYYYMMDD').fromNow(true); //10 years
moment([2009, 11, 26]).fromNow(); //10 years ago
moment().startOf('day').fromNow(); //15 hours ago
moment().endOf('hour').fromNow(); //in 24 minutes

4.时间查询

//查询当前年份是否为闰年
moment([2009]).isLeapYear(); //false
//检查一个时间是否在另一个时间之前(精确到秒比较)
moment('2009-11-26 06:01:27').isBefore('2009-11-26 06:01:28'); //true
//检查一个时间是否在另一个时间之前(精确到年比较)
moment('2009-11-26 06:01:27').isBefore('2009-11-26 06:01:28', 'year'); //false
//检查一个时间是否在另一个时间之后
moment('2009-11-26').isAfter('2020-11-26', 'year'); //false
//检查一个时间是否在其他两个时间之间
moment('2016-11-26').isBetween('2009-11-26', '2020-11-26'); //true
//获取当月的天数
moment('2009-11', 'YYYY-MM').daysInMonth(); //30
//获取当前 moment 年份的周数
moment().weeksInYear(); //52

5.时间计算

//时间增加
moment().add(4, 'years').format('YYYY-MM-DD'); //2024-03-24
moment().add(4, 'months').format('YYYY-MM-DD'); //2020-07-24
moment().add(4, 'days').format('YYYY-MM-DD'); //2020-03-28
moment([2016]).add(4, 'years').format('YYYY'); //2020
//时间减少
moment().subtract(10, 'years').format('YYYY'); //2010
//设置为时间单位的开头对时间进行更改
moment().startOf('hour').format('YYYY-MM-DD HH:mm:ss'); //2020-03-24 15:00:00
//设置为时间单位的末尾对时间进行更改
moment().endOf('hour').format('YYYY-MM-DD HH:mm:ss'); //2020-03-24 15:59:59

6.时长创建

//要创建时长,调用 moment.duration(),默认以毫秒为单位。
//创建时长1500毫秒
moment.duration(1500);
//获取时长的毫秒数(返回 0 至 999 之间的数字)
moment.duration(1500).milliseconds(); //500
//获取时长的秒数(返回 0 至 59 之间的数字)
moment.duration(1500).seconds(); //1
//获取时长的长度(以秒为单位)
moment.duration(1500).asSeconds(); //1.5
//以秒为单位创建时长
moment.duration(2, 'seconds');
//以年为单位创建时长
moment.duration(2, 'years');

7.日历时间显示

//moment().calendar(referenceTime, formats);
//moment#calendar 会根据日期与 referenceTime 的日期(默认为今天)的接近程度,使用不同的字符串格式化日期
moment().calendar(); //Today at 3:35 PM
moment().calendar(null, {
    sameDay: '[今天]',
    nextDay: '[明天]',
    nextWeek: 'dddd',
    lastDay: '[昨天]',
    lastWeek: '[上个] dddd',
    sameElse: 'DD/MM/YYYY'
}); //今天

moment().calendar('2020-03-25', {
    sameDay: '[今天]',
    nextDay: '[明天]',
    nextWeek: 'dddd',
    lastDay: '[昨天]',
    lastWeek: '[上个] dddd',
    sameElse: 'DD/MM/YYYY'
}); //昨天

moment().calendar(null, {
  sameDay: function (now) {
    if (this.isBefore(now)) {
      return '[今天将会发生]';
    } else {
      return '[今天已发生]';
    }
    /* ... */
  }
}); //今天已发生