快速开始
安装
npm install @iefe/dateformat
# 或
yarn add @iefe/dateformat
# 或
pnpm add @iefe/dateformat引入
ESM:
import { format, formatDate, fromNow, getDays, datefmt } from '@iefe/dateformat'CommonJS:
const { format, formatDate, fromNow, getDays, datefmt } = require('@iefe/dateformat')浏览器(v2 无 UMD 产物,请通过 ESM CDN 或打包工具):
<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 / isValid | iOS 兼容解析 / 合法性判断 |
| 相对时间与差值 | fromNow / diff | 中文相对时间 / 两日期差值 |
| 日期比较 | isToday / isSameDay / isBefore / isAfter | 日粒度与时刻粒度判断 |
| 年月信息 | getDays / getYearofDays / getYearLastDays / isLeapYear | 天数查询 / 闰年判断 |
格式化
format:三种调用形式
// 假设当前时间 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:
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' 这类溢出输入直接判非法:
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')。
相对时间与差值
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' 为日历差值,只统计满整月 / 整周年。
日期比较
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 等)仍保持库级回退约定。
年月信息
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. 命名空间门面 — 只导入一个标识符
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') // 29datefmt 经 Object.freeze 冻结,运行时改写或挂载任何属性都会抛 TypeError。 上文五组功能的所有函数都收拢在 datefmt 上,与具名导出同源同行为。
2. 不可变建造者 — 链式配置,无共享可变状态
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
<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
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
// 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)或打包工具使用。