背景

在前端Moment.js可以说是家喻户晓,目前在日期和时间的处理上仍然是使用最广泛的库。从2011年到现在Moment已经完成了它的使命,在技术发展到今天,JavaScript生态已经足够健全,有很多优秀的库可以替代moment.js。所以除非有重大问题会维护一下,小毛病就不管了,也不再发布大迭代版本创新了。不建议大家使用moment.js作为新项目的时间处理包,可以选择Luxon,Day.js,date-fns,js-Joda作为替代品。

Moment的继承者

  • day.js官网
  • Day.js 是一个轻量的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持完全一样
对比 moment dayjs
体积 67.8k左右 2KB左右
沙箱 Moment 对象是可变对象(mutable) 所有更改Day.js对象的API操作都将返回一个新的实例。
多语言支持
插件拓展 ×
  • 插件可以给 Day.js 增加新功能和扩展已有功能:

    • AdvancedFormat 扩展了 dayjs().format API 以支持更多模版
    • RelativeTime 增加了 .from .to .fromNow .toNow 4个 API 来展示相对的时间 (e.g. 3 小时以前).
    • IsLeapYear 增加了 .isLeapYear API 返回一个 boolean 来展示一个 Dayjs’s 的年份是不是闰年.
    • WeekOfYear 增加了 .week() API 返回一个 number 来表示 Dayjs 的日期是年中第几周.
    • IsSameOrAfter 增加了 .isSameOrAfter() API 返回一个 boolean 来展示一个时间是否和一个时间相同或在一个时间之后.
    • IsSameOrBefore 增加了 .isSameOrBefore() API 返回一个 boolean 来展示一个时间是否和一个时间相同或在一个时间之前.

小结

简单来说day.js 是Moment的完美继承者,不仅解决了mutable的问题,同样解决了包体积过大的问题,同时保持了与moment相同的api,几乎不需要任何代价的进行切换使用。Luxon,date-fns,js-Joda感兴趣的同学可以自行了解。

JS 的新一代日期/时间 API Temporal

  • Temporal 博客
    众所周知,JS的Date是出了名的难用,一直以来我们都在使用momentjs,dayjs等第三方库来处理日期和时间格式,于是 TC39 组织开始了对 Date 的升级改造,他们找到了 moment.js 库的作者,Maggie ,由她来担任新特性 Temporal的主力设计。
  • 特性
  • 所有的对象都是不可改变的。改变它们会产生新的值,类似于JavaScript中字符串的工作方式。
  • 它支持时区和非格雷戈尔式的日历。
  • 有几个专门针对时间值的类(带时区的日期时间值,不带时区的日期时间值,不带时区的日期值,等等)。这有几个好处。
    • 一个值的上下文(是否有时区,等等)更容易理解。
    • 如何实现一个给定的任务往往更加明显。
    • .toString() ,使用时可以少考虑很多。
  • 1月是第1个月。
  • Temporal 支持的日历基于标准的Unicode Unicode Common Locale Data Repository (CLDR) 也就是说支持农历、民国历等等
npm install @js-temporal/polyfillimport { Temporal} from '@js-temporal/polyfill';

Temporal是一个全局对象,像 Math 、Promise 一样位于顶级命名空间中,为 Javascript 语言带来了现代化的日期、时间接口。

对比Date和Temporal的使用

  • Temporal被设计为三部分

    • ISO 8601 格式的日期和时间;具体时间

    • 时区(中国北京);哪个时区的

    • 日历(中国农历);使用什么历法

  • 对比 Date

    new Date()
    //Mon May 16 2022 10:11:27 GMT+0800 (中国标准时间)
    

Date 采用 GMT格式(旧的时间表示格式) 的时间,使用方面不如 ISO 8601 通用,同时不包含 时区和历法。

