Как я могу преобразовать продолжительность с помощью JavaScript, например:
PT16H30M
Как я могу преобразовать продолжительность с помощью JavaScript, например:
PT16H30M
Теоретически вы можете получить продолжительность ISO8601, которая выглядит следующим образом:
P1Y4M3W2DT10H31M3.452S
Я написал следующее регулярное выражение, чтобы разбить это на группы:
(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?
Это не очень красиво, и кто-то, кто лучше разбирается в регулярных выражениях, может написать лучше.
Группы сводятся к следующему:
Я написал следующую функцию, чтобы преобразовать его в красивый объект:
var iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
window.parseISO8601Duration = function (iso8601Duration) {
var matches = iso8601Duration.match(iso8601DurationRegex);
return {
sign: matches[1] === undefined ? '+' : '-',
years: matches[2] === undefined ? 0 : matches[2],
months: matches[3] === undefined ? 0 : matches[3],
weeks: matches[4] === undefined ? 0 : matches[4],
days: matches[5] === undefined ? 0 : matches[5],
hours: matches[6] === undefined ? 0 : matches[6],
minutes: matches[7] === undefined ? 0 : matches[7],
seconds: matches[8] === undefined ? 0 : matches[8]
};
};
Используется следующим образом:
window.parseISO8601Duration('P1Y4M3W2DT10H31M3.452S');
Надеюсь, это поможет кому-то там.
Если вы используете momentjs, они имеют доступную функцию синтаксического анализа длительности ISO8601. Вам понадобится плагин для его форматирования, и, похоже, он не обрабатывает продолжительность недели, указанные в периоде на момент написания этой заметки.
P1D
является допустимой продолжительностью, поэтому не следует ожидать T
внутри регулярного выражения. Вот более правильное регулярное выражение: (-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?(?:T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?)?
- person Ser; 25.05.2018
Я только что сделал это для длительности даже более года.
Вот скрипка.
function convertDuration(t){
//dividing period from time
var x = t.split('T'),
duration = '',
time = {},
period = {},
//just shortcuts
s = 'string',
v = 'variables',
l = 'letters',
// store the information about ISO8601 duration format and the divided strings
d = {
period: {
string: x[0].substring(1,x[0].length),
len: 4,
// years, months, weeks, days
letters: ['Y', 'M', 'W', 'D'],
variables: {}
},
time: {
string: x[1],
len: 3,
// hours, minutes, seconds
letters: ['H', 'M', 'S'],
variables: {}
}
};
//in case the duration is a multiple of one day
if (!d.time.string) {
d.time.string = '';
}
for (var i in d) {
var len = d[i].len;
for (var j = 0; j < len; j++) {
d[i][s] = d[i][s].split(d[i][l][j]);
if (d[i][s].length>1) {
d[i][v][d[i][l][j]] = parseInt(d[i][s][0], 10);
d[i][s] = d[i][s][1];
} else {
d[i][v][d[i][l][j]] = 0;
d[i][s] = d[i][s][0];
}
}
}
period = d.period.variables;
time = d.time.variables;
time.H += 24 * period.D +
24 * 7 * period.W +
24 * 7 * 4 * period.M +
24 * 7 * 4 * 12 * period.Y;
if (time.H) {
duration = time.H + ':';
if (time.M < 10) {
time.M = '0' + time.M;
}
}
if (time.S < 10) {
time.S = '0' + time.S;
}
duration += time.M + ':' + time.S;
alert(duration);
}
В частности, решение строки DateTime которые можно использовать в тегах HTML5 <time/>
, поскольку они ограничены днями, минутами и секундами (поскольку только они могут быть преобразованы в точное количество секунд, поскольку месяцы и годы могут иметь разную продолжительность)
function parseDurationString( durationString ){
var stringPattern = /^PT(?:(\d+)D)?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d{1,3})?)S)?$/;
var stringParts = stringPattern.exec( durationString );
return (
(
(
( stringParts[1] === undefined ? 0 : stringParts[1]*1 ) /* Days */
* 24 + ( stringParts[2] === undefined ? 0 : stringParts[2]*1 ) /* Hours */
)
* 60 + ( stringParts[3] === undefined ? 0 : stringParts[3]*1 ) /* Minutes */
)
* 60 + ( stringParts[4] === undefined ? 0 : stringParts[4]*1 ) /* Seconds */
);
}
Тестовые данные
"PT1D" returns 86400
"PT3H" returns 10800
"PT15M" returns 900
"PT1D12H30M" returns 131400
"PT1D3M15.23S" returns 86595.23
Moment.js выпущен с поддержкой продолжительности версии 2.3.
const iso8601Duration = "PT16H30M"
moment.duration(iso8601Duration)
// -> { _data: { days: 0, hours: 16, milliseconds: 0, minutes: 30, months: 0, seconds: 0, years: 0} ...
moment.duration(iso8601Duration).asSeconds()
// -> 59400
Подробнее https://momentjs.com/docs/#/durations/ .
Завернул небольшой пакет, чтобы облегчить это:
import { parse, serialize } from 'tinyduration';
// Basic parsing
const durationObj = parse('P1Y2M3DT4H5M6S');
assert(durationObj, {
years: 1,
months: 2,
days: 3,
hours: 4,
minutes: 5,
seconds: 6
});
// Serialization
assert(serialize(durationObj), 'P1Y2M3DT4H5M6S');
Установить с помощью npm install --save tinyduration
или yarn add tinyduration
См.: https://www.npmjs.com/package/tinyduration.
Базовое решение для поддержки периода ISO8601.
Из-за отсутствия типа «длительность» в JavaScript и странной семантики дат, здесь используется арифметика дат для применения «периода» к дате «привязки» (по умолчанию используются текущие дата и время). По умолчанию добавляется период.
Укажите назад: true, чтобы указать дату в прошлом.
// 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;
}
Нет гарантии. Это может иметь особенности - проверьте свой вариант использования.