Moment.js 日期处理速查表 - Moment.js 日期格式化与操作大全

这张速查给做日常日期处理的 JS 开发者——把一个时间戳格式化展示、给有效期加几天、比较两个日期、或显示“3 天前”这类相对时间。内容涵盖从字符串、时间戳和对象字面量创建日期(注意 month 从 0 开始)、格式化令牌、add/subtract 与 startOf/endOf 的临界对齐、比较助手、相对时间,以及借助 moment-timezone 的时区处理。需要提醒的是 Moment 已进入维护模式,新项目建议优先用原生 Date 或更轻量的 Day.js。读完你应能完成日期的解析、格式化、移位与比较,并输出友好的相对时间文案。

编程语言·共 39 条命令·最后更新 2026-07-21
moment日期时间格式化

典型使用场景

面向正在维护既有代码库、里面已经大量使用 moment 的前端开发者:订单时间展示、相对时间(「3 天前」)、时长计算、跨时区排期。这里必须先说清楚一件事——moment 官方已进入维护模式(maintenance mode),不再新增功能,因此新项目应优先选 dayjs、date-fns 或浏览器原生 Temporal。本表保留的是存量系统里最常被查询的一批 API:解析、格式化、加减、比较、区间判断、diff、relative time、时区与 duration,用它来读懂旧代码、在迁移时对照语义,而不是鼓励新引入。

创建日期 5

moment()
创建当前时刻的 moment 对象
moment("2024-01-15")
从 ISO 日期字符串解析,得到对应时刻
moment("2024-01-15", "YYYY-MM-DD")
显式指定格式解析,非标准字符串更稳
moment(Date.now())
从毫秒时间戳创建日期对象
moment({ year: 2024, month: 0, day: 15 })
从对象字面量创建,注意 month 从 0 开始

格式化 5

moment().format("YYYY-MM-DD")
2024-01-15
moment().format("HH:mm:ss")
14:30:00
moment().format("dddd, MMMM Do YYYY")
Monday, January 15th 2024
moment().format("LLL")
本地化长格式
moment().toISOString()
ISO 8601 格式

操作日期 5

moment().add(7, "days")
加 7 天
moment().subtract(1, "month")
减 1 个月
moment().startOf("day")
设置为当天 00:00:00
moment().endOf("month")
设置为月末 23:59:59
moment().year(2025).month(0)
设置年月

查询与比较 8

moment().isBefore(other)
是否在之前
moment().isAfter(other)
是否在之后
moment().isSame(other, "day")
是否同一天
moment().isBetween(start, end)
是否在区间内
moment().isSameOrBefore(other)
相同或之前
moment().isSameOrAfter(other)
相同或之后
moment().diff(other, "days")
计算差值(指定单位)
moment().isValid()
是否有效日期

相对时间 6

moment().fromNow()
3 天前
moment().fromNow(true)
3 天(不含"前")
moment().toNow()
3 天后
moment().calendar()
今天 14:30 / 昨天 09:00
moment().from(other)
相对另一时刻的偏移
moment().to(other)
到另一时刻的偏移

时区与本地化 5

moment().utc()
转为 UTC 时间
moment().local()
转为本地时间
moment.locale("zh-cn")
设置中文
moment.tz("2024-01-15", "America/New_York")
指定时区(需 moment-timezone)
moment().utcOffset(480)
设置 UTC 偏移(分钟)

Duration 时长 5

moment.duration(100, "minutes")
从分钟创建时长
moment.duration({ hours: 2, minutes: 30 })
从对象创建时长
duration.asHours()
转换为总小时数
duration.humanize()
人性化显示(如"2 小时")
duration.add(1, "hour")
时长加运算

参数矩阵

