什么,你还在用 momentJs 处理相对时间
我想,下面这段代码,你是不是在开发中常常这样使用来计算距离现在过去了多长时间:
import moment from 'moment' // 61k (gzipped:19.k)
function Relative(props) {const timeString = moment(props.date).fromNow()return <>{timeString}</>
}
可是,你竟然用一个大小为 20k (还是压缩过的,没压缩 61k)的包,只用来做日期的转换? really? 你想要的只是进行一个日期上的转换啊。
现在,经过我这么一吓唬,你可能会想,能不能这么做:
function nativeGetRelativeTime(unit = 'days', amount = 2) {return `in ${amount} ${unit}s`
}
别,请别这么做。虽然相对时间暂时看起来像是一个简单的问题,但你应该要意识到相对时间有很多复杂的问题需要解决,比如:
- 缩写:一般不会显示 “1天前”? 一般会显示 “昨天”、“明天” 或 “明年” 这样的词
- 将来和过去: 比如我们不会显示“在 -2 天内”,而是显示 “2天前”
还可能存在其他问题,例如时区问题。这些复杂的问题一旦来到,往往开发者会采用像 momentJs 和 dayjs 这样的库来解决问题。虽然,下面这段代码也可以试着解决你的问题:
function nativeGetRelativeTime(locale, unit, amount) {if (locale === 'zh') {const isPlural = amount !== 1 && amount !== -1const isPast = amount < 0if (amount === 1 && unit === 'day') return '明天'if (amount === -1 && unit === 'day') return '昨天'if (amount === 1 && unit === 'year') return '明年'if (isPast) {return `${amount} ${unit}${isPlural ? 's' : ''} 前`}return `in ${amount} ${day}${isPlural ? 's' : ''}`}}
但是,还是请你别这么做。因为这看起来似乎变得复杂了。而我向你推荐的一个内置对象能帮助你解决相对时间的问题。
Intl.RelativeTimeFormat
重申一遍,当你遇到这些情况时,要记住,目前现代前端中已经有有很多解决常见问题的内置解决方案了,可以方便的进行使用。
而面对本文提到的相对时间问题,我要说的就是 Intl.RelativeTimeFormat 这个对象。
我先用下面一段代码来样式它的便捷性:
const rtf = new Intl.RelativeTimeFormat('en', {numeric: 'auto'
})rtf.format(1, 'day') // 'tomorrow'
rtf.format(-2, 'year') // '2 years ago'
rtf.format(10, 'minute') // 'in 10 minutes'
而且,它能很好地处理不同时区的问题:
const rtf = new Intl.RelativeTimeFormat('es-ES', {numeric: 'auto'
})
rtf.format(1, 'day') // 'mañana'
rtf.format(-2, 'year') // 'hace 2 años'
rtf.format(10, 'minute') // 'dentro de 10 minutos'
你甚至可以只传入navigator.language 作为第一个参数:
const rtf = new Intl.RelativeTimeFormat(navigator.language // ✅
)
除此之外,Intl.RelativeTimeFormat 支持的单位包括: "year", "quarter", "month", "week", "day", "hour", "minute", 和 "second"
现在,回到我们最初的例子,我们用 Intl.RelativeTimeFormat 来改写一下:
首先,我们先写一个简单的包装函数来处理相对时间的转换:
function Relative(props) {const timeString = getRelativeTimeString(props.date)return <>{timeString}</>
}
接着,我们使用 Intl.RelativeTimeFormat 对象来实现 getRelativeTimeString 函数:
export function getRelativeTimeString(date: Date | number,lang = navigator.language
): string {const timeMs = typeof date === "number" ? date : date.getTime();const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];const units: Intl.RelativeTimeFormatUnit[] = ["second", "minute", "hour", "day", "week", "month", "year"];const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;const rtf = new Intl.RelativeTimeFormat(lang, { numeric: "auto" });return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
}
Using date-fns
但是如果你不想自己的解决方案,那么也有一个开源的解决方案。date-fns 是一个很棒的 JavaScript 日期工具库,每个日期都支持以 树摇 的方式单独导出。
其中,date-fns 中内置了一个 intlFormatDistance 函数,它是 Intl.RelativeTimeFormat 的一个小包装器,这个函数做的正是我们需要的。并且,它的大小在2kb以下。
看下面的代码,是不是代码简单了许多:

