Last active
March 13, 2022 00:39
-
-
Save adriengibrat/e0b6d16cdd8c584392d8 to your computer and use it in GitHub Desktop.
Parse ISO 8601 duration as function that sums duration to a given date
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "parseDuration", | |
"version": "0.0.1", | |
"main": "./parseDuration.es5.js" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (name, definition) { | |
if (typeof module != 'undefined') module.exports = definition(); | |
else if (typeof define == 'function' && typeof define.amd == 'object') define(name, [], definition); | |
else this[name] = definition(); | |
}('parseDuration', function () { | |
/** | |
* Parse ISO 8601 duration (with a few limitations) | |
* | |
* @example | |
* var aDayAgo = parseDuration('-P1D').add, yesterday = aDayAgo(new Date()); | |
* | |
* @param {String} duration: ISO 8601 duration, only in "PnYnMnDTnHnMnS" or "PnW" formats, n being an integer | |
* @throws {Error} When duration cannot be parsed | |
* @returns {Function} That sums or substracts parsed duration to a given date, accorging duration sign | |
*/ | |
// see https://en.wikipedia.org/wiki/ISO_8601#Durations | |
var durationRegex = /^(-)?P(?:(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?|(\d+)W)$/; | |
return function parseDuration (duration) { | |
var parsed; | |
duration && duration.replace(durationRegex, function (_, sign, year, month, day, hour, minute, second, week) { | |
sign = sign ? -1 : 1; | |
// parse number for each unit | |
var units = [year, month, day, hour, minute, second, week].map(function (num) { return parseInt(num, 10) * sign || 0; }); | |
parsed = {year: units[0], month: units[1], week: units[6], day: units[2], hour: units[3], minute: units[4], second: units[5]}; | |
}); | |
// no regexp match | |
if (!parsed) { throw new Error('Invalid duration "' + duration + '"'); } | |
/** | |
* Sum or substract parsed duration to date | |
* | |
* @param {Date} date: A valid date instance | |
* @throws {TypeError} When date is not valid | |
* @returns {Date} Date plus or minus duration, according duration sign | |
*/ | |
parsed.add = function add (date) { | |
if (Object.prototype.toString.call(date) !== '[object Date]' || isNaN(date.valueOf())) { | |
throw new TypeError('Invalide date'); | |
} | |
return new Date(Date.UTC( | |
date.getUTCFullYear() + parsed.year, | |
date.getUTCMonth() + parsed.month, | |
date.getUTCDate() + parsed.day + parsed.week * 7, | |
date.getUTCHours() + parsed.hour, | |
date.getUTCMinutes() + parsed.minute, | |
date.getUTCSeconds() + parsed.second, | |
date.getUTCMilliseconds() | |
)); | |
}; | |
return parsed; | |
}; | |
})); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Parse ISO 8601 duration (with a few limitations) | |
* | |
* @example | |
* let aDayAgo = parseDuration('-P1D').add, yesterday = aDayAgo(new Date()); | |
* | |
* @param {String} duration: ISO 8601 duration, only in "PnYnMnDTnHnMnS" or "PnW" formats, n being an integer | |
* @throws {Error} When duration cannot be parsed | |
* @returns {Object} Parsed duration with "add" method that sums or substracts parsed duration to a given date, accorging duration sign | |
*/ | |
// see https://en.wikipedia.org/wiki/ISO_8601#Durations | |
let durationRegex = /^(-)?P(?:(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?|(\d+)W)$/; | |
export default function parseDuration (duration) { | |
let parsed; | |
duration && duration.replace(durationRegex, (_, sign, ...units) => { | |
sign = sign ? -1 : 1; | |
// parse number for each unit | |
let [year, month, day, hour, minute, second, week] = units.map((num) => parseInt(num, 10) * sign || 0); | |
parsed = {year, month, week, day, hour, minute, second}; | |
}); | |
// no regexp match | |
if (!parsed) { throw new Error(`Invalid duration "${duration}"`); } | |
return Object.assign(parsed, { | |
/** | |
* Sum or substract parsed duration to date | |
* | |
* @param {Date} date: Any valid date | |
* @throws {TypeError} When date is not valid | |
* @returns {Date} New date with duration difference | |
*/ | |
add(date) { | |
if (Object.prototype.toString.call(date) !== '[object Date]' || isNaN(date.valueOf())) { | |
throw new TypeError('Invalide date'); | |
} | |
return new Date(Date.UTC( | |
date.getUTCFullYear() + parsed.year, | |
date.getUTCMonth() + parsed.month, | |
date.getUTCDate() + parsed.day + parsed.week * 7, | |
date.getUTCHours() + parsed.hour, | |
date.getUTCMinutes() + parsed.minute, | |
date.getUTCSeconds() + parsed.second, | |
date.getUTCMilliseconds() | |
)); | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment