const WEEKDAY = 7;
const run = Symbol('run');
const init = Symbol('init');
const DATE_TIMESTAMP = {
year: {
chs: '年',
timestamp: 12 * 30 * 24 * 60 * 60 * 1000
},
month: {
chs: '月',
timestamp: 30 * 24 * 60 * 60 * 1000
},
day: {
chs: '天',
timestamp: 24 * 60 * 60 * 1000
},
hour: {
chs: '小时',
timestamp: 60 * 60 * 1000
},
minute: {
chs: '分钟',
timestamp: 60 * 1000
},
second: {
chs: '秒',
timestamp: 1000
}
};
const weekdayEnum = [
'周日',
'周一',
'周二',
'周三',
'周四',
'周五',
'周六'
];
Object.freeze(DATE_TIMESTAMP);
Object.freeze(weekdayEnum);
/**
* @description DateTime 时间类,用于处理日常时间格式,以及获取对应时间
* @class DateTime
* @constructor
* @property {String} today 获取当前时间
* @property {String} toFormat 获取当前设置的格式化后的时间字符串
* @property {Date} toDate 获取当前设置的时间格式
* @property setDate 设置时间,实例化后,可根据需求自行设置此时间
* @method isDate 是否为时间格式,仅验证是否为Date
* @method convertDate 尝试转换为时间格式
* @method timeFrom 计算距今的时间差,多久之前
* @method format 格式化传入的时间
* @method addSeconds 目标时间添加秒数
* @method addMinutes 目标时间添加分钟数
* @method addHours 目标时间添加小时数
* @method addDays 目标时间添加分天数
* @method addMonths 目标时间添加月数
* @method addYears 目标时间添加年数
* @method getWeekStart 获取目标时间周一
* @method getWeekEnd 获取目标时间周日
* @method getFirstDay 获取目标时间第一天,月初
* @method getLastDay 获取目标时间的最后一天,月末
*/
class DateTime {
#dateTime;
constructor(date = new Date, format = 'yyyy-MM-dd') {
this.dateFormat = format;
this.#dateTime = DateTime.convertDate(date);
}
/**
* @description 获取当前时间
* @returns {string} 当前时间
*/
get today() {
return DateTime.format(new Date, this.dateFormat);
}
/**
* @description 获取当前设置的格式化后的时间字符串
* @returns {string}
*/
get toFormat() {
return DateTime.format(this.#dateTime, this.dateFormat);
}
/**
* @description 获取当前设置的时间格式
* @returns {*}
*/
get toDate() {
return this.#dateTime;
}
/**
* @description 设置实例时间
* @param date {String|Number|Date}
*/
set setDate(date) {
this.#dateTime = DateTime.convertDate(date);
}
/**
* @description 是否为时间格式
* @method isDate
* @static
* @param date {String|Number|Date}
* @returns {boolean}
*/
static isDate(date) {
return Object.prototype.toString.call(date) === '[object Date]';
}
/**
* @description 尝试转换为时间格式
* @method convertDate
* @static
* @throws 转换失败抛出异常,Invalid Date--日期格式不正确
* @param date {String|Number|Date} 将要转换的值
* @returns {Date|*}
*/
static convertDate(date) {
if (!DateTime.isDate(date)) {
if (typeof date !== "number") {
date = String(date).replace(/[^\s\d:]/g, '/');
}
date = new Date(date);
if (date.toString() === 'Invalid Date') {
console.error('Invalid Date -- 日期格式不正确,仅支持时间戳,“年-月-日 时:分:秒等格式”');
throw new Error('Invalid Date -- 日期格式不正确,仅支持时间戳,“年-月-日 时:分:秒等格式”');
}
return date;
}
return date;
}
/**
* @description 计算距今的时间差,多久之前
* @method timeFrom
* @static
* @param lastTime {String|Number|Date}
* @returns {string} 返回值为距离当前时间的差值,格式为: n秒前,n分钟前,n小时前...
*/
static timeFrom(lastTime, isDiff = false, fromTime = new Date) {
if (isDiff) {
let diff = /^\d+$/g.test(lastTime);
if (!diff) {
lastTime = Number(lastTime);
if (Number.isNaN(lastTime)) {
console.error('时间格式不正确,请输入正确的时间间隔');
throw new Error('时间格式不正确,请输入正确的时间间隔');
}
}
} else {
lastTime = DateTime.convertDate(lastTime).getTime()
}
let txt = '刚刚';
let suffix = '前';
let dateNow = fromTime.getTime();
let diffTime = isDiff ? lastTime : (dateNow - lastTime);
for (let key in DATE_TIMESTAMP) {
let value = DATE_TIMESTAMP[key];
if (diffTime >= value.timestamp && DATE_TIMESTAMP.hasOwnProperty(key)) {
txt = Math.floor(diffTime / value.timestamp) + `${value.chs === '月' ? '个月' : value.chs}` + suffix;
break;
}
}
return txt;
}
/**
* @description 格式化传入的时间
* @method format
* @static
* @param date {String|Number|Date}
* @param format {String} 将要转换的时间格式
* @returns {string} 返回格式化后的时间字符串
*/
static format(date, format = 'yyyy/MM/dd hh:mm:ss') {
date = DateTime.convertDate(date);
if (/(y+)/.test(format)) {
format = format.replace(RegExp.$1, String(date.getFullYear()).substr(4 - RegExp.$1.length));
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'wk': weekdayEnum[date.getDay()],
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
};
for (let k in o) {
if (new RegExp(`(${k})`).test(format)) {
let str = o[k] + '';
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : (str.padStart(2, '0')));
}
}
return format;
}
/**
* @description 回到今天
* @return {DateTime}
*/
backToday() {
this.#dateTime = new Date;
return this;
}
/**
* @description 添加n秒
* @method addSeconds
* @param secondNum {String|Number}
* @returns {DateTime} 返回实例
*/
addSeconds(secondNum) {
let second = Number.parseInt(secondNum);
this[run]({
second
});
return this;
}
/**
* @description 添加 n 分钟
* @method addMinutes
* @param minuteNum {String|Number}
* @returns {DateTime} 实例
*/
addMinutes(minuteNum) {
let minute = Number.parseInt(minuteNum);
this[run]({
minute
});
return this;
}
/**
* @description 添加 n 小时
* @method addHours
* @param hourNum {String|Number}
* @returns {DateTime} 实例
*/
addHours(hourNum) {
let hour = Number.parseInt(hourNum);
this[run]({
hour
});
return this;
}
/**
* @description 添加 n 天
* @method addDays
* @param dayNum {String|Number}
* @returns {DateTime} 实例
*/
addDays(dayNum) {
let day = Number.parseInt(dayNum);
this[run]({
day
});
return this;
}
/**
* @description 添加 n 星期
* @method addWeeks
* @param weekNum {String|Number}
* @returns {DateTime} 实例
*/
addWeeks(weekNum) {
let week = Number.parseInt(weekNum);
this[run]({
week
});
return this;
}
/**
* @description 添加 n 个月
* @method addMonths
* @param monthNum {String|Number}
* @returns {DateTime} 实例
*/
addMonths(monthNum) {
let month = Number.parseInt(monthNum);
this[run]({
month
});
return this;
}
/**
* @description 添加 n 年
* @method addYears
* @param yearNum {String|Number}
* @returns {DateTime} 实例
*/
addYears(yearNum) {
let year = Number.parseInt(yearNum);
this[run]({
year
});
return this;
}
/**
* @description 获取周一
* @method getWeekStart
* @param isCurWeek 是否获取当前时间的周一,true:当前时间, false:实例时间
* @param format 时间格式
* @returns {DateTime} 实例
*/
getWeekStart(isCurWeek = true, format = this.dateFormat) {
this[init](isCurWeek, format);
let wk = this.#dateTime.getDay() || WEEKDAY;
let toFormat = this[run]({
day: 1 - wk
}).toFormat;
this.backToday();
return toFormat;
}
/**
* @description 获取周日
* @method getWeekEnd
* @param isCurWeek {Boolean|String} 是否获取当前时间的周日,true:当前时间, false:实例时间
* @param format {String} 时间格式
* @returns {DateTime} 实例
*/
getWeekEnd(isCurWeek = true, format = this.dateFormat) {
this[init](isCurWeek, format);
let wk = this.#dateTime.getDay() || WEEKDAY;
let toFormat = this[run]({
day: WEEKDAY - wk
}).toFormat;
this.backToday();
return toFormat;
}
/**
* @description 获取月份第一天
* @method getFirstDay
* @param isCurMonth {Boolean|String} 是否获取当前时间的月初,true:当前时间, false:实例时间
* @param format {String} 时间格式
* @returns {DateTime} 实例
*/
getFirstDay(isCurMonth = true, format = this.dateFormat) {
this[init](isCurMonth, format);
let d = this.#dateTime.getDate();
let toFormat = this[run]({
day: 1 - d
}).toFormat;
this.backToday();
return toFormat;
}
/**
* @description 获取月份最后一天
* @method getLastDay
* @param isCurMonth {Boolean|String} 是否获取当前时间的月末,true:当前时间, false:实例时间
* @param format {String} 时间格式
* @returns {DateTime} 实例
*/
getLastDay(isCurMonth = true, format = this.dateFormat) {
this[init](isCurMonth, format);
let d = this.#dateTime.getDate();
let toFormat = this.addMonths(1).addDays(0 - d).toFormat;
this.backToday();
return toFormat;
}
[run]({year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, week = 0}) {
let date = this.#dateTime;
let y = date.getFullYear() + year;
let M = date.getMonth() + month;
let d = date.getDate() + day;
d += week * WEEKDAY;
let h = date.getHours() + hour;
let m = date.getMinutes() + minute;
let s = date.getSeconds() + second;
this.#dateTime = new Date(y, M, d, h, m, s);
return this;
}
[init](isCurrent, format) {
if (isCurrent) {
this.#dateTime = new Date();
}
if (typeof isCurrent === 'string') {
this.dateFormat = isCurrent;
} else {
this.dateFormat = format;
}
}
}
let date = new DateTime()
date.addDays(2)
console.log(date.addMonths(2).toFormat)
console