ISO 8601时期支持的基本解决方案。 由于JavaScript中缺少'duration'类型和奇怪的日期语义,它使用日期算法将'period'应用于'锚'日期(默认为当前日期和时间)。默认为添加period。 指定之前:false提供过去的日期。
// Adds ISO8601 period: P<dateparts>(T<timeparts>)?
// E.g. period 1 year 3 months 2 days: P1Y3M2D
// E.g. period 1H: PT1H
// E.g. period 2 days 12 hours: P2DT12H
// @param period string: ISO8601 period string
// @param ago bool [optiona] true: Subtract the period, false: add (Default)
// @param anchor Date [optional] Anchor date for period, default is current date
function addIso8601Period(period /*:string */, ago /*: bool? */, anchor /*: Date? */) {
var re = /^P((?<y>\d+)Y)?((?<m>\d+)M)?((?<d>\d+)D)?(T((?<th>\d+)H)?((?<tm>\d+)M)?((?<ts>\d+(.\d+)?)S)?)?$/;
var match = re.exec(period);
var direction = ago || false ? -1 : 1;
anchor = new Date(anchor || new Date());
anchor.setFullYear(anchor.getFullYear() + (match.groups['y'] || 0) * direction);
anchor.setMonth(anchor.getMonth() + (match.groups['m'] || 0) * direction);
anchor.setDate(anchor.getDate() + (match.groups['d'] || 0) * direction);
anchor.setHours(anchor.getHours() + (match.groups['th'] || 0) * direction);
anchor.setMinutes(anchor.getMinutes() + (match.groups['tm'] || 0) * direction);
anchor.setSeconds(anchor.getSeconds() + (match.groups['ts'] || 0) * direction);
return anchor;
}
const durationExp = /^(?<sign>\+|-)?P((?<Y>\d+)Y)?((?<M>\d+)M)?((?<D>\d+)D)?T((?<H>\d+)H)?((?<m>\d+)M)?((?<S>\d+(\.\d+))?S)?$/
/**
* # applyISODuration
* Apply ISO 8601 duration string to given date
* - **duration** must be a strng compliant with ISO 8601 duration
* /!\ it doesn't support the Week parameter but it can easily be replaced by adding a number of days
* - **date** can be omit and will then default to Date.now()
* It can be any valid value for Date constructor so you can pass date
* as strings or number as well as Date object
* returns a new Date with the duration applied
*/
const applyISODuration = (duration/*:string*/, date/*?: Date|string|number*/) => {
date = date ? new Date(date) : new Date()
const parts = duration.match(durationExp)?.groups
if (!parts) {
throw new Error(`Invalid duration(${duration})`)
}
const addOrSubstract = parts.sign === '-' ? (value) => -value : (value) => +value;
parts.Y && date.setFullYear(date.getFullYear() + addOrSubstract(parts.Y))
parts.M && date.setMonth(date.getMonth() + addOrSubstract(parts.M))
parts.D && date.setDate(date.getDate() + addOrSubstract(parts.D))
parts.H && date.setHours(date.getHours() + addOrSubstract(parts.H))
parts.m && date.setMinutes(date.getMinutes() + addOrSubstract(parts.m))
parts.s && date.setSeconds(date.getSeconds() + addOrSubstract(parseFloat(parts.S)))
return date
}
使用方法:
applyISODuration('P2DT12H5.555S')
applyISODuration('P2DT12H5.555S', new Date("2022-06-23T09:52:38.298Z") )
const { Duration } = require('luxon');
// Parse an ISO 8601 duration string
const duration = Duration.fromISO('P3Y6M4DT12H30M5S');
// Print the total number of seconds in the duration
console.log(duration.as('seconds'));
9条答案
按热度按时间63lcw9qa1#
理论上,您可以得到如下所示的ISO8601持续时间:
P1Y4M3W2DT10H31M3.452S
我编写了以下正则表达式来将其解析为组:
它并不漂亮,更精通正则表达式的人可能会写一个更好的。
这些组可归结为以下几类:
1.标志
1.年数
1.月数
1.周数
1.天数
1.小时数
1.会议记录
1.秒数
我编写了以下函数将其转换为一个nice对象:
这样使用:
希望这对外面的人有帮助。
更新
如果你使用的是momentjs,他们有ISO8601持续时间解析功能,你需要一个plugin to format,它似乎不能处理在写这篇笔记时指定的周数。
von4xj4u2#
Moment.js随2.3版本发布,支持持续时间。
更多信息请访问https://momentjs.com/docs/#/durations/。
o4tp2gmn3#
r8uurelv4#
包了一个小包裹,以方便这一点:
使用
npm install --save tinyduration
或yarn add tinyduration
安装请参阅:https://www.npmjs.com/package/tinyduration
qyzbxkaa5#
我刚刚这样做的持续时间,甚至超过一年之久。
这是一个fiddle。
vnjpjtjt6#
特别是解决可在HTML5
<time/>
标签中使用的DateTime字符串,因为它们被限制为Days、Minutes和Seconds(因为只有这些字符串可以转换为精确的秒数,因为Months和Years可以有不同的持续时间)测试数据
mo49yndu7#
ISO 8601时期支持的基本解决方案。
由于JavaScript中缺少'duration'类型和奇怪的日期语义,它使用日期算法将'period'应用于'锚'日期(默认为当前日期和时间)。默认为添加period。
指定之前:false提供过去的日期。
没有保修。这可能有怪癖-测试您的用例。
a14dhokn8#
这是James Caradoc-Davies提出的解决方案的更新
使用方法:
gdrx4gfi9#
或者,您可以使用luxon程式库中的
Duration.fromISO
方法。以下是如何使用它的示例:
这将记录持续时间的总秒数,在本例中为“117536305”。
请注意,luxon库是Moment project btw的一部分。