使用方法(更多API)

  • 如何获取本地时区的当前日期和时间?
    请注意,如果您只需要日期而不是时间,则应使用Temporal.PlainDate. 如果两者都需要,请使用Temporal.PlainDateTime.

    const date = Temporal.Now.plainDateISO();
    date.toString();Temporal.Now.plainDateTimeISO().toString();
    
  • 如何获得 Unix 时间戳?

    const timeStamp = Temporal.Now.instant();// Timestamp in Milliseconds
    timeStamp.epochMilliseconds;
    // Timestamp in Seconds
    timeStamp.epochSeconds;
    
  • Temporal在类型和遗留之间转换Date

    • 旧版Date=>Temporal.Instant和/或Temporal.ZonedDateTime
    const legacyDate = new Date('1970-01-01T00:00:01Z');
    const instant = legacyDate.toTemporalInstant();  // 转换为 temporal 格式assert.equal(instant.epochMilliseconds, legacyDate.getTime()); // 和 Date 对比
    assert.equal(instant.toString(), '1970-01-01T00:00:01Z');const zoned = instant.toZonedDateTimeISO(Temporal.Now.timeZone());assert.equal(zoned.epochMilliseconds, legacyDate.getTime());const zoned2 = instant.toZonedDateTimeISO('Asia/Shanghai');assert.equal(zoned2.epochMilliseconds, legacyDate.getTime());
    assert.equal(zoned2.timeZone.id, 'Asia/Shanghai');
    
    • 仅日期值:legacy Date=>Temporal.PlainDate
      要正确地将 date-only 转换Date为 aTemporal.PlainDate而不会受到偏离一天错误的影响,您必须确定使用哪个时区的午夜来构造Date,然后在从 转换为 时使用相同的时Temporal.Instant区Temporal.PlainDate。
       let date = new Date(2000, 0, 1);let plainDate = date.toTemporalInstant()                         // => 2000-01-01T08:00:00Z.toZonedDateTimeISO(Temporal.Now.timeZone()) // => 2000-01-01T00:00:00-08:00[America/Los_Angeles].toPlainDate();                              // => 2000-01-01assert.equal(plainDate.toString(), '2000-01-01');date = new Date(Date.UTC(2000, 0, 1)); // => Fri Dec 31 1999 16:00:00 GMT-0800 (Pacific Standard Time)date = new Date('2000-01-01T00:00Z');  // => Fri Dec 31 1999 16:00:00 GMT-0800 (Pacific Standard Time)plainDate = date.toTemporalInstant()       // => 2000-01-01T00:00:00Z.toZonedDateTimeISO('UTC') // => 2000-01-01T00:00:00+00:00[UTC].toPlainDate();            // => 2000-01-01assert.equal(plainDate.toString(), '2000-01-01');
    
    • Temporal类型 => 遗留Date
    // To convert Instant to legacy Date, use the epochMilliseconds property.const instant = Temporal.Instant.from('2020-01-01T00:00:01.000999Z');
    const result = new Date(instant.epochMilliseconds);assert.equal(result.getTime(), 1577836801000); // ms since Unix epoch
    assert.equal(result.toISOString(), '2020-01-01T00:00:01.000Z');// Same thing for ZonedDateTime.
    // Note that legacy Date will not preserve the ZonedDateTime's time zone.const zoned = Temporal.ZonedDateTime.from('2020-01-01T00:00:01.001[Asia/Tokyo]');
    const result2 = new Date(zoned.epochMilliseconds);assert.equal(result2.getTime(), 1577804401001); // note, different time
    assert.equal(result2.toISOString(), '2019-12-31T15:00:01.001Z');// For most use cases, new Date(x.epochMilliseconds) is fine.
    // You may need to add an extra round() step if you want other
    // rounding behaviour than truncation. For example, here the 999
    // microseconds is rounded to 1 millisecond.const result3 = new Date(instant.round({ smallestUnit: 'millisecond' }).epochMilliseconds);assert.equal(result3.getTime(), 1577836801001);
    assert.equal(result3.toISOString(), '2020-01-01T00:00:01.001Z');
    
  • 类型之间的转换

    • 将日历日期 ( Temporal.PlainDate) 和挂钟时间 ( Temporal.PlainTime) 组合成Temporal.PlainDateTime. 就是将日期加上时间组合起来
    const date = Temporal.PlainDate.from('2020-05-14');const noonOnDate = date.toPlainDateTime(Temporal.PlainTime.from({ hour: 12 }));assert(noonOnDate instanceof Temporal.PlainDateTime);assert.equal(noonOnDate.toString(), '2020-05-14T12:00:00');
    • 将日历上的一天 ( Temporal.PlainMonthDay) 和一年组合成Temporal.PlainDate 就是将天和年组合起来
    const birthday = Temporal.PlainMonthDay.from('12-15');const birthdayIn2030 = birthday.toPlainDate({ year: 2030 });birthdayIn2030.dayOfWeek; // => 7assert(birthdayIn2030 instanceof Temporal.PlainDate);assert.equal(birthdayIn2030.toString(), '2030-12-15');
    
  • 序列化

    • 要将精确时间序列Temporal.Instant化为字符串,请使用toString(). 没有任何参数,这会给你一个 UTC 时间的字符串。

    • 如果您需要您的字符串包含 UTC 偏移量,则使用该timeZone选项Temporal.Instant.prototype.toString()将返回该时区中与确切时间相对应的挂钟时间的字符串序列化。

    • 这会丢失有关字符串所在时区的信息,因为它只保留该特定确切时间与时区的 UTC 偏移量。如果您需要您的字符串包含时区名称,请改用Temporal.ZonedDateTime它保留此信息。

    const instant = Temporal.Instant.from('2022-05-16T10:41:51Z');
    // 使用 toString 获得字符串
    const result = instant.toString(); // '2022-05-16T10:41:51Z'
    // 使用 toString 获得某时区字符串
    const result2 = instant.toString({ timeZone: 'America/Yellowknife' });// 使用 toZonedDateTimeISO 转换时区
    const zoned = instant.toZonedDateTimeISO('Asia/Seoul');
    const result3 = zoned.toString();// ZonedDateTime
    assert(zoned.equals(Temporal.ZonedDateTime.from(result3)));
    
  • 同时Temporal 支持排序, 四舍五入, 时区转换, 时间的计算等等功能

    • 具体API查看上面链接的Doc文档

