前端时间函数使用指南与常见陷阱解析

东方红梅 移动 阅读 599
赞 9 收藏
二维码
手机扫码查看
反馈

时间函数这事儿,我踩过太多坑了

做移动端开发,时间处理几乎是绕不开的。用户要显示“3分钟前”,后台给的是 ISO 8601 字符串;本地要缓存数据,得用时间戳判断是否过期;动画要平滑,还得靠 requestAnimationFrame 配合时间差……但真正让我头疼的,不是业务逻辑,而是到底该用哪个时间函数方案

前端时间函数使用指南与常见陷阱解析

原生 Date?moment.js?dayjs?还是自己手写?我折腾过好几个项目,从电商到社交,从 H5 到 React Native,踩过坑、翻过车,今天就来聊聊这几个主流方案的实际体验——不讲理论,只说实战。

谁更灵活?谁更省事?

先说结论:现在我基本只用 dayjs,除非项目特别老或者性能极其敏感。别急着喷,听我慢慢道来。

最早那会儿,大家都用原生 Date。代码写起来像这样:

const now = new Date();
const past = new Date('2024-01-01T10:00:00Z');
const diff = now - past; // 毫秒差

看起来挺干净,但一到格式化就崩溃了。想输出“YYYY-MM-DD HH:mm”?得自己拼字符串,还要处理时区、补零、月份从0开始这些反人类设计。更别说解析各种格式的时间字符串了,稍有不慎就返回 Invalid Date。我曾经在一个 H5 活动页里,因为用户手机时区设置异常,导致整个倒计时错乱,线上事故,半夜被叫醒修 bug。

后来有了 moment.js,简直是救星。链式调用、格式化一行搞定、国际化支持好,代码清爽多了:

import moment from 'moment';
const formatted = moment('2024-01-01T10:00:00Z').format('YYYY-MM-DD HH:mm');

但问题也来了:**体积太大**。gzip 后还有 70KB+,对移动端首屏加载是致命伤。我有个项目引入后,Lighthouse 性能分直接掉 15 分。而且它不可变(immutable)的设计在某些场景反而麻烦,比如频繁修改时间对象时,得不断 clone,内存开销不小。

于是 dayjs 出现了。它 API 和 moment 几乎一致,但体积只有 2KB(gzip 后)。我试了下,迁移成本极低,几乎改个 import 就行:

import dayjs from 'dayjs';
const formatted = dayjs('2024-01-01T10:00:00Z').format('YYYY-MM-DD HH:mm');

插件机制也够用,比如相对时间(“3分钟前”):

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
console.log(dayjs().subtract(3, 'minute').fromNow()); // "3分钟前"

这里注意我踩过好几次坑:**relativeTime 插件默认是英文的**!中文得自己配 locale,或者用社区版。我现在的做法是封装一个工具函数,统一处理:

import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.locale('zh-cn');
dayjs.extend(relativeTime);

export const formatRelativeTime = (date) => {
  return dayjs(date).fromNow();
};

性能对比:差距比我想象的大

有人会说:“不就几 KB 吗?现在手机都快,无所谓。”但实际跑起来,差别真不小。我在一个列表页做了测试:渲染 100 条带时间的动态,每条都要格式化和计算相对时间。

  • 原生 Date 手写格式化:最快,但代码丑且易错
  • moment.js:平均耗时 120ms,页面明显卡顿
  • dayjs:平均耗时 35ms,流畅

更关键的是内存占用。moment 的每个实例都携带大量 locale 数据,而 dayjs 默认只加载需要的部分。在低端安卓机上,moment 容易触发 GC,导致掉帧。我亲眼见过一个瀑布流页面,用 moment 时滚动卡成 PPT,换成 dayjs 后丝滑如德芙。

当然,如果你只是偶尔格式化一两个时间,比如页面顶部的“最后更新时间”,那原生 Date 也够用。但一旦涉及列表、实时更新、动画同步,我还是推荐用成熟库。

我的选型逻辑

我现在选型就看三点:

  1. 项目是否新:新项目无脑 dayjs
  2. 是否需要复杂时区处理:如果涉及全球用户,可能得上 Luxon 或 date-fns-tz,但 90% 的国内项目不需要
  3. 团队是否熟悉:如果老项目已经在用 moment,且没性能问题,那就别折腾

特别提醒:**千万别在移动端用 moment 作为新项目的基础库**。我见过实习生直接 npm install moment,结果上线后被 QA 报“页面加载慢”,查了半天才发现是它。

另外,date-fns 也是个选项,函数式风格,tree-shakable 做得更好。但它的 API 不如 dayjs 直观,比如格式化要传 format 字符串,而 dayjs 是方法链。我试过一次,写起来总觉得别扭,最后还是切回 dayjs 了。

至于原生 Date?除非是超轻量级的小程序或嵌入式 H5,否则我不碰。那些“不用第三方库”的洁癖,在时间处理这种细节密集的场景下,只会让你加班更多。

核心代码就这几行

最后贴个我项目里常用的封装,亲测有效:

// utils/time.js
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import relativeTime from 'dayjs/plugin/relativeTime';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

dayjs.locale('zh-cn');
dayjs.extend(relativeTime);
dayjs.extend(utc);
dayjs.extend(timezone);

// 格式化为标准时间字符串
export const formatStandard = (date) => {
  return dayjs(date).format('YYYY-MM-DD HH:mm');
};

// 相对时间(3分钟前)
export const formatRelative = (date) => {
  return dayjs(date).fromNow();
};

// 处理 UTC 时间(假设后端返回的是 UTC)
export const formatFromUTC = (utcString) => {
  return dayjs.utc(utcString).local().format('YYYY-MM-DD HH:mm');
};

用的时候直接 import 调用就行,不用每次重复配置。这个封装我已经在三个项目里复用了,稳得很。

以上是我踩坑后的总结,希望对你有帮助

时间函数看着简单,实则暗坑无数。选对工具能省下大把 debug 时间。我现在的策略很明确:dayjs 为主,原生 Date 为辅,moment.js 已列入黑名单(除非维护老项目)。

当然,技术没有银弹。如果你有更优的实现方式,或者在特殊场景下有更好的方案,欢迎评论区交流——说不定下次我就改主意了。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论
南宫永伟
这个小技巧虽然简单,但非常实用,直接提升了我的开发效率。
点赞
2026-03-01 23:25