参数归一化-实现时间格式化

文章目录

    • 需求分析
    • 具体实现
    • 完整源码

不知道大家有没有尝试封装过一个时间格式化的函数啊,在之前我封装的时候,开始是觉得手到擒来,但是实践之后发现写非常的shi啊,大量的分支判断,哪怕是映射起到的作用也只是稍微好一点,不过比较好的是,当天晚上我就看见了袁教头的参数归一化讲解啊,立马就让我眼界大开,如果你也不知道,就一起来看一下

需求分析

  1. 时间格式化,一个基础的知识,也没有什么难度,但是如果要变得通用一点,那么就不是那么容易处理了

  2. 由这个参数最为难搞,比如存在一个 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 => {
    	// ...
    })
    
  3. 那诸如这些情况,怎么写呢,最简单粗暴的就莫过于 if 判断了,但是这种判断写起来的话可想而知

  4. 所以应该怎么处理呢?其实仔细看一下,这些参数无论是 date 还是 dateTime 或者其他,最后无非就是要得到一个格式化后的时间,那么这一步都是可以通过一个函数来处理完成的,所以我们首先第一步就是搞定,无论参数是什么情况,都将其转化为一个函数,而这种将不同的情况转换为一种情况,就是参数归一化

具体实现

  1. 我们上面列举的参数大致可以分为传递的函数和字符串,字符串又分为固定的词汇和用户传入一些自定义的时间格式,但是 yyyy-MM-dd HH:mm:ss 这种情况是可以将 date、dateTime 也包含在内的,所以如果我们可以将这个 date 转为 yyyy-MM-dd,将 dateTime 转为 yyyy-MM-dd HH:mm:ss 是不是就可以将多种情况变为一种情况了

  2. 要完成这个参数的归一,我们需要一个辅助函数,这个函数会返回给我们一个函数,定义函数 _format,如下:

    function _format(format) {}
    
    function formatDateTime(date, format, isPad) {
        const f = _format(format)
    }
    
  3. 那么 _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'
    	}
    }
    
  4. 此时我们就已经将参数都处理为一种情况了。现在就是返回一个函数来出来这个结果,怎么处理呢?那只能是你给我一些数据,比如 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
    }
    
  5. 可以看到,我们需要返回的这个函数,需要接收一些数据,那这些是不是就很好处理了呢,如下:

    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()
    	}
    }
    
  6. 此时我们还需要对这些数据进行进一步的处理,比如是否补零,如下:

    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)
    }
    
  7. 结果如图:

    参数归一化-实现时间格式化_第1张图片

  8. 来看看传递函数的结果,如图:

参数归一化-实现时间格式化_第2张图片

  1. 基于此,我们还可以更换分割符使用,如下:

    参数归一化-实现时间格式化_第3张图片

  2. 怎么样,这样是不是对比直接使用 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)
}

你可能感兴趣的:(javascript,前端)