Temporal 小结

1.Date不支持除用户本地时间以外的时区。Temparal 支持开发人员通过 TimeZone 来设置本地时间以外的时区。
2.计算 API 缺失。除了时区和日历类型外,其他类型都可以进行 算术运算,即时间的比较,增加,减少等。
3.不支持非公历,Calendar 类型支持 Temparal 选择日历。
4.解析器行为不可靠以至于无法使用,在 Temporal 里,new 构造函数() 或者From 方法,对参数的要求都更加规范,同时From 方法支持 日期溢出 后的逻辑处理,可以防止系统崩溃。

左侧绿色区域的 Instant 类型,用来表达某个瞬间的时间,不包含时区和日历的信息。右侧黄色区域的 PlainXX系列(5个),用来表达日历日期或者钟表时间,包含日历信息,而中间的 ZonedDateTime 则横跨左右两个区域,包含时区和日历信息,可以作为一个通道,连接左侧的 Instant 和右侧的 Plain系列,负责类型之间转换的桥梁,同时中间的 Timezone 时区类型 Calendar 日历类型,不单独使用,配合上方的 ZonedDateTime 类型来辅助转换。最下面的 Duration 与所有类型没有直接关系,不参与类型转换,表示一段持续时间,并且这段时间可以用来进行算术。

参考文章

Day.js中文网

tc39 提案博客

Moment.js 宣布停止开发,现在该用什么?

360导航前端团队 - JS历史最头疼的对象Date即将淘汰,替代物Temporal真的好用

