Luxon
几个灵魂拷问
- 你是否一看到日期和时间戳就有生理不适
- 你是否到现在都分不清楚 getDay 和 getDate 有什么区别
- 你是否还记得 getMonth 是从 0 开始还是从 1 开始,其他 API 呢
- 虽然场景比较少,但是怎么切换时区显示呢
Luxon 是什么
Luxon 是一个轻量的 JavaScript 日期库(压缩后的大小约为 21.1KB),它隶属于 Moment 项目组,在 moment 基础上优化了 API 的语义、时区,统一了 API 的命名规范,让开发者更容易上手,让你彻底摆脱原生难用的方法,从此爱上日期时间
DateTime.local().setZone('America/New_York').minus({ weeks: 1 }).endOf('day').toISO()
Luxon 的语法非常的语义化,甚至不用了解他的 API 语法也能看懂上面的输出结果
诞生背景
Luxon 的作者名为 icambron,他也是 Moment 的开发者之一,在开发的过程中,他逐渐有了些新想法想去优化,但是却未能成功,一是时区,Moment 的底层架构使得这部分功能难以改善,二是链式调用,这部分与 Moment 现有的 API 完全不兼容,icambron 为了不影响现有的 Moment 功能,于是就新开了一个项目,在吸收了 Moment 的设计思想之上,创造了 Luxon,他断断续续写了 2 年,最终被 Moment 队伍接受,并将 Luxon 放在了 Moment 组织之下,而现在,Moment 虽然还在维护,但是官方已经声明,他们了解了 Moment 的缺陷,虽然项目没有死,但是也不会有更新的东西了(It is not dead, but it is indeed done.),而首推的其他库就是 Luxon
Moment.js 的缺点
- 因为底层设计的缺陷,体积越来越大,尤其是加上国际化之后,甚至需要通过特定的 webpack 插件优化
- 时区的功能和本身的库独立,需要另行加载,而且文档不够清晰,对使用时区的开发者,非常不友好
- 本身设计的对象是可变的,这样在使用中会造成很多困扰,例如:
let a = moment() let b = a.add(10, 'days') console.log(a === b) // true
这是国人开发的一个日期插件,也是 Moment 推荐的另一个小而美库,他解决了上述的一些缺陷,同时保持着 Moment 一致的 API 规范,可以方便的迁移过去,且有完善的中文文档,是很多国人开发者的不二选择
Luxon 安装
npm install --save luxon
其他还有 CDN 加载,RequireJS 加载等多种方式,因为 npm 安装普适性较高,这里就不一一列举了,如果需要可以去官网检索
Luxon 快速上手
下面通过一些简单的例子,展示一下 Luxon 都有哪些功能
import { DateTime, Interval, Duration } from 'luxon'
// 获取当前时间
DateTime.local()
// 格式化时间 '2020 Dec 10'
DateTime.local().format('yyyy LLL dd')
// 加减运算
DateTime.local().plus({ hours: 2, minutes: 30 })
// 表示一个时间段
Interval.fromDateTimes(dt1, dt2)
// 表示一个时间周期,这个功能一般会结合 Interval 和 DateTime 的运算使用
const dur = Duration.fromObject({hours: 2, minutes: 7})
DateTime.local().plus(dur)
Interval.fromDateTimes(dt1, dt2).toDuration()
// Interval 和 Duration 的区别主要是一个是具体的时间(哪天到哪天),一个是时间段(多少小时)
// 国际化 '2020 12月 10'
DateTime.local().setLocale('en-US').toFormat('yyyy LLL dd')
// 时区
DateTime.local().setZone('America/Los_Angeles')
上述有些方法是静态方法,例如: DateTime.local(), Interval.merge()
,有些是实例方法:例如:dt.format(), dt.plus()
接下来展开说明 Luxon 的各部分 API
DateTime
DateTime 可以生成一个无法被改变的日期对象,通过这个对象可以进行一系列的变化,例如:生成新的日期,格式化显示日期等
- 创建 DateTime 对象
DateTime.local() DateTime.fromJSDate() DateTime.fromObject({ year: 2020, month: 10, day: 5 }) DateTime.fromFormat('2020-12-10', 'yyyy-LL-dd') DateTime.fromSQL() ...
- 获取日期对象基本属性
const dt = DateTime.local() dt.year dt.month dt.day ...
- 转换日期
DateTime.local().plus({ days: 1 }) DateTime.local().set({ hour: 8, minute: 30 }) DateTime.local().endOf('day') ...
- 按指定格式输出日期
DateTime.local().toFormat('yyyy-LL-dd') DateTime.local().plus({ days: 1 }).toJSDate() ...
以下部分 API 和 DateTime 有异曲同工之处,因此省略,只列出一些特殊的接口
Duration
Duration 代表一个时间段,例如:2 小时 30 分,这个时间段可以用来页面展示,例如:2 小时前,也可以用来转换现有的 DateTime 对象,例如:在现有基础上加 2 小时
- 创建 Duration 对象
Duration.fromObject({ hour: 2, minute: 30 }) ...
- 获取基本属性
- 转换 Duration
- 按指定格式输出
Duration 也可以结合 DateTime 操作日期的转换,例如:
const dur = Duration.fromObject({ hour: 2 }) const dt = DateTime.local() dt.plus(dur) // 在当前时间增加 2 小时
Interval
Interval 是一个具体的时间段,例如:2020 年 12 月 10 日 至 2020 年 12 月 14 日,可能乍一看不知道用在什么地方,但是不要急,看完 API 之后你就会对他有个合适的应用场景
- 创建 Interval 对象
// Interval 内部需要两个 DateTime 对象,start 和 end // 这里需要传两个 DateTime 对象,标明 开始 和 结尾 Interval.fromDateTimes(dt1, dt2) // 也可以传一个 DateTime 和 Duration 对象 Interval.after(startDt, dur)
- 一些 Interval 特殊数据
- 获取 Interval 的长度,例如:两个日期中间有多少天、多少秒,length 和 count 的区别是:length 表示两个日期中间跨度有几天,是一个精确的数字,而 count 则不太精确,表示这两个日期中有几个完整的天
const dt1 = DateTime.fromObject({ day: 10, hour: 12 }) const dt2 = DateTime.fromObject({ day: 14 }) const it = Interval.fromDateTimes(dt1, dt2) it.length('days') // 3.5 it.count('days') // 5
- 判断某个日期是否在给定的两个日期之间
it.contains(somedt)
- 获取 Interval 的长度,例如:两个日期中间有多少天、多少秒,length 和 count 的区别是:length 表示两个日期中间跨度有几天,是一个精确的数字,而 count 则不太精确,表示这两个日期中有几个完整的天
- 转换 Interval
// 返回不同的时间段的并集 Interval.merge([ it1, it2 ]) // 返回不同的时间段的交集 Interval.xor([ it1, it2 ])
- 比较 Interval
it.equals(otherit) // 是否和其他时间段有交集 it.overlaps(otherit) // 是否包含其他时间段 it.engulfs(otherit) // 是否本时间段的 end 是其他时间段的 start it.abutsStart(otherit) // 是否本时间段的 start 是其他时间段的 end // 这几个函数可以想象成 大于等于、小于等于 功能 it.abutsEnd(otherit)
- 按指定格式输出
// 这里 separator 选项可以设置两个日期之间的连接符,例如:2020 ~ 2023 中间的 ~ it.toFormat('yyyy-LL-dd', { separator: '~' }) // 直接输出为 Duration 对象 it.toDuration('days')
国际化
Luxon 国际化用的是原生的 API 接口 Intl,因此无需引入其他文件,默认会根据系统语言自动展示
// 通过 DateTime 设置国家
DateTime.fromISO('2020-12-12', { locale: 'fr' })
DateTime.local().setLocale('en_US')
// 全局设置
Settings.defaultLocale = 'fr'
时区
设置时区无需引入其他的文件,默认会根据系统所在的时区自动选择,有多种设置方式
// 通过字符串设置
DateTime.fromFormat('2020-12-20T09:10:23 Europe/Paris', 'yyyy-MM-dd"T"HH:mm:ss z', { setZone: true})
// DateTime 对象设置
DateTime.local().setZone('America/Los_Angeles')
// 全局设置
Setting.defaultZoneName = 'Asia/Tokyo'
// 获取 DateTime 的其他时区,而不改变原有的对象
const local = DateTime.local()
const rezone = local.setZone('America/Los_Angeles', { keepLocalTime: true })
local.valueOf() === rezone.valueOf() // false
其他类
-
Setting
可以展示全局设置、也可以进行一些全局设置,如上面所述,全局的时区、全局的语言、全局的数字显示字符(1、2、3 显示为 一、二、三)等等
-
Info
Info 类用来展示系统静态信息,例如当前的月份格式化字符(一月、二月)等等
总结
通过上面的概览,大家可以看出 Luxon 的 API 语言非常的规范,例如:国际化都用 locale 这个单词表示,而且语义很明确,例如:setZone、toJSDate、fromObject等等,而且根据 API 名称还可以简单的了解到传参需要的数据格式,例如:fromObject 可以传一个对象参数,fromDateTimes(注意这里有一个 s),可以传两个 DateTime 格式的数据,而且官方的文档阅读起来也非常的有条理(虽然目前还没有中文),API 文档也列举的很详细,所有你想用到的方法和属性都会列举出来,不像某些国内的文档(例如:小程序文档),某些功能在这个页面分类里,某些在另一个页面,当然这也和作者只有一个人有关系,总之,这款小而美的日期库,非常值得一用,并且用过之后你一定会喜欢上它