更新2021-06-29:澄清了Instant如何使用ISO-8601日历。列出了某些类的属性。
日期,JavaScript的当前日期时间API是难以使用的。 ECMAScript提案“Temporal”是一个新的和更好的日期时间API和目前在舞台3.它是由Philipp Dunkel,Maggie Johnson-Pint,Matt Johnson-Pint,Brian Terlson,Shane Carr,Ujjwal Sharma,Philip Chimeno,杰森创造的威廉姆斯,贾斯汀补助金。
但是,它不是一个详尽的文档:有关许多细节,您必须咨询时间的(优秀)文档。
时间日期时间API可通过全局变量时间访问。很高兴使用:
所有对象都是不可变的。更改它们会产生新的值,类似于字符串如何在JavaScript中工作。
时间值有几个专门类别(日期时间值与时区,日期时间值没有时区,日期值,没有时区等)。这有几个好处:
该帖子从背景知识开始。这将有助于你的剩余部分,但没有它,你应该没问题。
接下来,概述时间API的所有类以及它们如何合适。
明显的太阳时间(本地表观时间):测量时间最早的方法之一是将当前时间基于太阳位置。例如,中午是太阳直接开销时。
平均太阳时间(本地平均时间):此时间表纠正了明显的太阳时间的变化,使年度的每一天具有相同的长度。
标准时间和时区:标准时间指定如何同步地理区域内的时钟。它成立于19世纪,以支持天气预报和火车旅行。在20世纪,标准时间是全球范围的标准和地理区域成为时区。
壁钟时间是时区内的当前时间(如墙上的时钟所示)。壁钟时间也被称为本地时间。
UTC,Z和GMT是指定类似的时间的方式,但细微不同:
UTC(协调世界时)是所有时间区基于的时间标准。它们相对于它指定。也就是说,没有国家或地区将UTC作为当地时区。
Z(Zulu时区)是一个常规用于航空和军队的军事时区,作为UTC + 0的另一个名称。
GMT(格林威治黎明)是在一些欧洲和非洲国家使用的时区。它是UTC加零时间,因此与UTC具有同一时间。
时间的时区基于IANA时区数据库(短:TZ数据库)。 IANA代表互联网分配的号码权限。在该数据库中,每个时区都有一个标识符和定义UTC次偏移的规则。如果时区具有标准时间和夏令时,偏移量在一年内发生变化:
const标准时间=临时.zoneddateTime.from({:'欧洲/苏黎世':1995,:11,:30,:3,:24,}); assert.equal(standardtime.tostring(), ' 1995-11-30T03:24:00 + 01:00 [欧洲/苏黎世]'); //(a)const daylightsavingtime = temporal.zoneddatetime.from({:'欧洲/苏黎世':1995,:5,:30,:3,:24,}); assert.equal(Daylightsavingtime .tostring(),' 1995-05-30t03:24:00 + 02:00 [欧洲/苏黎世]'); //(b)
在标准时间内,欧洲/苏黎世时区的时间偏移是+1:00(第a行)。在夏令时,时间偏移是+2:00(B线)。
IANA网站上的“时区数据库”是一个时区名称列表。
Wikipedia上的“TZ数据库时区列表”是另一个时区名称列表。
“时间差”(“Zeitverschiebung”)列出了城市的时区等 - 例如,旧金山的时区是美国/ Los_Angeles。
按时间支持的日历基于标准Unicode Unicode公共区域数据存储库(CLDR) - 等:
ISO8601由大多数西方国家使用,并通过QuotialAl.now.now.zonedDateTemiso()等方法来获得额外的支持()()(返回系统时区和ISO-8601日历中的当前日期和挂钟时间)。
标准ISO-8601和RFC 3339指定了如何表示字符串中的日期。目前,它们是缺少yemporal所需的功能:
下面的代码显示了一个完整的日期时间字符串的样子。在实践中,许多这些部件往往会丢失:
const zdt = temporal.zoneddatetime.from({:'非洲/内罗毕和#39;:2019,:11,:30,:8,:55,:0,:0,:0,:0,:123,:456,:789,} ); assert.equal(zdt.tostring({:'始终':' nanosecond'}),' 2019-11-30t08:55:00.123456789 + 03:00 [非洲/内罗毕] [U-CA = ISO8601]&#39);
本节概述了时间API的类。它们都可以通过全局变量时空(Temporal.Instant,Temporal.ZonedDateTime等)访问。
壁钟时间(也称为本地时间或时钟时间)在全球范围内变化,具体取决于时钟的时区。
纪元时间是表示确切时间的一种方式:它是一个数字计数时间单位(如纳秒)或Unix时期(1970年1月1日午夜UTC)。
一方面,我们可以通过构造函数创建实例。它接受完全指定日期时间值所需的最小数量。例如,在两个类的用于确切时间,即时和ZonedDateme的情况下,时间本身通过epoch纳秒指定。
const epochnanoseconds = 6046761644163000000n; Const TimeZone ='美国/ Los_Angeles&#39 ;; //旧弗朗西斯科常ZDT1 =新的临时.zoneddatetime(epochnanoseconds,timezone); ssuert.equal(zdt1.tostring(),' 2161-08-12t09:00:44.163-07:00 [美国/ Los_Angeles]& #39;);
另一方面,我们可以通过静态工厂方法创建实例。从()。它超载:大多数类都支持其参数的三种值。
首先,如果参数是同一类的实例,则克隆该实例:
const zdt3 = temporal.zoneddatetime.from({:'美国/ los_angeles':2161,:8,:12,:9,:0,:4,:44,:163,:0,:0,} ); assert.equal(zdt3.tostring(),' 2161-08-12t09:00:44.163-07:00 [美国/ LOS_ANGELES]');
请注意,我们不需要在DINE A中指定偏移量,但它以行B线显示。 recisoday:参考ISO日,用于消除歧义时使用ISO-8601日历以外的日历 Refisoyear:参考ISO年,用于消除歧义时使用ISO-8601日历以外的日历 Instant在内部使用UTC和ISO-8601日历(例如,用于.tostring()),但它们未存储在实例中。 Object Temporal.Now有几种工厂方法,用于创建表示当前时间的时间值: 我们可以使用Temporal.now来访问系统的当前时区。 此时刻可以改变 - 例如,当系统旅行时: Class Instant表示全球确切时间。 它的时间标准是UTC。 它主要是由于时代以来的纳秒的容器。 这也反映了它没有具有如。性和.hour(哪种Zoneddatetime和Plaindatetime)的属性。
对于某些操作(例如.TOSTRING()),Instant内部使用ISO-8601日历,但该日历未存储在实例中。
夏令时可能播放角色的时间计算(“一小时后”)
//澳大利亚墨尔本的当前时间(在ISO-8601日历中)Const ZonedDatetime = Temporal.Now.Now.zonedDateteMiSo('澳大利亚/墨尔本'); assert.equal(zoneddatetime.tostring(),' 2021-06-27T10:46:31.179753181 + 10:00 [澳大利亚/墨尔本]');
如果一个类没有时区,则时间调用它“平原”。有三个TimeZone的课程:PlaindateTime,Plaindate和凌乱。他们是时间的抽象表现。
时区无关时的时间计算(“1998年5月的第一个星期三”)。
const zoneddatetime = temporal.now.now.zoneddatetemeiso('亚洲/新西伯利亚人和#39;); assert.equal(zoneddatetime.tostring(),' 2021-06-27T10:46:31.179 + 07:00 [亚洲/ novosibirsk]'); //获得墙钟时间作为字符串const plaindatetime = zoneddatetime.toplabaindatetime()assert.equal(plaindatetime.tostring(),' 2021-06-27t10:46:31.179');
// bastille day const bastilleday = youpalal.plainmonthday.from({:7,:14}); assert.equal(bastilleday.tostring(),' 07-14'); // Bastille Day于1989年在巴黎康斯特Zoneddatetime = Bastilleday .toplaindate({:1989}).tozoneddatetime('欧洲/巴黎'); assert.equal(zoneddatetime.tostring(),' 1989 -07-14T00:00:00 + 02:00 [欧洲/巴黎]');
包含完整日期的所有时间类都使用日历来帮助它们使用各种计算。大多数代码将使用ISO-8601日历,但也支持其他日历系统。
const pd1 = new youpalal.plaindate(1992,2,24,' ISO8601'); Const PD2 =新的临时.Plaindate(1992,2,24,{:' ISO8601'}); const pd3 =新的临时.plaindate(1992,2,24,新的临时.calendar(' iso8601'));
时区的实例代表时区。它们支持IANA时区,UTC和UTC抵消。对于大多数用例,IANA时区是最佳选择,因为它们可以正确处理夏令时。
const zdt1 = new temporal.zoneddatetime(0n,'美国/利马'); const zdt2 = new temporal.zoneddatetime(0n,{:'美国/利马'}); const zdt3 =新的临时.zoneddatetime(0n,new temporal.timezone('美国/利马'));
持续时间表示时间长度 - 例如3小时45分钟。
但是,.TOString()不会让您隐藏在这种情况下的分钟 - 如果这是您想要的,则必须将ZonedDateTime转换为Plaindate:
所有时间日期时间值都有.tojson()方法,因此可以串联到JSON:
const zdt = temporal.zoneddatetime.from(' 2019-12-01T12:00 [亚洲/新加坡]'); //直接严格完成分区日期时间:assert.equal(json.stringify(zdt),'" 2019-12-01T12:00:00 + 08:00 [亚洲/新加坡]" '); //严格在对象内进行分区日期时间:const obj = {:zdt}; assert.equal(json.stringify(obj),' {" starttime":" 2019- 12-01T12:00:00 + 08:00 [亚洲/新加坡]"}');
如果要使用日期时间值解析JSON,则需要设置JSON REVIVER。
时间的支持将日期时间值转换为人类可读字符串类似于Intl.dateTimeFormat的:
const zdt = temporal.zoneddatetime.from(' 2019-12-01T12:00 [欧洲/柏林]'); assert.equal(zdt.tolocalestring(),' 12/1/2019 ,12:00:00 GMT + 1'); assert.equal(zdt.tolocalestring(' de-de'),' 1.12.2019,12:00:00 Mez&# 39;); assert.equal(zdt.tolocalestring(' en-gb' {:' long':' numeric&#39 ;,:' long& #39;,:'数字',}),2019年12月1日星期日和#39;);
另一方面,Instant公开的一个字段为我们提供了以毫秒为单位的时间 - 我们可以使用它来创建日期:
大多数日期时间课程支持丰富的字段,如.dayofweek,.month和.calendar。值得注意的异常是即时的,其时区和日历是固定的,其设置和状态基于时代时间。
在所有其他日期时间类中,我们可以使用静态出厂函数.from()来配置实例:
const zoneddatetime = temporal.zoneddatetime.from({:'非洲/拉各斯':1995,:12,:12,:7,:3,:3,:3,:3::30,:0,:3,:500,} ); assert.equal(zoneddatetime.tostring(),' 1995-12-07T03:24:30.0000035 + 01:00 [非洲/拉古斯]');
如果我们想更改字段,我们需要通过.with():
const dates = [temporal.zoneddateTeme.from(' 2022-12-01t12:00 [亚洲/德黑兰]'),yourthalal.zoneddatetime.from(' 2001-12-01T12:00 [亚洲/德黑兰]'),临时.zoneddatetime.from(' 2009-12-01t12:00 [亚洲/德黑兰]'),]; dates.sort(temporal.zoneddatetime.com摊) ; assert.deepequal(dates.map(d => d.tostring()),[' 2001-12-01T12:00:00 + 03:30 [亚洲/德黑兰]&#39 ;,&# 39; 2009-12-01T12:00:00 + 03:30 [亚洲/德黑兰]&#39 ;,' 2022-12-01T12:00:00 + 03:30 [亚洲/德黑兰]&#39 ;,]);
const Instant = temporal.instant.from(' 1970-01-01T00:00:01Z'); const zoneddatetime = Instant.tozoneddatetemeiso('欧洲/马德里'); assert.equal(zoneddatetime.tostring(),' 1970-01-01t01:00:01 + 01:00 [欧洲/马德里]'); const plaindatetetime1 = zoneddatetime.toplaindatetime(); serret.equal(plaindatetime1.tostring(),' 1970-01-01t01:00:01'); const timezone = temporal .timezone.from('欧洲/马德里'); const plaindatetetime2 = timezone.getplaindateTemefor(即时); assert.equal(plaindatetime2.tostring(),' 1970-01-01T01:00:01');
const zoneddatetime = temporal.zoneddatetime.from(' 2019-12-01T12:00 [欧洲/明斯克]'); const Instant = zoneddatetime.toinstant(); assert.equal(Instant.tostring(),' 2019-12-01T09:00:00:00Z'); const plaindatetime = zoneddatetime.toplaindatetime(); assert.equal(plaindateTeme.tostring(),' 2019-12-01T12:00:00');
const plaindatetetime = temporal.plaindatetime。(' 1995-12-07T03:24:30'); const zoneddatetime = plaindateTime.tozoneddatetime('欧洲/柏林'); assert.equal(zoneddatetime.tostring(),' 1995-12-07T03:24:30 + 01:00 [欧洲/柏林]'); const Instant = zoneddatetime.toinstant(); assert.equal(Instant.tostring(),' 1995-12-07T02:24:30z');
const secoverure = temporal.zoneddatetime.from(' 2017-05-08T12:55 [欧洲/柏林]'); //慕尼黑const aslival = temporal.zoneddatetime.from(' 2017-05-08T17:10 [美国/ Los_Angeles]'); //西雅图Const飞行时间=出发。intilt.until(抵达); assert.equal(飞行时间.Tostring(),' pt13h15m');
为了计算劳动节(9月份的第一个星期一),我们需要弄清楚待加入9月1日的数天,以便到达工作日1(星期一)。
const mod =(a,b)=> ((A%b)+ b)%b;功能(年){const firstofseptember = temporal.plaindate.from({年,:9,:1,}); //到周一到几天了? const monday = 1; Const Daystoadd = Mod(星期一 - Firstofseptember.Dayofweek,7);返回firstofseptember.add({:daystoadd}); issert.equal(getlaborday(2021).tostring(),' 2021-09-06'); assert.equal(getlaborday(2022).tostring( ),' 2022-09-05');
虽然这一提议' s api未被预期更改,但该提案的实施者在IETF标准化时区/日历字符串序列化格式之前,该提案的实施者不得发出未发布的时间实现。查看#1450更新。
提案链接到合金。警告:聚填充适用于与API一起使用,但它应该被认为已被认为已被贬值(通过更好的实现替换)而不是在生产中使用。
官方时间文档目前在GitHub上托管,但最终将被移动到MDN Web Docs。
遗留日期API在“不耐烦程序员JavaScript”书籍“JavaScript”的一章中。