JS 的新一代日期/时间 API Temporal和 Moment.js的继承者相关推荐

  1. JS 的新一代日期/时间 API Temporal,比起 Date 它真的好用(Temporal教程)

    本文作者王明是360导航前端团队前端开发工程师 原文标题:JS历史最头疼的对象Date即将淘汰,替代物Temporal真的好用(全网首发Temporal教程) 原文地址:https://juejin. ...

  2. JS 的新一代日期/时间 API Temporal

    众所周知,JS的Date是出了名的难用,一直以来我们都在使用momentjs,dayjs等第三方库来处理日期和时间格式,于是 TC39 组织开始了对 Date 的升级改造,他们找到了 moment.j ...

  3. 一文告诉你Java日期时间API到底有多烂

    前言 你好,我是A哥(YourBatman). 好看的代码,千篇一律!难看的代码,卧槽卧槽~其实没有什么代码是"史上最烂"的,要有也只有"史上更烂". 日期是商 ...

  4. java date只保留年月日_Java日期时间API系列14-----Jdk8中日期API类,日期计算1,获取年月日时分秒等...

    通过Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, Tempora ...

  5. jsr303自定义验证_JSR 310新日期/时间API的自定义JSR 303 Bean验证约束

    jsr303自定义验证 借助JSR 310,Java 8终于为我们带来了不错的日期和时间API. 对于仍在使用Java 7的那些人(就像我目前在我的当前项目中一样),有很好的反向移植,请访问www.t ...

  6. JSR 310新日期/时间API的自定义JSR 303 Bean验证约束

    借助JSR 310,Java 8终于为我们带来了不错的日期和时间API. 对于仍在使用Java 7的那些人(例如我目前在我的当前项目中),有很好的反向移植,请访问www.threeten.org了解更 ...

  7. 6 日期字符串转日期_Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类...

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  8. java date加一天_Java日期时间API系列15-----Jdk8中API类,java日期计算2,年月日时分秒的加减等...

    通过Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, Tempora ...

  9. java 包结构 枚举类_Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类...

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

最新文章

  1. java速算24,Java扑克牌速算24的方法
  2. 超融合与传统架构真正的区别在哪?
  3. 组会PPT20200910《大工HPT放电结果错误剖析》
  4. 数学建模-预测模型总结(适用范围、优缺点)【灰色预测模型、插值与拟合、时间序列预测法、马尔科夫预测、差分方程、微分方程模型、神经元网络】
  5. 性能测试报告模板_性能测试规范之测试报告
  6. 【转】如何实现一个文件系统
  7. c++ double 截取_c选择double小数点后自动截取3位,不...
  8. 如何割教育培训机构的韭菜?
  9. input做成label效果
  10. JumpList中Recent类别和自定义类型
  11. wps 宏 禁用_WPS表格如何解除宏禁用
  12. CTF训练(密码学)——位移密码
  13. 一年级金字塔框填数字_一年
  14. 检测网络是否正常(ping,Telnet,tracert以及tnsping)
  15. Output tensors to a Model must be the output of a TensorFlow `Layer`
  16. [android] app运行在夜神模拟器上
  17. jieba分词词性标注含义
  18. linux下x264安装
  19. STM32中的串口通信的基础知识
  20. 【ROS wiki】ros wiki中查阅常见的消息类型

热门文章

  1. 【计算机组装与网络布线】计算机组装与维护(二)——硬件系统的组装及故障分析
  2. RHEL8配置本地YUM源
  3. Rowhammer Test for DRAM
  4. <数据库> datediff、timestampdiff函数的区别
  5. ffmpeg集成到androidStudio
  6. torch.optim.lr_scheduler.StepLR()函数
  7. 爱奇艺缓存的视频qsv怎样转mp4
  8. CentOS7-使用squid搭建http代理服务器
  9. 2022年中科大细胞生物学实验原理往年题复习参考
  10. Mikrotik接口VLAN设置