moment.js作为一个全球通用库,需要做许多兼容,导致其大而全.在日常项目开发中,往往用不到几个API.个人参与维护的B端项目,组内同事使用其API集中在日期选择组件及前后端日期格式化传递处理上.在项目优化时,通过组内内部约定,采用几个小函数去除moment.js的依赖,可显著减少项目打包体积(moment.min.js 52Kb, moment-with-locales.min.js 327Kb).
日期/时间格式化展示
在与后端进行数据交接时,后端通常接收/传递2018-10-15 15:34:33形式的标准格式,前端在日期选择组件里展示给用户时,也会采用该格式.定义一个函数将日期对象转换为该类字符返回.
export function getDateTime(date = new Date()) {
let arr = [];
arr[0] = date.getFullYear();
arr[1] = date.getMonth() + 1;
arr[2] = date.getDate();
arr[3] = date.getHours();
arr[4] = date.getMinutes();
arr[5] = date.getSeconds();
arr = arr.map(item => item < 10 ? `0${item}`:item);
return `${arr.slice(0,3).join('-')} ${arr.slice(3).join(':)}`;
}
后续可通过该标准日期格式,再二次处理获得一些常用的格式:
- 只需要日期部分: getDateTime(date).slice(0, 10)
- 只需要时间部分: getDateTime(date).slice(10)/getDateTime(date).slice(-8)
- 去掉前置的0: getDateTime(date).replace(/([-|:|\s])0/g, "$1")
// 获取标准时间格式hack方法.
export function getDateTime(date = new Date()) {
const times = date.getTime() - date.getTimezoneOffset() * 6e4;
return new Date(times).toISOString().slice(0,19).replace('T', ' ');
}
//转换为中文日期时间格式
const cn = ['年', '月','日 ', '时', '分', '秒'];
const ret = getDateTime(date).split(/[-:\s]/).map((val, index) => +val + cn[index]).join('');
标准日期格式转换为Date对象
从接口获取到时间字符串,需要转换为日期对象进行后续的区间计算等操作,如计算昨天,今天,近一周,近一个月.
export function toDate(string) {
const args = string.split(/[\-:\s]/);
args[1] -= 1;
return new Date(...args);
}
// 这里有隐性转换, '09' 通过减法运算或给Date()构造函数传递多参数,会转整.
// 如果是ES5,这里spread运算符怎么写? https://babeljs.io/en/repl.html
日期区间计算
在订单查询等业务中,经常会提供今天,昨天,近一周,近一个月等便捷日期选择查询方式,前端需要根据当前日期结合用户操作,转换为后端需要的时间格式进行查询操作.
对于天/时/分/秒,可以加减相应的秒数来处理.
const ONE_DAY = 86400000;
export function getOffsetDay(offset = 0, date = new Date()) {
const seconds = date.getTimes();
const days = new Date(seconds + ONE_DAY * offset);
return getDateTime(days).slice(0, 10);
}
对于月份,计算秒数较复杂,可以利用setMonth来简便处理.不过需要考虑自然月逻辑(7/31减一个月是6/30,而不是7/1(6/31)).
export function getOffsetMonth(offset = 0, date = new Date()) {
const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();
//can add if day >28 for less cacl monthlastday
const monthLastDay = new Date(new Date(year, month+1 + offset, 1, 1) - ONE_DAY).getDate();
if (day > monthLastDay) date.setDate(monthLastDay);
date.setMonth(month + offset);
return getDateTime(date).slice(0, 10);
}
日期比较
日期转换为上面的标准字符格式后,可以直接采用字符串来比较(早于,晚于,等于).日期对象可显式转换为毫秒数(date.getTime()) 或 隐式(调valueOf())来进行比较. 特定区间的日期比较,则可以用上面的函数将日期字符转换为日期对象,加减相应的毫秒数后再用简单的比较方式处理.
notice
- date.set**相关函数会有相应的进位处理.
- date.set**返回值为设置后日期对象的时间戳
- new Date(string) 底层是调用的Date.parse().格式为RFC 2822 或 ISO 8601,具体见MDN链接
- new Date(...args) 多参数时,调用的是Date.UTC()
- new Date(...args) 多参数(2 ~ 7)传递时,当省略相关参数时,采用默认值(0 or 1),而非当前本地时间对应值.
- 直接采用函数方式调用Date(),返回当前时间的字符串形式,忽略传递的参数.
- date.toGMTString()正在弃用,建议使用toUTCString()替代.二者有闰秒之差?
- date.getTimezoneOffset()返回的是当前本地时间与UTC时间相差的分钟数
- date.toJSON返回toISOString字符串,用JSON.stringify深拷贝对象时需要将时间字符转换回来.
文章推荐
developer.mozilla.org/en-US/docs/…
GitHub勘误/交流: github.com/pagemarks/c…