Intl.DateTimeFormat
除此之前,Intl.DateTimeformat 还提供格式化日期和时间:
new Intl.DateTimeFormat('en-US').format(new Date())
// -> 1/23/2023new Intl.DateTimeFormat('en-US', {dateStyle: 'full'
}).format(new Date())
// -> Monday, January 23, 2023new Intl.DateTimeFormat('en-US', {timeStyle: 'medium'
}).format(new Date())
// -> 4:17:23 PMnew Intl.DateTimeFormat('en-US', {dayPeriod: 'short', hour: 'numeric'
}).format(new Date())
// -> 4 in the afternoon
Intl.NumberFormat
同时,Intl.NumberFormat 这个对象还能为你格式化数字:
new Intl.NumberFormat('en', { style: 'currency', currency: 'USD'
}).format(123456.789)
// -> $123,456.79new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR'
}).format(123456.789)
// -> 123.456,79 €new Intl.NumberFormat('pt-PT', {style: 'unit', unit: 'kilometer-per-hour'
}).format(50));
// -> 50 km/h(16).toLocaleString('en-GB', {style: 'unit', unit: 'liter', unitDisplay: 'long',
}));
// -> 16 litres
目前,所有主流浏览器以及 Node.js 和 Deno 都支持 Intl.RelativeTimeFormat。
如果你还在使用像 momentJs 这样的大型数据处理库,不妨考虑考虑Intl.RelativeTimeFormat, Intl.DateTimeFormat 这些对象,能不能帮你解决你面临的问题。

