js格式化日期时间自动补0的两种解法
场景
将2020-1-2这种日期格式转化为2020-01-02
一、切割字符串
提示:
function formatDate(str) {
// 根据 - 符号拆分
return str
.split("-")
.map((item) => {
// +item 将item字符串转换为数字
// 小于10的时候就补全一个前缀0
if (+item < 10) {
return "0" + +item;
}
// 大于10的时候不用补0
return item;
})
.join("-"); // 最后重组回来
}
// 测试
formatDate("2020-1-2"); // 输出 '2020-01-02'
二、正则
- 前瞻:(?=),后顾:(?<=)
提示:可以用来识别-、/、.等字符之间的数字
// 前瞻:
A(?=B) //查找B前面的A
// 后顾:
(?<=B)A //查找B后面的A
// 负前瞻:
A(?!B) //查找后面不是B的A
// 负后顾:
(?<!B)A //查找前面不是B的A
- 单词边界:\b
提示:用于识别-到日期开始或结束位置的数字,比如2020-1-2 3:4:5中,2后面的间隙,1前面的间隙,5后面的间隙,都是单词边界
单词指的是\w可以匹配的字符,即数字、大小写字母以及下划线 [0-9a-zA-Z_]
边界 指的是占位的字符左右的间隙位置 - replace方法替换匹配的字符串:$&
// 使用$&匹配
function formatDate(str) {
/*
replace第一个参数正则
(?<=\/|-|\.|:|\b)\d{1} 用的是后顾,查找 / 或者 - 或者 . 或者 : 或者 单词边界 或者 T 后面的一个数字
\d{1}(?=\/|-|\.|:|\b) 用的是前瞻,查找 / 或者 - 或者 . 或者 : 或者 单词边界 或者 T 前面的一个数字
replace 第二个参数"0$&" 匹配到的字符串前置补0
*/
// 直接 return 打包报错
return str.replace(/(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g, "0$&");
// 解决打包报错问题
let regExp = new RegExp("(?<=\/|-|\\.|\:|\\b|T)\\d{1}(?=\/|-|\\.|\:|\\b|T)", "g")
return str.replace(regExp, "0$&");
}
// 使用$1匹配
function formatDate(str) {
/*
replace第一个参数正则和上面的一样
replace 第二个参数是一个函数,第一个入参就是匹配到的第一个参数,可以在函数内处理补0
*/
return str.replace(
/(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g,
function ($1) {
return "0" + $1;
}
);
}
// 测试
formatDate("2020-1-2 3:4:5"); // 输出 '2020-01-02 03:04:05'
formatDate("2020/1/2"); // 输出 '2020/01/02'
formatDate("2020.1.2"); // 输出 '2020.01.02'
formatDate("2020/1/2T3:4:5"); // 输出 '2020/01/02T03:04:05'
三、代码(多种格式)
组件 - v-dateYMDFormat
<el-date-picker v-model="birthday" type="date" v-dateYMDFormat value-format="yyyy-MM-dd"> </el-date-picker>
main.js引入
import '@/components/common/js/direct.js'
direct.js
import Vue from 'vue'
import $ from 'jquery'; // 在需要使用的页面中
import moment from 'moment' // 引入js日期处理类库
// 时间日期选择器(年-月-日) - 输入格式转换
Vue.directive('dateFormat', {
inserted: function (el, binding, vnode) {
const { value: _obj } = binding
const { context: _this, data } = vnode
const { expression: key } = data.model
let arr = []
const modelValue = function (value, len) {
// 判断输入的时间为几位数,正则匹配相应的事件格式。可直接采用moment转换,更直接。
value = value.replace(/[^0-9]/g, '')
if (value.length > 5 && value.length < 9) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
} else if (value.length > 9 && value.length < 13) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5') // 格式化输入格式,2021-03-01 09:50
} else if (value.length > 12) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5:$6') // 格式化输入格式,2020-03-01 09:50:30
} else {
return false
}
value = supplement(value)
// const newValue = value.replace(/-/g,"/"); // 解决前台new Date(yyyy-MM-dd)转化时间相差8小时的问题,不知道靠不靠谱,改用moment
// const time = value && value.constructor == String ? new Date(newValue) : value // 转换时间格式
// const time = value && value.constructor == String ? moment(value) : value // 转换时间格式
// const time = value // 转换时间格式
const time = value && value.constructor == String ? value : '' // 转换时间格式
let keys = key.split('.')
if (arr.length === len) {
arr = [];
}
arr.push(time)
// 判断指令是否有传值,是否有传数组的名称跟索引值,原因:转换出来的时间控件_this[key1][key2]取不到绑定的相关值
if (!_obj) {
// 处理简单的绑定
if (keys && keys.length >= 2) {
const [key1, key2, key3, key4] = keys
if (key4) {
_this[key1][key2][key3][key4] = len === 2 ? arr : time;
} else if (key3) {
_this[key1][key2][key3] = len === 2 ? arr : time;
} else {
_this[key1][key2] = len === 2 ? arr : time;
}
} else {
_this[key] = len === 2 ? arr : time;
}
} else {
// 处理循环中的时间控件绑定,需要传值,再去相应的数组中查找相应的字段赋值
let objKey = _obj.obj.split('.')
if (objKey && objKey.length >= 2) {
// 解构赋值
const [flag1, flag2, flag3, flag4] = objKey;
// _obj.index:索引,_obj.modelName:绑定的字段名
if (flag4) {
_this[flag1][flag2][flag3][flag4][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else if (flag3) {
_this[flag1][flag2][flag3][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else {
_this[flag1][flag2][_obj.index][_obj.modelName] = len === 2 ? arr : time;
}
} else {
_this[objKey][_obj.modelName] = len === 2 ? arr : time;
}
}
};
if (_this && _this._isVue) {
const $this = $($(el).children('input')[0])
const $this2 = $($(el).children('input')[1])
// 判断是范围的还是单个独立的日期时间控件,范围的两个输入框都要绑定change事件
if ($(el).children('input').length > 1) {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 2);
})
$this2.on('change', function () {
let value = $this2.val()
modelValue(value, 2);
})
} else {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 1);
})
}
}
}
})
// 时间日期选择器(年-月-日) - 输入格式转换
Vue.directive('dateYMDFormat', {
inserted: function (el, binding, vnode) {
const { value: _obj } = binding
const { context: _this, data } = vnode
const { expression: key } = data.model
let arr = []
const modelValue = function (value, len) {
// 判断输入的时间为几位数,正则匹配相应的事件格式。可直接采用moment转换,更直接。
value = value.replace(/[^0-9]/g, '')
if (value.length > 5 && value.length < 9) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
} else if (value.length > 9 && value.length < 13) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5') // 格式化输入格式,2021-03-01 09:50
} else if (value.length > 12) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5:$6') // 格式化输入格式,2020-03-01 09:50:30
} else {
return false
}
value = supplement(value)
// const newValue = value.replace(/-/g,"/"); // 解决前台new Date(yyyy-MM-dd)转化时间相差8小时的问题,不知道靠不靠谱,改用moment
// const time = value && value.constructor == String ? new Date(newValue) : value // 转换时间格式
// const time = value && value.constructor == String ? moment(value) : value // 转换时间格式
// const time = value // 转换时间格式
const time = value && value.constructor == String ? value : '' // 转换时间格式
let keys = key.split('.')
if (arr.length === len) {
arr = [];
}
arr.push(time)
// 判断指令是否有传值,是否有传数组的名称跟索引值,原因:转换出来的时间控件_this[key1][key2]取不到绑定的相关值
if (!_obj) {
// 处理简单的绑定
if (keys && keys.length >= 2) {
const [key1, key2, key3, key4] = keys
if (key4) {
_this[key1][key2][key3][key4] = len === 2 ? arr : time;
} else if (key3) {
_this[key1][key2][key3] = len === 2 ? arr : time;
} else {
_this[key1][key2] = len === 2 ? arr : time;
}
} else {
_this[key] = len === 2 ? arr : time;
}
} else {
// 处理循环中的时间控件绑定,需要传值,再去相应的数组中查找相应的字段赋值
let objKey = _obj.obj.split('.')
if (objKey && objKey.length >= 2) {
// 解构赋值
const [flag1, flag2, flag3, flag4] = objKey;
// _obj.index:索引,_obj.modelName:绑定的字段名
if (flag4) {
_this[flag1][flag2][flag3][flag4][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else if (flag3) {
_this[flag1][flag2][flag3][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else {
_this[flag1][flag2][_obj.index][_obj.modelName] = len === 2 ? arr : time;
}
} else {
_this[objKey][_obj.modelName] = len === 2 ? arr : time;
}
}
};
if (_this && _this._isVue) {
const $this = $($(el).children('input')[0])
const $this2 = $($(el).children('input')[1])
// 判断是范围的还是单个独立的日期时间控件,范围的两个输入框都要绑定change事件
if ($(el).children('input').length > 1) {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 2);
})
$this2.on('change', function () {
let value = $this2.val()
modelValue(value, 2);
})
} else {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 1);
})
}
}
}
})
// 时间月份选择器(年-月-01) - 输入格式转换
Vue.directive('monthYMDFormat', {
inserted: function (el, binding, vnode) {
const { value: _obj } = binding
const { context: _this, data } = vnode
const { expression: key } = data.model
let arr = []
const modelValue = function (value, len) {
// 判断输入的时间为几位数,正则匹配相应的事件格式。可直接采用moment转换,更直接。
value = value.replace(/[^0-9]/g, '')
if (value.length > 5 && value.length < 7) {
value = value + '01'
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
// } else
// if (value.length > 5 && value.length < 9) {
// value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
// } else if (value.length > 9 && value.length < 13) {
// value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5') // 格式化输入格式,2021-03-01 09:50
// } else if (value.length > 12) {
// value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3 $4:$5:$6') // 格式化输入格式,2020-03-01 09:50:30
} else {
return false
}
value = supplement(value)
// const newValue = value.replace(/-/g,"/"); // 解决前台new Date(yyyy-MM-dd)转化时间相差8小时的问题,不知道靠不靠谱,改用moment
// const time = value && value.constructor == String ? new Date(newValue) : value // 转换时间格式
// const time = value && value.constructor == String ? moment(value) : value // 转换时间格式
// const time = value // 转换时间格式
const time = value && value.constructor == String ? value : '' // 转换时间格式
let keys = key.split('.')
if (arr.length === len) {
arr = [];
}
arr.push(time)
// 判断指令是否有传值,是否有传数组的名称跟索引值,原因:转换出来的时间控件_this[key1][key2]取不到绑定的相关值
if (!_obj) {
// 处理简单的绑定
if (keys && keys.length >= 2) {
const [key1, key2, key3, key4] = keys
if (key4) {
_this[key1][key2][key3][key4] = len === 2 ? arr : time;
} else if (key3) {
_this[key1][key2][key3] = len === 2 ? arr : time;
} else {
_this[key1][key2] = len === 2 ? arr : time;
}
} else {
_this[key] = len === 2 ? arr : time;
}
} else {
// 处理循环中的时间控件绑定,需要传值,再去相应的数组中查找相应的字段赋值
let objKey = _obj.obj.split('.')
if (objKey && objKey.length >= 2) {
// 解构赋值
const [flag1, flag2, flag3, flag4] = objKey;
// _obj.index:索引,_obj.modelName:绑定的字段名
if (flag4) {
_this[flag1][flag2][flag3][flag4][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else if (flag3) {
_this[flag1][flag2][flag3][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else {
_this[flag1][flag2][_obj.index][_obj.modelName] = len === 2 ? arr : time;
}
} else {
_this[objKey][_obj.modelName] = len === 2 ? arr : time;
}
}
};
if (_this && _this._isVue) {
const $this = $($(el).children('input')[0])
const $this2 = $($(el).children('input')[1])
// 判断是范围的还是单个独立的日期时间控件,范围的两个输入框都要绑定change事件
if ($(el).children('input').length > 1) {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 2);
})
$this2.on('change', function () {
let value = $this2.val()
modelValue(value, 2);
})
} else {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 1);
})
}
}
}
})
// 时间月份选择器(年-月) - 输入格式转换
Vue.directive('monthYMFormat', {
inserted: function (el, binding, vnode) {
const { value: _obj } = binding
const { context: _this, data } = vnode
const { expression: key } = data.model
let arr = []
const modelValue = function (value, len) {
// 判断输入的时间为几位数,正则匹配相应的事件格式。可直接采用moment转换,更直接。
value = value.replace(/[^0-9]/g, '')
if (value.length === 5) {
value = value.replace(/^(\d{4})\D*(\d{1})\D*/, '$1-0$2') // 格式化输入格式,2021-03
} else if (value.length > 5) {
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*/, '$1-$2') // 格式化输入格式,2021-03
} else {
return false
}
value = supplement(value)
const time = value && value.constructor == String ? value : '' // 转换时间格式
let keys = key.split('.')
if (arr.length === len) {
arr = [];
}
arr.push(time)
// 判断指令是否有传值,是否有传数组的名称跟索引值,原因:转换出来的时间控件_this[key1][key2]取不到绑定的相关值
if (!_obj) {
// 处理简单的绑定
if (keys && keys.length >= 2) {
const [key1, key2, key3, key4] = keys
if (key4) {
_this[key1][key2][key3][key4] = len === 2 ? arr : time;
} else if (key3) {
_this[key1][key2][key3] = len === 2 ? arr : time;
} else {
_this[key1][key2] = len === 2 ? arr : time;
}
} else {
_this[key] = len === 2 ? arr : time;
}
} else {
// 处理循环中的时间控件绑定,需要传值,再去相应的数组中查找相应的字段赋值
let objKey = _obj.obj.split('.')
if (objKey && objKey.length >= 2) {
// 解构赋值
const [flag1, flag2, flag3, flag4] = objKey;
// _obj.index:索引,_obj.modelName:绑定的字段名
if (flag4) {
_this[flag1][flag2][flag3][flag4][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else if (flag3) {
_this[flag1][flag2][flag3][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else {
_this[flag1][flag2][_obj.index][_obj.modelName] = len === 2 ? arr : time;
}
} else {
_this[objKey][_obj.modelName] = len === 2 ? arr : time;
}
}
};
if (_this && _this._isVue) {
const $this = $($(el).children('input')[0])
const $this2 = $($(el).children('input')[1])
// 判断是范围的还是单个独立的日期时间控件,范围的两个输入框都要绑定change事件
if ($(el).children('input').length > 1) {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 2);
})
$this2.on('change', function () {
let value = $this2.val()
modelValue(value, 2);
})
} else {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 1);
})
}
}
}
})
// 时间月份选择器(年-01-01) - 输入格式转换
Vue.directive('yearYMDFormat', {
inserted: function (el, binding, vnode) {
const { value: _obj } = binding
const { context: _this, data } = vnode
const { expression: key } = data.model
let arr = []
const modelValue = function (value, len) {
// 判断输入的时间为几位数,正则匹配相应的事件格式。可直接采用moment转换,更直接。
value = value.replace(/[^0-9]/g, '')
if (value.length <= 4) {
value = value + '0101'
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
} else if (value.length <= 4) {
value = value.substring(0, 4) + '0101'
value = value.replace(/^(\d{4})\D*(\d{1,2})\D*(\d{1,2})\D*/, '$1-$2-$3') // 格式化输入格式,2021-03-01
} else {
return false
}
value = supplement(value)
// const newValue = value.replace(/-/g,"/"); // 解决前台new Date(yyyy-MM-dd)转化时间相差8小时的问题,不知道靠不靠谱,改用moment
// const time = value && value.constructor == String ? new Date(newValue) : value // 转换时间格式
// const time = value && value.constructor == String ? moment(value) : value // 转换时间格式
// const time = value // 转换时间格式
const time = value && value.constructor == String ? value : '' // 转换时间格式
let keys = key.split('.')
if (arr.length === len) {
arr = [];
}
arr.push(time)
// 判断指令是否有传值,是否有传数组的名称跟索引值,原因:转换出来的时间控件_this[key1][key2]取不到绑定的相关值
if (!_obj) {
// 处理简单的绑定
if (keys && keys.length >= 2) {
const [key1, key2, key3, key4] = keys
if (key4) {
_this[key1][key2][key3][key4] = len === 2 ? arr : time;
} else if (key3) {
_this[key1][key2][key3] = len === 2 ? arr : time;
} else {
_this[key1][key2] = len === 2 ? arr : time;
}
} else {
_this[key] = len === 2 ? arr : time;
}
} else {
// 处理循环中的时间控件绑定,需要传值,再去相应的数组中查找相应的字段赋值
let objKey = _obj.obj.split('.')
if (objKey && objKey.length >= 2) {
// 解构赋值
const [flag1, flag2, flag3, flag4] = objKey;
// _obj.index:索引,_obj.modelName:绑定的字段名
if (flag4) {
_this[flag1][flag2][flag3][flag4][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else if (flag3) {
_this[flag1][flag2][flag3][_obj.index][_obj.modelName] = len === 2 ? arr : time;
} else {
_this[flag1][flag2][_obj.index][_obj.modelName] = len === 2 ? arr : time;
}
} else {
_this[objKey][_obj.modelName] = len === 2 ? arr : time;
}
}
};
if (_this && _this._isVue) {
const $this = $($(el).children('input')[0])
const $this2 = $($(el).children('input')[1])
// 判断是范围的还是单个独立的日期时间控件,范围的两个输入框都要绑定change事件
if ($(el).children('input').length > 1) {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 2);
})
$this2.on('change', function () {
let value = $this2.val()
modelValue(value, 2);
})
} else {
$this.on('change', function () {
let value = $this.val()
modelValue(value, 1);
})
}
}
}
})
// 补0
// 使用$&匹配
function supplement(str) {
// replace第一个参数正则
// (?<=\/|-|\.|:|\b)\d{1} 用的是后顾,查找 / 或者 - 或者 . 或者 : 或者 单词边界 或者 T 后面的一个数字
// \d{1}(?=\/|-|\.|:|\b) 用的是前瞻,查找 / 或者 - 或者 . 或者 : 或者 单词边界 或者 T 前面的一个数字
// replace 第二个参数"0$&" 匹配到的字符串前置补0
// return str.replace(/(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g, "0$&");
let regExp = new RegExp("(?<=\/|-|\\.|\:|\\b|T)\\d{1}(?=\/|-|\\.|\:|\\b|T)", "g")
return str.replace(regExp, "0$&");
}