当前位置: 首页 > news >正文

什么,你还在用 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天前”

还可能存在其他问题,例如时区问题。这些复杂的问题一旦来到,往往开发者会采用像 momentJsdayjs 这样的库来解决问题。虽然,下面这段代码也可以试着解决你的问题:

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 处理相对时间

我想&#xff0c;下面这段代码&#xff0c;你是不是在开发中常常这样使用来计算距离现在过去了多长时间&#xff1a; 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年 全国乙卷 适用地区&#xff1a;河南、江西、甘肃、青海、内蒙古、宁夏、新疆、陕西 吹灭别人的灯&#xff0c;并不会让自己更加光明&#xff1b;阻挡别人的路&#xff0c;也不会让自己行得更远。 “一花独放不是春&#xff0c;百花齐放春满园。”如果世界上只有一种花朵…...

java版本工程项目管理系统平台源码,助力工程企业实现数字化管理

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…...

代码随想录第55天

1.判断子序列&#xff1a; 动态规划五部曲分析如下&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为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代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

自学黑客【网络安全】,一般人我劝你还是算了吧

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 我在之前的回答中&#xff0c;我都一再强调不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;而…...

编程中的心理策略:如何从错误中学习并实现自我成长

在日复一日的工作中&#xff0c;我们免不了会产生一些失误&#xff0c;会因此感到沮丧和失望。但如何正确地对待和处理这些失误才是最重要的&#xff0c;它直接影响到我们的工作表现和个人成长。 一、面对失误而带来的指责和沮丧的策略 在程序设计领域&#xff0c;我们经常面临…...

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流控&#xff0c;Consu…...

Tableau招聘信息数据可视化

获取的招聘信息数据为某招聘网站发布的大数据及数据分析相关岗位&#xff0c;对其他计算机相关岗位的招聘信息数据分析也有一定的参考价值。因为所获取的招聘信息数据数量只有1万左右&#xff0c;实际的招聘信息数量肯定不止1万&#xff0c;所以可能会与实际信息有一定的误差。…...

游戏服务器开发指南(八):合理应对异常

大家好&#xff01;我是长三月&#xff0c;一位在游戏行业工作多年的老程序员&#xff0c;专注于分享服务器开发相关的文章。 本文是通用程序设计主题下的第二篇。这个主题主要探讨如何编写高效、健壮、易读的游戏业务代码&#xff0c;每篇从一个小点切入。本次讨论的要点是&a…...

【g】聚类算法之K-means算法

聚类算法是一种无监督学习方法&#xff0c;它将相似的数据样本划分为一组&#xff0c;同时将不相似的数据样本划分为另一组。这个过程由计算机自动完成&#xff0c;不需要任何人为的干预。 K-means算法是一种经典的聚类算法&#xff0c;它的主要思想是把数据集分成k个簇&#…...

scala内建控制结构

一、条件表达式 &#xff08;一&#xff09;语法格式 - if (条件) 值1 else 值2&#xff08;二&#xff09;执行情况 条件为真&#xff0c;结果是值1&#xff1b;条件为假&#xff0c;结果是值2。如果if和else的返回结果同为某种类型&#xff0c;那么条件表达式结果也是那种类…...

Linux SSH命令实战教程,提升你的服务器管理基本功!

前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文是专栏【linux基本功-基础命令实战】的第62篇文章。 专栏地址&#xff1a;[linux基本功-基础命令专栏] &#xff0c; 此专栏是沐风晓月对Linux常用命令的汇总&#xff0c;希望能够加深自己的印象&am…...

【Python】Python进阶系列教程-- Python3 CGI编程(二)

文章目录 前言什么是CGI网页浏览CGI架构图Web服务器支持及配置第一个CGI程序HTTP头部CGI环境变量GET和POST方法使用GET方法传输数据简单的表单实例&#xff1a;GET方法使用POST方法传递数据通过CGI程序传递checkbox数据通过CGI程序传递Radio数据通过CGI程序传递 Textarea 数据通…...

do..while、while、for循环反汇编剖析

1、循环语句重要特征提取 循环语句最重要的特点就是执行的过程中会往上跳&#xff01;&#xff01;&#xff01; 箭头往上跳的一般都是循环语句&#xff0c;比如下面的for循环&#xff1a; 2、do..while语句反汇编 #include<iostream> using namespace std; #pragma …...

【代码随想录】刷题Day53

1.最长公共子序列 1143. 最长公共子序列 和之前的一道题目的区别就是这个子序列不需要每个字符相邻。那么条件就变成两种了&#xff0c;一种是当前的字符相同&#xff0c;一种是不同。相同跟之前的条件一样&#xff1b;不同则需要继承上次比较的较大值。if (text1[i - 1] tex…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

OPENCV图形计算面积、弧长API讲解(1)

一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的API…...