TypeScript 封装 Date 格式化函数:简洁又高效

引言

在项目开发中,日期时间格式化展示是常见的功能需求,但由于不同场景对格式的要求各异,团队中每个开发者都独立编写代码来满足各自需求,这导致项目中出现大量重复且冗余的代码。这种现象不仅降低了开发效率,也违背了代码规范中关于 避免重复代码(DRY-Don't Repeat Yourself)保持一致性 的原则。

避免过度封装 :虽然 DRY 原则 强调避免重复代码,但过度封装可能会导致代码复杂难懂。在封装时需要权衡代码的通用性和灵活性。

基于以上思考,封装一个通用的日期格式化函数,不仅能减少重复代码,还能显著提升代码的可复用性和可维护性。通过学习和整合项目组中同学们的优秀实现,我记录下自己的学习过程,并尝试封装出一个易于使用的日期格式化工具函数。

代码实现

  1. MDN的Date文档
  2. 通过指定占位符定义 format 格式,使用 replace 方法将占位符替换为具体的日期时间值

定义 占位符 规则

输入 示例 描述
YY 25 两位数的年份
YYYY 2025 四位数的年份
M 1-12 月份/从 1 开始
MM 01-12 月份/两位数
MMM Jan-Dec 简写英文的月份名称
MMMM January-December 完整英文的月份名称
MMMMM 一月-十二月 大写汉字的月份名称
D 1-31 月份里的一天
DD 01-31 月份里的一天/两位数
W 0 0-6,分别表示星期日-星期六
WW 周日 周x
WWW 星期日 星期x
Q 1 1-4
QQ 一季度 一季度--四季度
H 0-23 小时/24 小时制
HH 00-23 小时/24 小时制/两位数
h 1-12 小时/12 小时制
hh 01-12 小时/12 小时制/两位数
A AM / PM 上午/下午 大写
a am / pm 上午/下午 小写
m 0-59 分钟
mm 00-59 分钟/两位数
s 0-59
ss 00-59 秒/两位数
S 0-9 毫秒/一位数
SS 00-99 毫秒/两位数
SSS 000-999 毫秒/三位数

源码

ts 复制代码
function dateFormatter(format: string = 'YYYY-MM-DD HH:mm:ss', date: Date | string | number  = new Date()): string {
  let parsedDate: Date;
  if (date instanceof Date) {
    parsedDate = date;
  } else if (typeof date === 'string' || typeof date === 'number') {
    parsedDate = new Date(date);
    if (isNaN(parsedDate.getTime())) {
      parsedDate = new Date();
    }
  } else {
    parsedDate = new Date()
  }
  // 获取日期的基本信息
  const year = parsedDate.getFullYear();
  const month = parsedDate.getMonth(); // 0 表示 1 月
  const day = parsedDate.getDate();
  const weekday = parsedDate.getDay(); // 0 表示星期日
  const hour = parsedDate.getHours();
  const minute = parsedDate.getMinutes();
  const second = parsedDate.getSeconds();
  const millisecond = parsedDate.getMilliseconds();


  // 星期和月份的常量定义
  const FULL_WEEKDAYS = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
  const SHORT_WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
  const MONTHS_CHINESE = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
  const MONTHS_SHORT_EN = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  const MONTHS_LONG_EN = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
  const QUARTERS = ['一季度', '二季度', '三季度', '四季度'];

  // 获取季度的函数
  const getQuarter = (month: number) => Math.ceil((month + 1) / 3);

  // 映射表:格式化占位符到实际值的映射
  const PLACEHOLDER_MAPPING = {
    // 年份
    YYYY: year.toString(),
    YY: year.toString().slice(-2),

    // 月份
    M: (month + 1).toString(),
    MM: (month + 1).toString().padStart(2, '0'),
    MMM: MONTHS_SHORT_EN[month],
    MMMM: MONTHS_LONG_EN[month],
    MMMMM: MONTHS_CHINESE[month],

    // 日期
    D: day.toString(),
    DD: day.toString().padStart(2, '0'),

    // 星期
    W: weekday.toString(),
    WW: SHORT_WEEKDAYS[weekday],
    WWW: FULL_WEEKDAYS[weekday],

    // 季度
    Q: getQuarter(month).toString(),
    QQ: QUARTERS[getQuarter(month) - 1],

    // 时间(24小时制)
    H: hour.toString(),
    HH: hour.toString().padStart(2, '0'),

    // 时间(12小时制)
    h: (hour % 12 || 12).toString(),
    hh: (hour % 12 || 12).toString().padStart(2, '0'),
    A: hour >= 12 ? 'PM' : 'AM',
    a: hour >= 12 ? 'pm' : 'am',

    // 分钟和秒
    m: minute.toString(),
    mm: minute.toString().padStart(2, '0'),
    s: second.toString(),
    ss: second.toString().padStart(2, '0'),

    // 毫秒
    S: millisecond.toString(),
    SS: millisecond.toString().padStart(2, '0'),
    SSS: millisecond.toString().padStart(3, '0')
  };

  // 替换逻辑:根据格式字符串中的占位符替换为实际值
  return format.replace(/Y+|M+|D+|W+|Q+|H+|h+|A|a|m+|s+|S+/g, (match) => {
    return PLACEHOLDER_MAPPING[match] || '';
  });
}

感谢阅读,敬请斧正!

相关推荐
W起名有点难10 分钟前
前端学习——CSS
前端·css·学习
关山月33 分钟前
18 个最佳 React UI 组件库
前端
belldeep1 小时前
p5.js:sound(音乐)可视化,动画显示音频高低变化
javascript·sound·audio·p5.js·p5.sound
挣扎与觉醒中的技术人1 小时前
【技术干货】三大常见网络攻击类型详解:DDoS/XSS/中间人攻击,原理、危害及防御方案
前端·网络·ddos·xss
记得早睡~1 小时前
leetcode654-最大二叉树
javascript·数据结构·算法·leetcode
zeijiershuai1 小时前
Vue框架
前端·javascript·vue.js
vvilkim1 小时前
使用 JavaScript 和 HTML5 实现强大的表单验证
开发语言·javascript·html5
写完这行代码打球去1 小时前
没有与此调用匹配的重载
前端·javascript·vue.js
华科云商xiao徐1 小时前
使用CPR库编写的爬虫程序
前端
狂炫一碗大米饭1 小时前
Event Loop事件循环机制,那是什么事件?又是怎么循环呢?
前端·javascript·面试