Files
2026-07-09 17:30:10 +08:00

259 lines
7.6 KiB
JavaScript

/**
* 日期时间工具类。
*
* 说明:
* - 页面只需要展示日期时,统一使用这里的方法,避免每个页面重复处理格式。
* - 后端常见日期格式为 `YYYY-MM-DD` 或 `YYYY-MM-DD HH:mm:ss`。
* - 纯日期字符串用本地时区解析,避免浏览器按 UTC 解析导致日期偏移。
*/
class DateUtil {
/**
* 转为“5月9日”格式。
*
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
* @returns {string}
*/
static formatDateToMonthDay(dateStr) {
try {
// 第一步:把传入的字符串或 Date 对象统一转成 Date。
const date = DateUtil._parseDate(dateStr);
// 第二步:无效日期直接返回空字符串,页面不显示错误内容。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:取月份和日期,拼接成中文展示格式。
const month = date.getMonth() + 1;
const day = date.getDate();
return `${month}${day}日`;
} catch (error) {
return '';
}
}
/**
* 转为“2026年5月9日”格式。
*
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
* @returns {string}
*/
static formatDateToYearMonthDay(dateStr) {
try {
// 第一步:统一解析日期。
const date = DateUtil._parseDate(dateStr);
// 第二步:无效日期不继续格式化。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:分别取年月日,拼成完整中文日期。
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}${month}${day}日`;
} catch (error) {
return '';
}
}
/**
* 转为“YYYY-MM-DD”格式,适合列表右侧日期展示。
*
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
* @returns {string}
*/
static formatDateToYMD(dateStr) {
try {
// 第一步:统一解析日期。
const date = DateUtil._parseDate(dateStr);
// 第二步:无效日期返回空字符串。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:月份和日期补零,保证列表展示宽度稳定。
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
} catch (error) {
return '';
}
}
/**
* 转为“YYYY-MM-DD HH:mm:ss”格式,适合资金流水、订单时间等完整时间展示。
*
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
* @returns {string}
*/
static formatDateTimeToYMDHMS(dateStr) {
try {
// 第一步:统一解析日期。
const date = DateUtil._parseDate(dateStr);
// 第二步:无效日期返回空字符串,避免页面显示 Invalid Date。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:分别补齐年月日时分秒,保证表格宽度稳定。
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
// 第四步:拼接成后端和页面都常用的完整时间格式。
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
} catch (error) {
return '';
}
}
/**
* 转为“HH:mm:ss”格式,适合日志或轮询状态时间展示。
*
* @param {string|number|Date} dateStr 后端时间、时间戳或 Date 对象
* @returns {string}
*/
/**
* 转为“YYYY-MM-DD HH:mm”格式,适合评论发布时间等不需要精确到秒的场景。
*
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
* @returns {string}
*/
static formatDateTimeToYMDHM(dateStr) {
try {
// 第一步:统一解析传入的时间。
const date = DateUtil._parseDate(dateStr);
// 第二步:无效时间返回空字符串,避免页面显示 Invalid Date。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:只补齐到分钟,不展示秒。
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`;
} catch (error) {
return '';
}
}
static formatTimeToHMS(dateStr) {
try {
// 第一步:时间戳直接转 Date,字符串和 Date 继续走统一解析。
const date = typeof dateStr === 'number' ? new Date(dateStr) : DateUtil._parseDate(dateStr);
// 第二步:无效时间返回空字符串。
if (!DateUtil._isValidDate(date)) {
return '';
}
// 第三步:补齐时分秒,保持展示稳定。
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return `${hour}:${minute}:${second}`;
} catch (error) {
return '';
}
}
/**
* 获取当前时间。
*
* @returns {Date}
*/
static getCurrentDate() {
return new Date();
}
/**
* 判断两个日期是否为同一天。
*
* @param {string|Date} date1 第一个日期
* @param {string|Date} date2 第二个日期
* @returns {boolean}
*/
static isSameDay(date1, date2) {
try {
// 第一步:两个入参都先转成 Date。
const d1 = DateUtil._parseDate(date1);
const d2 = DateUtil._parseDate(date2);
// 第二步:任意一个日期无效,就判定不是同一天。
if (!DateUtil._isValidDate(d1) || !DateUtil._isValidDate(d2)) {
return false;
}
// 第三步:同时比较年、月、日。
return d1.getFullYear() === d2.getFullYear()
&& d1.getMonth() === d2.getMonth()
&& d1.getDate() === d2.getDate();
} catch (error) {
return false;
}
}
/**
* 统一解析日期。
*
* @param {string|Date} dateStr 日期字符串或 Date 对象
* @returns {Date|null}
*/
static _parseDate(dateStr) {
// 第一步:如果已经是 Date 对象,直接返回。
if (dateStr instanceof Date) {
return dateStr;
}
// 第二步:非字符串不尝试解析。
if (typeof dateStr !== 'string') {
return null;
}
// 第三步:去掉首尾空格,兼容接口偶发空白。
const value = dateStr.trim();
if (!value) {
return null;
}
// 第四步:纯日期用斜杠格式解析,避免浏览器按 UTC 导致日期前后偏移。
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
return new Date(value.replace(/-/g, '/'));
}
// 第五步:带时间的字符串交给浏览器 Date 解析。
return new Date(value);
}
/**
* 判断 Date 对象是否有效。
*
* @param {Date|null} date 日期对象
* @returns {boolean}
*/
static _isValidDate(date) {
return date instanceof Date && !Number.isNaN(date.getTime());
}
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = DateUtil;
} else if (typeof window !== 'undefined') {
window.DateUtil = DateUtil;
}