Skip to content

快速开始 ​

安装 ​

bash
npm install @iefe/dateformat
# 或
yarn add @iefe/dateformat
# 或
pnpm add @iefe/dateformat

引入 ​

ESM:

js
import { format, formatDate, fromNow, getDays, datefmt } from '@iefe/dateformat'

CommonJS:

js
const { format, formatDate, fromNow, getDays, datefmt } = require('@iefe/dateformat')

浏览器(v2 无 UMD 产物,请通过 ESM CDN 或打包工具):

html
<script type="module">
  import { format, formatDate, fromNow, getDays } from 'https://unpkg.com/@iefe/dateformat/dist/index.js'

  console.log(format())                   // 当前时间 'YYYY-MM-DD hh:ii:ss'
  console.log(formatDate('2024-02-29'))   // '2024-02-29 00:00:00'
  console.log(fromNow('2023-03-10'))      // 相对时间描述
  console.log(getDays('2023-02'))         // 28
</script>

功能分类导览 ​

v2 的 API 按功能分为五组,全部纯函数、非法入参不抛错:

分类API一句话说明
格式化format / formatDate旧版约定格式化 / 格式化任意日期
解析与校验parseDate / isValidiOS 兼容解析 / 合法性判断
相对时间与差值fromNow / diff中文相对时间 / 两日期差值
日期比较isToday / isSameDay / isBefore / isAfter日粒度与时刻粒度判断
年月信息getDays / getYearofDays / getYearLastDays / isLeapYear天数查询 / 闰年判断

格式化 ​

format:三种调用形式 ​

js
// 假设当前时间 2023-03-10 15:00:00(星期五)
format()                          // '2023-03-10 15:00:00'(默认模板)
format('YYYY-MM-DD')              // '2023-03-10'(单参数视为模板)
format('-7', 'YYYY-MM-DD')        // '2023-03-03'(偏移 + 模板)
format(' +3 ', 'MM-DD')           // '03-13'(偏移字符串允许空格)
format('YYYY-MM-01')              // '2023-03-01'(模板中的固定字符原样保留)

非法输入不抛错:无法识别的参数按模板处理,模板中的非 Token 字符原样保留。

formatDate:格式化任意日期 ​

format 的基准恒为"今天",想格式化一个用户给定的日期(如后端返回值、生日)用 formatDate:

js
import { formatDate } from '@iefe/dateformat'

formatDate('2024-02-29')                          // '2024-02-29 00:00:00'(默认模板)
formatDate('2024/02/15 10:30:00', 'MM-DD hh:ii') // '02-15 10:30'
formatDate(new Date(), 'Y年M月D日')               // 中文大写同样可用
formatDate('abc', 'YYYY-MM-DD')                   // 非法入参回退当前时间(不抛错)

解析与校验 ​

parseDate 不依赖 new Date(string) 原生解析,而是按组件构造 Date, 天然规避 iOS Safari 上 new Date('2024-01-01 12:00:00') 返回 Invalid Date 的问题; 并带回写校验,'2023-02-31' 这类溢出输入直接判非法:

js
import { parseDate, isValid } from '@iefe/dateformat'

parseDate('2024-02-15')           // 2024 年 2 月 15 日 0 点的 Date
parseDate('2024-01-01 12:00:00')  // iOS Safari 下同样可用
parseDate('2023-02-31')           // null(回写校验:2 月没有 31 日)
parseDate('abc')                  // null(非法输入返回 null,不抛错)

isValid('2024-02-29')             // true
isValid('2023-02-29')             // false(平年 2 月无 29 日)
isValid(undefined)                // false

支持 'YYYY-MM'、'YYYY-MM-DD'、'YYYY/MM/DD' 及其带时间的形式('2024-01-01 12:00'、'2024-01-01T12:00:00')。

相对时间与差值 ​

js
import { fromNow, diff } from '@iefe/dateformat'

// 假设当前时间 2023-03-10 15:00:00
fromNow(new Date())          // '刚刚'
fromNow('2023-03-10 14:30')  // '30 分钟前'
fromNow('2023-03-11 14:00')  // '23 小时后'
fromNow('2022-04-10 15:00')  // '11 个月前'
fromNow('abc')               // ''(非法输入返回空字符串,不误报"刚刚")

diff('2024-03-01', '2024-01-01')                     // 60(默认单位 day)
diff('2024-01-01', '2024-03-01')                     // -60(负数表示 a 早于 b)
diff('2024-03-01 12:00', '2024-03-01 10:30', 'hour') // 1(1.5 小时向零取整)
diff('2024-03-01', '2024-01-01', 'month')            // 2(日历差值,只统计满整月)

diff 支持 7 种单位(DiffUnit):'ms' / 'second' / 'minute' / 'hour' / 'day' 为精确时间差换算后向零取整;'month' / 'year' 为日历差值,只统计满整月 / 整周年。

日期比较 ​

js
import { isToday, isSameDay, isBefore, isAfter } from '@iefe/dateformat'

// 假设今天是 2023-03-10
isToday('2023-03-10 23:59')                       // true(日粒度,忽略时分秒)
isSameDay('2023-03-10 08:00', '2023-03-10 23:59') // true
isBefore('2023-03-10 08:00', '2023-03-10 09:00')  // true(时刻粒度,精确到毫秒)
isAfter('2023-03-11', '2023-03-10')               // true

判定类函数对非法或缺失输入一律返回 false(不回退当前时间,避免误报); 值类函数(format / getDays 等)仍保持库级回退约定。

年月信息 ​

