欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

JavaScript日期格式转换指南

最编程 2024-08-03 20:50:44
...

title: Date时间格式化
date: 2021-06-09
description: 这是可以用于项目开发中的时间格式化实践


开始

我们经常在项目中看到Date转换成相关的时间展示,
比如2021年06月20日2021-06-202021年06月20日 18:00:00
本文将介绍如何快速、方便的让Date对象转换成上述的格式

常规操作

const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();

//2021年06月20日
console.log(year + '年' + month + '月' + day + '日' )
//2021年06月20日 18:00:00
console.log(year + '年' + month + '月' + day + '日' + hour+ ':' + minute +':' + second)

上面的方式好处就是足够灵活,可以按照需求任意搭配,不好的地方也有:
1、代码太过于冗长,使用不太友好
2、要是存在多个时间,变量命名容易冲突
3、不方便复用、移植、重构

如何改善

1、针对上面的问题,我们可以通过function来简化整个操作
在js里面,function可以利用他的作用域有效隔离变量命名冲突,
constlet之前还可以通过闭包来实现作用域隔离

2、定义规则,利用正则匹配相关规则实现内容替换,通过字符串的replace来替换上述console的组合操作

3、挂载在Date对象的prototype上面,可以对整个Date对象实现方法扩展,方便复用

定义规则

输入 示例 描述
yyyy 2020 输入几个y就是几位数字的年份
M MM 7 07 月份数字,复数的M当小于10则会追加0
d dd 3 03 月的某天,复数的d当小于10则会追加0
H HH 0..23 小时(24小时制),复数的h当小于10则会追加0
h hh 1..12 小时(12小时制),复数的h当小于10则会追加0
m mm 0..59 分钟,复数的m当小于10则会追加0
s ss 0..59 秒数,复数的s当小于10则会追加0
S SS SSS 0..999 带分数的秒钟,复数的S当小于10则会追加0
w ww 1..7 指定日期的星期中的第几天,复数的w当小于10则会追加0
W 一..天 指定日期的星期中的第几天,汉字一 二 三 四 五 六 天
q 1..4 季度

如何调用

我们在尝试在Date对象上面挂载一个format方法,通过这个方法,传入上面定义的规则实现格式的转换

//定义方法
Date.prototype.format = function(rule){
    console.log(this)
    return rule
}

//方法调用
new Date().format('yyyy-MM-dd HH:mm:ss')

问题:
1.定义在prototype上面是为什么
2.function的声明可不可以使用箭头函数替代

如何转换

上面已经将方法定义好,调用方式也确定了,我们将使用正则去匹配相关的Rule,并生成文本

替换规则:
1、找出相同的规律,建立规则映射结构
2、年份需要单独处理
3、带分数的秒钟需要单独处理
4、汉化的周几需要单独处理

规则1:
通过示例可以看出,大部分的值都是在两位数之内,同时传入复数的规则都会追加0
我们利用正则匹配区间内$n的特性可以获得对应的匹配字符串
string.substring可以实现复数规则追加0
规则2:
年份数值不需要复数规则追加0,传入几个y则展示多少位年份
所以这里要提出来单独处理
规则3:
带分数的秒钟这里的值是三位数字的,和两位数字的处理在string.substring有所不同
所以这里也要提出来单独处理
规则4:
汉化的周几,这里需要建立一个数值映射结构{1: "一",2: "二",3: "三",4: "四",5: "五",6: "六",0: "天"}
所以这里也要提出来单独处理

综上所述,我们用代码实现下面的format函数

Date.prototype.format = function(ruleText){
    const date = {
        "M+": this.getMonth() + 1,
        "d+": this.getDate(),
        "H+": this.getHours(),
        "h+": (this.getHours() + 1) % 12 || 12,
        "m+": this.getMinutes(),
        "s+": this.getSeconds(),
        "q+": Math.floor((this.getMonth() + 3) / 3),
        "w+": this.getDay()
    };
    if (/(y+)/i.test(ruleText)) {
        ruleText = ruleText.replace(
            RegExp.$1,
            (this.getFullYear() + "").substring(4 - RegExp.$1.length)
        );
    }
    if (/(S+)/.test(ruleText)) {
        const ms = this.getMilliseconds();
        ruleText = ruleText.replace(
            RegExp.$1,
            RegExp.$1.length === 1
                ? ms
                : ("000" + ms).substring(("" + ms).length)
        );
    }
    if (/(W+)/.test(ruleText)) {
        const weeks = {1: "一",2: "二",3: "三",4: "四",5: "五",6: "六",0: "天"};
        ruleText = ruleText.replace(RegExp.$1, weeks[date["w+"]]);
    }
    for (const k in date) {
        if (new RegExp("(" + k + ")").test(ruleText)) {
            ruleText = ruleText.replace(
                RegExp.$1,
                RegExp.$1.length === 1
                    ? date[k]
                    : ("00" + date[k]).substring(("" + date[k]).length)
            );
        }
    }
    return ruleText;
}

//测试
new Date().format("测试1=>yyyy年MM月dd日 hh:mm:ss 星期W Qq")
new Date().format("测试2=>yyyy年MM月dd日 HH:mm:ss 星期W Qq")
new Date().format("测试3=>yyyy年MM月d日 H:mm:ss 星期W Qq")
new Date().format("测试3=>yy年M月d日 H:mm:ss 星期W Qq")

运行上面的测试代码,获得如下结果


res1.png

问题:
1.如果传入yyyyyy会发生什么,其他的规则呢
2.针对这个方法还有优化的点吗

总结

1、解决Date时间格式化,在项目中反复的去按照需求规则展示时间的代码冗余
2、将规则语义化,更利于展示和理解
3、可移植性强,能多项目复用,对项目不会产生其余的副作用
至此,整个Date时间格式化函数就完成了