这里是编程轨迹,下篇文章再见~
相关文章:
什么,你还在用 momentJs 处理相对时间
我想,下面这段代码,你是不是在开发中常常这样使用来计算距离现在过去了多长时间: import moment from moment // 61k (gzipped:19.k) function Relative(props) {const timeString moment(props.date).fromNow()return <>{timeString…...
三维模型 工程图
飞机 Crankshaft飞机发动机手动冲压机包装成型机械-充填机械设备10数控等离子切割机床铜线缠绕机机床-磨床08机床-磨床04(附工程图)机床-车床数字纤维缠绕机机械臂液压钳机床-车床06挤出机机械手-09机械手模型库六柴油发动机中央空调机柜空调机机床-钻床三维设计电脑服务器机箱…...
我用ChatGPT写2023高考语文作文(二):全国乙卷
2023年 全国乙卷 适用地区:河南、江西、甘肃、青海、内蒙古、宁夏、新疆、陕西 吹灭别人的灯,并不会让自己更加光明;阻挡别人的路,也不会让自己行得更远。 “一花独放不是春,百花齐放春满园。”如果世界上只有一种花朵…...
java版本工程项目管理系统平台源码,助力工程企业实现数字化管理
鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管…...
代码随想录第55天
1.判断子序列: 动态规划五部曲分析如下: 确定dp数组(dp table)以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。 注意这里是判断s是否…...
算法设计与分析(填空专题)
文章目录 填空题填空题 设有一稀疏图 G,则 G 采用 邻接表 存储较省空间。 算法的时间复杂性是指算法中 元运算 执行次数。 分治法的基本思想是将一个规模为 n 的问题分解为与原问题 相同 的 k 个规模较小且互相独立的子问题。 贪心算法中每次做出的贪心选择都是 当前的 最优选…...
Ubuntu22.04 K8s1.27.2
Ubuntu22.04 && K8s1.27.2 1. 服务器配置 IpServerMEM192.168.56.11k8smaster6G192.168.56.16k8snode14G192.168.56.17k8snode24G 2. 获取源 $ sudo apt-get update $ sudo apt-get install -y apt-transport-https ca-certificates curl# packages.cloud.google.c…...
卡尔曼滤波与组合导航原理(十二)扩展卡尔曼滤波:EKF、二阶EKF、迭代EKF
文章目录 一、多元向量的泰勒级数展开二、扩展Kalman滤波三、二阶滤波四、迭代EKF滤波 一、多元向量的泰勒级数展开 { y 1 f 1 ( X ) f 1 ( x 1 , x 2 , ⋯ x n ) y 2 f 2 ( X ) f 2 ( x 1 , x 2 , ⋯ x n ) ⋮ y m f m ( X ) f m ( x 1 , x 2 , ⋯ x n ) \left\{\begin{…...
基于蒙特卡洛模拟法的电动汽车充电负荷研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
自学黑客【网络安全】,一般人我劝你还是算了吧
一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员(以编程为基础的学习)再开始学习 我在之前的回答中,我都一再强调不要以编程为基础再开始学习网络安全,一般来说,学习编程不但学习周期长,而…...
编程中的心理策略:如何从错误中学习并实现自我成长
在日复一日的工作中,我们免不了会产生一些失误,会因此感到沮丧和失望。但如何正确地对待和处理这些失误才是最重要的,它直接影响到我们的工作表现和个人成长。 一、面对失误而带来的指责和沮丧的策略 在程序设计领域,我们经常面临…...
Rocket面试(五)Rocketmq发生流量控制的情况有哪些?
在使用rocketmq过程中总能看见一下异常 [TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while, period in queue: 206ms, size of queue: 5这是因为Rocketmq出发了流量控制。 触发流量控制就是为了防止Broker压力过大挂掉。主要分为Broker流控,Consu…...
Tableau招聘信息数据可视化
获取的招聘信息数据为某招聘网站发布的大数据及数据分析相关岗位,对其他计算机相关岗位的招聘信息数据分析也有一定的参考价值。因为所获取的招聘信息数据数量只有1万左右,实际的招聘信息数量肯定不止1万,所以可能会与实际信息有一定的误差。…...
游戏服务器开发指南(八):合理应对异常
大家好!我是长三月,一位在游戏行业工作多年的老程序员,专注于分享服务器开发相关的文章。 本文是通用程序设计主题下的第二篇。这个主题主要探讨如何编写高效、健壮、易读的游戏业务代码,每篇从一个小点切入。本次讨论的要点是&a…...
【g】聚类算法之K-means算法
聚类算法是一种无监督学习方法,它将相似的数据样本划分为一组,同时将不相似的数据样本划分为另一组。这个过程由计算机自动完成,不需要任何人为的干预。 K-means算法是一种经典的聚类算法,它的主要思想是把数据集分成k个簇&#…...
scala内建控制结构
一、条件表达式 (一)语法格式 - if (条件) 值1 else 值2(二)执行情况 条件为真,结果是值1;条件为假,结果是值2。如果if和else的返回结果同为某种类型,那么条件表达式结果也是那种类…...
Linux SSH命令实战教程,提升你的服务器管理基本功!
前言 大家好,又见面了,我是沐风晓月,本文是专栏【linux基本功-基础命令实战】的第62篇文章。 专栏地址:[linux基本功-基础命令专栏] , 此专栏是沐风晓月对Linux常用命令的汇总,希望能够加深自己的印象&am…...
【Python】Python进阶系列教程-- Python3 CGI编程(二)
文章目录 前言什么是CGI网页浏览CGI架构图Web服务器支持及配置第一个CGI程序HTTP头部CGI环境变量GET和POST方法使用GET方法传输数据简单的表单实例:GET方法使用POST方法传递数据通过CGI程序传递checkbox数据通过CGI程序传递Radio数据通过CGI程序传递 Textarea 数据通…...
do..while、while、for循环反汇编剖析
1、循环语句重要特征提取 循环语句最重要的特点就是执行的过程中会往上跳!!! 箭头往上跳的一般都是循环语句,比如下面的for循环: 2、do..while语句反汇编 #include<iostream> using namespace std; #pragma …...
【代码随想录】刷题Day53
1.最长公共子序列 1143. 最长公共子序列 和之前的一道题目的区别就是这个子序列不需要每个字符相邻。那么条件就变成两种了,一种是当前的字符相同,一种是不同。相同跟之前的条件一样;不同则需要继承上次比较的较大值。if (text1[i - 1] tex…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