参数作用示例
moment(input, format)按显式格式解析非标准字符串,比依赖自动推断更稳moment("2024-01-15", "YYYY-MM-DD")
format(pattern)按模式输出字符串,如 YYYY-MM-DD、HH:mm:ssmoment().format("YYYY-MM-DD")
add(n, unit) / subtract(n, unit)加减时间;单位可写 "days"、"month"、"hours"moment().add(7, "days")
startOf(unit) / endOf(unit)把值对齐到单位边界,如当天 00:00:00、月末 23:59:59moment().endOf("month")
isSame(other, unit?)按指定粒度比较;不传 unit 时精确到毫秒moment().isSame(other, "day")
isBetween(start, end)判断是否落在区间内,常用于时间线筛选moment().isBetween(start, end)
diff(other, unit)计算两个时刻的差值并以指定单位返回moment().diff(other, "days")
isValid()校验解析结果是否有效,解析失败时先查这一项moment().isValid()
fromNow(true) / calendar()相对当前时间的口语化输出moment().fromNow(true)
moment.duration(100, "minutes").asHours()创建时长对象并换算成总单位数duration.asHours()

易错点与避坑指南

现象新项目里仍然在装 moment,安装体积告警一直出现在构建输出中。

原因moment 已进入维护模式(maintenance mode),不再新增功能,官方已建议新项目改用轻量替代。

处置新代码改用 dayjs(体积小、API 高度相似)、date-fns(按函数引入、可摇树)或原生 Temporal;存量代码保留 moment 并按模块逐步替换,不要新引入。

现象moment({ year: 2024, month: 0, day: 15 }) 得到的是 2023-12,月份少算一个月。

原因moment 的对象字面量构造沿用 JS Date 的 0 基月份,month: 0 是一月。

处置确认 month 是 0 基(0 = 一月);或改用字符串解析 moment("2024-01-15", "YYYY-MM-DD") 避免歧义。

现象moment("2024-13-45") 这类非法输入参与计算后,页面显示 Invalid date。

原因moment 会尽力解析并产生无效对象,无效对象参与运算会静默返回无效结果。

处置解析后立即用 isValid() 校验,非法输入走降级分支或返回 null,不要继续参与 add / diff / format。

现象两个时间戳看起来同一天,isSame() 却返回 false。

原因isSame 不传单位时精确到毫秒,时分秒不同即判定为不等。

处置显式指定粒度:moment().isSame(other, "day"),需要模糊边界时用 isSameOrBefore / isSameOrAfter。

现象服务端存 UTC,页面展示的时间和预期差几个小时。

原因混用了本地时区与 UTC,moment() 取的是本地时区,而数据往往是 UTC。

处置统一策略:入库用 moment().utc() 或 moment().toISOString(),展示前按需 moment().local();跨时区业务用 moment.tz("2024-01-15", "America/New_York")(需额外安装 moment-timezone)。

现象diff 算出的天数比预期少一天,月末场景尤其明显。

原因diff 按完整单位数向下取整,跨月时不按日历天计算。

处置明确业务口径:算日历跨度用 startOf("day") 对齐后再 diff,或用 isBetween(start, end) 配合 startOf/endOf 判断区间归属。

排障路径

  1. 1确认解析是否成功,再看格式化结果

    moment().isValid()

    任何非标准输入先过 isValid();为 false 时直接走降级,不要继续 format。

  2. 2解析非标准字符串时显式给格式

    moment("2024-01-15", "YYYY-MM-DD")

    依赖自动推断在 2024/01/15 与 15/01/2024 这类输入上会得到不同日期,显式格式最稳。

  3. 3判断是否同一天而不是同一毫秒

    moment().isSame(other, "day")

    isSame / isBetween 都要带 unit 才能符合「按天」的业务口径。

  4. 4统一时区口径

    moment().utc()

    入库统一 UTC,展示前 moment().local();跨时区排期需要 moment-timezone 的 moment.tz()。

  5. 5先看迁移前的对照口径

    moment().diff(other, "days")

    把现有 moment 逻辑用这一组 API 写清楚语义,再逐条替换为 dayjs / date-fns / Temporal,行为差异才可控。

