不知道大家有没有尝试封装过一个时间格式化的函数啊,在之前我封装的时候,开始是觉得手到擒来,但是实践之后发现写非常的shi啊,大量的分支判断,哪怕是映射起到的作用也只是稍微好一点,不过比较好的是,当天晚上我就看见了袁教头的参数归一化讲解啊,立马就让我眼界大开,如果你也不知道,就一起来看一下
时间格式化,一个基础的知识,也没有什么难度,但是如果要变得通用一点,那么就不是那么容易处理了
由这个参数最为难搞,比如存在一个 formatDateTime 方法,使用如下:
// 日期 2023-12-29
formatDateTime(new Date(), 'date')
// 日期时间 2023-12-29 6:23:3
formatDateTime(new Date(), 'dateTime')
// 年月日时分秒[不补0] 2023-12-29 6:23:3
formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss')
// 年月日时分秒 2023-12-29 06:23:03
formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss', true)
// 年月日时分秒毫秒 2023-12-29 06:23:03:015
formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss:ms', true)
// 自定义函数处理
formatDateTime(new Date(), dateInfo => {
// ...
})
那诸如这些情况,怎么写呢,最简单粗暴的就莫过于 if 判断了,但是这种判断写起来的话可想而知
所以应该怎么处理呢?其实仔细看一下,这些参数无论是 date 还是 dateTime 或者其他,最后无非就是要得到一个格式化后的时间,那么这一步都是可以通过一个函数来处理完成的,所以我们首先第一步就是搞定,无论参数是什么情况,都将其转化为一个函数,而这种将不同的情况转换为一种情况,就是参数归一化
我们上面列举的参数大致可以分为传递的函数和字符串,字符串又分为固定的词汇和用户传入一些自定义的时间格式,但是 yyyy-MM-dd HH:mm:ss 这种情况是可以将 date、dateTime 也包含在内的,所以如果我们可以将这个 date 转为 yyyy-MM-dd,将 dateTime 转为 yyyy-MM-dd HH:mm:ss 是不是就可以将多种情况变为一种情况了
要完成这个参数的归一,我们需要一个辅助函数,这个函数会返回给我们一个函数,定义函数 _format,如下:
function _format(format) {}
function formatDateTime(date, format, isPad) {
const f = _format(format)
}
那么 _format 函数应该怎么实现呢?首先判断类型,传入的参数是否是一个函数,如果是一个函数则直接返回,在判断是否是一个字符串,如果是字符串在将 date 和 dateTime 变为自定义的格式,如下:
function _format(format) {
if (typeof format === 'function') {
return format
}
if (typeof format !== 'string') {
throw new Error('format must be string or function')
}
if (format === 'date') {
format = 'yyyy-MM-dd'
}
if (format === 'dateTime') {
format = 'yyyy-MM-dd HH:mm:ss'
}
}
此时我们就已经将参数都处理为一种情况了。现在就是返回一个函数来出来这个结果,怎么处理呢?那只能是你给我一些数据,比如 year、month… 等等这些信息,然后我这个返回的函数内部替换一下即可,如下:
function _format(format) {
if (typeof format === 'function') {
return format
}
if (typeof format !== 'string') {
throw new Error('format must be string or function')
}
if (format === 'date') {
format = 'yyyy-MM-dd'
}
if (format === 'dateTime') {
format = 'yyyy-MM-dd HH:mm:ss'
}
const result = dateInfo => {
const { year, month, day, hour, minute, second, millisecond } = dateInfo
return format
.replaceAll('yyyy', year)
.replaceAll('MM', month)
.replaceAll('dd', day)
.replaceAll('HH', hour)
.replaceAll('mm', minute)
.replaceAll('ss', second)
.replaceAll('ms', millisecond)
}
return result
}
可以看到,我们需要返回的这个函数,需要接收一些数据,那这些是不是就很好处理了呢,如下:
function isDate(value) {
return value instanceof Date
}
function formatDateTime(date, format, isPad) {
// 判断传递的 date 是否是一个时间对象
date = isDate(date) ? date : new Date(date)
// 如果 date 为 Invalid Date 就报错
if (isNaN(date.getTime())) {
throw new Error('Invalid Date')
}
const f = _format(format)
// 得到 year, month, day, hour, minute, second, millisecond
const dateInfo = {
year: date.getFullYear().toString(),
month: (date.getMonth() + 1).toString(),
day: date.getDate().toString(),
hour: date.getHours().toString(),
minute: date.getMinutes().toString(),
second: date.getSeconds().toString(),
millisecond: date.getMilliseconds().toString()
}
}
此时我们还需要对这些数据进行进一步的处理,比如是否补零,如下:
function formatDateTime(date, format, isPad) {
// 判断传递的 date 是否是一个时间对象
date = isDate(date) ? date : new Date(date)
// 如果 date 为 Invalid Date 就报错
if (isNaN(date.getTime())) {
throw new Error('Invalid Date')
}
const f = _format(format)
// 得到 year, month, day, hour, minute, second, millisecond
const dateInfo = {
year: date.getFullYear().toString(),
month: (date.getMonth() + 1).toString(),
day: date.getDate().toString(),
hour: date.getHours().toString(),
minute: date.getMinutes().toString(),
second: date.getSeconds().toString(),
millisecond: date.getMilliseconds().toString()
}
function _isPad(prop, len) {
dateInfo[prop] = dateInfo[prop].padStart(len, '0')
}
// 是否补零
if (isPad) {
_isPad('year', 4)
_isPad('month', 2)
_isPad('day', 2)
_isPad('hour', 2)
_isPad('minute', 2)
_isPad('second', 2)
_isPad('millisecond', 3)
}
return f(dateInfo)
}
结果如图:
来看看传递函数的结果,如图:
基于此,我们还可以更换分割符使用,如下:
怎么样,这样是不是对比直接使用 if 来判断参数格式化,要优雅不少呢
function _format(format) {
if (typeof format === 'function') {
return format
}
if (typeof format !== 'string') {
throw new Error('format must be string or function')
}
if (format === 'date') {
format = 'yyyy-MM-dd'
}
if (format === 'dateTime') {
format = 'yyyy-MM-dd HH:mm:ss'
}
const result = dateInfo => {
const { year, month, day, hour, minute, second, millisecond } = dateInfo
return format
.replaceAll('yyyy', year)
.replaceAll('MM', month)
.replaceAll('dd', day)
.replaceAll('HH', hour)
.replaceAll('mm', minute)
.replaceAll('ss', second)
.replaceAll('ms', millisecond)
}
return result
}
function isDate(value) {
return value instanceof Date
}
function formatDateTime(date, format, isPad) {
date = isDate(date) ? date : new Date(date)
if (isNaN(date.getTime())) {
throw new Error('Invalid Date')
}
const f = _format(format)
const dateInfo = {
year: date.getFullYear().toString(),
month: (date.getMonth() + 1).toString(),
day: date.getDate().toString(),
hour: date.getHours().toString(),
minute: date.getMinutes().toString(),
second: date.getSeconds().toString(),
millisecond: date.getMilliseconds().toString()
}
function _isPad(prop, len) {
dateInfo[prop] = dateInfo[prop].padStart(len, '0')
}
if (isPad) {
_isPad('year', 4)
_isPad('month', 2)
_isPad('day', 2)
_isPad('hour', 2)
_isPad('minute', 2)
_isPad('second', 2)
_isPad('millisecond', 3)
}
return f(dateInfo)
}