js
import { getYearLastDays, getYearofDays, getDays, isLeapYear } from '@iefe/dateformat'

// 假设今天是 2023-03-10(平年)
getDays()                            // 31(本月)
getDays('2023-02')                   // 28
getDays('2024-02')                   // 29(闰年)
getYearofDays()                      // 365
getYearofDays(2024)                  // 366
getYearLastDays()                    // 296(今年剩余,不含今天)
getYearofDays() - getYearLastDays()  // 69(今年已过去)
isLeapYear(2024)                     // true
isLeapYear(1900)                     // false(被 100 整除但不被 400 整除)

四个方法无参时一律以"今天"为基准;非法入参回退默认值而非抛错。

命名空间与 Builder(避免变量污染) ​

format、getDays 是前端最高频的命名之一,按名导入容易与业务代码或 date-fns 等库的同名导出冲突。v2 提供两种零污染用法:

1. 命名空间门面 — 只导入一个标识符

js
import { datefmt } from '@iefe/dateformat'

datefmt.format('-7', 'YYYY-MM-DD')    // '2023-03-03'
datefmt.formatDate('2024-02-29')      // '2024-02-29 00:00:00'
datefmt.fromNow('2023-03-10 14:30')   // '30 分钟前'
datefmt.getDays('2024-02')            // 29

datefmt 经 Object.freeze 冻结,运行时改写或挂载任何属性都会抛 TypeError。 上文五组功能的所有函数都收拢在 datefmt 上,与具名导出同源同行为。

2. 不可变建造者 — 链式配置,无共享可变状态

js
datefmt.create('YYYY-MM-DD hh:ii:ss') // 工厂方法:以模板创建建造者
  .offset(-7)                         // 偏移 -7 天(可叠加)
  .render()                           // '2023-03-03 15:00:00'

// 每一步都返回新实例,原实例与兄弟实例互不影响:
const today = datefmt.create('YYYY-MM-DD')
const lastWeek = today.offset(-7) // 新实例 → '2023-03-03'
const nextWeek = today.offset(7)  // 新实例 → '2023-03-17'
today.render()                    // '2023-03-10'(原实例未被修改)
  • pattern / offset / base 均返回新实例;offset 支持叠加(.offset(-7).offset('+3') 净偏移 -4)
  • 非法参数(如 .offset('abc'))忽略不抛错
  • render() 延迟求值(调用时才读系统时间),toString() 等价,可直接用于模板字符串 `${builder}`

在框架中使用 ​

Vue 3 ​

vue
<script setup lang="ts">
import { ref } from 'vue'
import { formatDate, fromNow, getDays, isToday } from '@iefe/dateformat'

const today = ref(formatDate(new Date(), 'YYYY年MM月DD日 a'))
const week = ref(formatDate(new Date(), '今天EE'))
const monthDays = getDays()
const createdAt = '2024-01-01 09:30'
</script>

<template>
  <p>{{ today }}({{ week }}),本月共 {{ monthDays }} 天</p>
  <p>上周同日:{{ formatDate('2023-03-03', 'YYYY-MM-DD') }}</p>
  <p v-if="isToday(createdAt)">今天创建</p>
  <p v-else>创建于 {{ fromNow(createdAt) }}</p>
</template>

React 18 ​

tsx
import { useMemo } from 'react'
import { formatDate, fromNow, getDays, getYearLastDays, isToday } from '@iefe/dateformat'

export function Today({ createdAt }: { createdAt: string }) {
  const text = useMemo(() => formatDate(new Date(), 'YYYY年MM月DD日 a'), [])
  return (
    <p>
      {text},本月共 {getDays()} 天,今年还剩 {getYearLastDays()} 天;
      该记录创建于 {isToday(createdAt) ? '今天' : fromNow(createdAt)}
    </p>
  )
}

可选封装:useFormattedDate ​

ts
// React
export function useFormattedDate(date?: string | Date, pattern?: string): string {
  return useMemo(() => formatDate(date, pattern), [date, pattern])
}

// Vue
export function useFormattedDate(date: Ref<string | Date | undefined>, pattern?: string) {
  return computed(() => formatDate(date.value, pattern))
}

已知限制 ​

  • hh 是 24 小时制、ii 是分钟 — 与 dayjs/moment 的 HH/mm 语义不同,迁移时注意。
  • 模板中的独立字母 a、i、s、H、Q、x、X、Y、M、D 都是 Token,会被替换(如模板 'abc' 中的 a 会变成时段)。固定文案请用 [方括号] 转义(见格式化 Token)。
  • ww 为 ISO 8601 周数:周一为一周开始、含当年首个周四的周为第 1 周。年末/年初的周序号可能属于相邻年份(2023-01-01 → 52),与同一模板中 YYYY 的年份可能相差 1。
  • 仅使用运行环境本地时区,不做时区转换;x / X 时间戳不受时区影响。
  • getDays 只取年月、忽略日部分('2024-02-31' 也返回 29);月份越界的输入回退本月。与之不同,parseDate / isValid / diff / fromNow / 比较函数对 '2023-02-31' 这类溢出日期判非法(回写校验)。
  • 日期字符串解析不走 new Date(string),而是取出年月日时分秒后按组件构造 Date,天然规避 iOS Safari 上 '2024-01-01 12:00:00' 解析失败的问题。
  • 偏移字符串仅平移日期、保留当天时分秒。
  • 自迁移到 tsup 后不再提供 UMD 产物;浏览器请通过 ESM(<script type="module"> + CDN)或打包工具使用。

本站由 VitePress 静态生成,各版本文档相互独立。