命令示例

解析、格式化与差值三件套

const d = moment("2024-01-15", "YYYY-MM-DD"); const s = d.format("YYYY-MM-DD HH:mm"); const days = moment().diff(d, "days");

非 ISO 字符串一定要带格式串:moment("15/01/2024") 在不同区域设置下解析结果完全不同,带上 "DD/MM/YYYY" 才是确定的。diff 差值按 moment() 当前时间计算,需要固定基准就把两个值都显式给出。

输出

2024-01-15 00:00
2024-01-15 00:00

边界与相对显示:startOf + calendar

const begin = moment().startOf("day"); // 今天 00:00:00.000 const end = moment().endOf("month"); // 本月最后一天 23:59:59.999 const label = moment().calendar();

startOf("day") / endOf("month") 是做「今天」「本月」范围查询的标准写法,比自己拼 00:00:00 少一堆时区与毫秒边界问题。endOf 会含 .999 毫秒,若要和数据库的整日上限比较,通常再配 startOf("day") 收口。

输出

今天 14:30 / 昨天 09:00

安全判断用 isSameOrBefore,而不是裸比较

moment("2024-01-15").isSameOrBefore("2024-02-01"); moment("2024-01-15").isBetween("2024-01-01", "2024-02-01", "day", "[]");

isSameOrBefore 把相等情形并入判断,避免边界日期上 isBefore 返回 false 造成的漏判。第四个参数 "[ ]" 表示闭区间;默认是开区间,同一天的首尾都会被排除——这是日期筛选最常见的 off-by-one。

时区:统一用 UTC 存储,展示时再本地化

const iso = moment.utc().toISOString(); const shanghai = moment(iso).tz("Asia/Shanghai").format("YYYY-MM-DD HH:mm"); const offsetMin = moment().utcOffset(480);

moment() 默认取本地时区,直接 toISOString() 前不做 utc() 会带上本地偏移。稳妥做法是入口处 moment.utc() 归一,存 ISO 字符串,出库时再 .tz(...) 转到目标时区展示。utcOffset(480) 是 UTC+8 的分钟数写法。

输出

2024-01-15T06:00:00.000Z

时长计算与国际化

const d = moment.duration({ hours: 2, minutes: 30 }); const hours = d.asHours(); // 2.5 moment.locale("zh-cn"); const text = d.humanize(); // 3 小时

moment.duration 表示「一段时间」而非某个时间点,和 moment 对象混用容易在 diff 与 add 上出错。humanize() 依赖全局 locale,中英混排的界面里最好按文案需求分别设置,或改用 Intl 生态的库。

常见坑与注意事项

  • Moment.js 处于维护模式(maintenance mode),官方已不再新增功能并建议逐步迁移。新项目请选 dayjs、date-fns 或原生 Temporal;继续在存量项目里加功能,等于给自己叠加长期升级成本。
  • 对象字面量构造时 month 从 0 开始:moment({ year: 2024, month: 0, day: 15 }) 是一月,不是十二月。1 月写 month: 1 会静默变成 2 月,无任何报错。
  • moment() 创建的对象是可变的,set/add/subtract/format 都直接改原对象并返回它。把它存进状态或缓存后忘记 .clone(),别处的日期会被跟着改掉,排查时极难定位。
  • 直接 moment("15/01/2024") 这类非 ISO 字符串,不同区域设置解析结果不同,日期可能整体偏移一天。必须显式传格式串,或先换成 ISO 8601。
  • 服务端用 moment().format() 生成的时间串带着服务器本地时区,客户端再解析就是另一回事。接口层一律用 toISOString()(UTC)传时间,展示层再本地化。
  • Locale 数据不全时 moment.locale("zh-cn") 会静默回退到英文,.fromNow() 就输出 "3 days ago" 而非中文,且没有任何警告。上线前用 .locale() 回读确认语言真的生效了。

