当前位置: 首页 > 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 这些对象,能不能帮你解决你面临的问题。

在这里插入图片描述
这里是编程轨迹,下篇文章再见~

http://www.lryc.cn/news/92671.html

相关文章:

  • 三维模型 工程图
  • 我用ChatGPT写2023高考语文作文(二):全国乙卷
  • java版本工程项目管理系统平台源码,助力工程企业实现数字化管理
  • 代码随想录第55天
  • 算法设计与分析(填空专题)
  • Ubuntu22.04 K8s1.27.2
  • 卡尔曼滤波与组合导航原理(十二)扩展卡尔曼滤波:EKF、二阶EKF、迭代EKF
  • 基于蒙特卡洛模拟法的电动汽车充电负荷研究(Matlab代码实现)
  • 自学黑客【网络安全】,一般人我劝你还是算了吧
  • 编程中的心理策略:如何从错误中学习并实现自我成长
  • Rocket面试(五)Rocketmq发生流量控制的情况有哪些?
  • Tableau招聘信息数据可视化
  • 游戏服务器开发指南(八):合理应对异常
  • 【g】聚类算法之K-means算法
  • scala内建控制结构
  • Linux SSH命令实战教程,提升你的服务器管理基本功!
  • 【Python】Python进阶系列教程-- Python3 CGI编程(二)
  • do..while、while、for循环反汇编剖析
  • 【代码随想录】刷题Day53
  • MySQL 索引及查询优化总结
  • 什么是AJAX?
  • 报表生成器FastReport .Net用户指南:显示数据列、HTML标签
  • bootstrap-dialog弹框,去掉遮盖层,可移动
  • 7. user-Agent破解反爬机制
  • 3.Nginx+Tomcat负载均衡和动静分离群集
  • 数据结构与算法之树结构
  • 【python】 用来将对象持久化的 pickle 模块
  • 【博客654】prometheus配置抓取保护以防止压力过载
  • Backtrader官方中文文档:第十三章Observers观察者
  • 算法leetcode|54. 螺旋矩阵(rust重拳出击)