提示

  • Moment.js 已停止新功能开发,新项目推荐 dayjs(API 兼容,体积更小)。
  • 月份从 0 开始:0=一月,11=十二月。
  • format 令牌:YYYY=年,MM=月,DD=日,HH=时,mm=分,ss=秒。
  • 操作日期会返回新 moment 对象,原对象不可变。
  • fromNow/toNow 自动选择单位(秒、分钟、小时、天、月、年)。
  • diff 默认返回毫秒,传入第二参数可指定单位(days/months/years)。
  • duration 用于度量时间长度而非某个时间点,humanize 可输出友好文本。

常见问题

什么时候必须给 moment() 显式传格式字符串?

当输入不是 ISO 8601 形状时。moment("2024-01-15") 走的是内置的宽松解析,多数标准格式都能认出来,但像 2024/01/15 15:30、15/01/2024 这类分隔符与顺序都不确定的字符串,不同浏览器与不同 moment 版本可能给出不同结果。碰到这种情况就写 moment("2024-01-15", "YYYY-MM-DD"),第二个参数把期望格式说死,解析结果稳定可预期。经验法则是:接口约定的标准格式直接解析,用户输入、一切非 ISO 字符串一律带上格式参数。

界面上同时要绝对时间和「3 天前」,两个方法怎么配合?

按信息密度分层用。moment().calendar() 给的是日历化表述,会把今天和昨天折叠成「今天 14:30」「昨天 09:00」这样的短文案,非常适合列表里扫一眼就用;日期更远的则自动回落到完整日期格式。moment().fromNow() 给的是相对偏移,不管多远都保持「3 天前」这种说法,适合详情页或通知流里强调时间过去了多久。moment().fromNow(true) 则去掉了「前」「后」这层方向词,只剩「3 天」,需要你自己拼接上下文文案时用它。三者按展示位的宽窄搭配即可。

moment.duration 的 asHours() 返回的是小数还是整数?

返回的是小数,也就是总小时数。moment.duration({ hours: 2, minutes: 30 }) 构造出的时长,asHours() 会给出 2.5 而不是 2——它表示把整个 duration 归一到该单位后的总量,而不是「整小时的部分」。moment.duration(100, "minutes") 的 asHours() 同理是 1.667 左右。需要「完整多少小时」这种向下取整的语义时,得自己在结果上取整,而不是指望 asHours 自动截断。duration.add(1, "hour") 是在时长上做加法,加完同样可以用 asHours 一次性读出归一后的总量。

duration 和 moment 对象能互相转换吗?

可以,两者都是 moment 家族的类型,可以在同一个表达式里配合使用。最常见的用法是取「距离某个时刻还有多久」:把两个具体时刻相减得到的 diff 结果本身就是 duration,可以直接 asHours() 换算成小时数,或者 humanize() 输出「2 小时」这样的可读文本。反过来,要把一段时间加到某个时刻上,就用 moment().add(7, "days") 这类操作作用于 moment 对象;duration.add(1, "hour") 则只在时长之间做加减。记住判断标准:描述「一个时间点」用 moment,描述「一段长度」用 duration。

moment().format("LLL") 和手写 YYYY-MM-DD HH:mm 该怎么选?

看要的是可排序性还是可读性。手写令牌串(本表有 YYYY-MM-DD、HH:mm:ss、dddd, MMMM Do YYYY 等)输出是固定的,换语言不会变,适合做文件名、日志行、排序键或者需要稳定对照的地方。format("LLL") 是本地化长格式,会跟着 moment.locale("zh-cn") 的设置走,同一份代码在不同语言环境下给出各自的日期长写法,适合面向用户的界面。典型分工是:搜索和排序用 YYYY-MM-DD HH:mm,展示给人看的用 LLL。

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。

由 巧匠 维护

公开更新于 2026年7月21日,内容持续校对官方文档。

联系我们

命令或描述有误?提交反馈、商务合作或产品建议都可发送邮件给我们。

联系我们