@typespec/http-server-js
Version:
TypeSpec HTTP server code generator for JavaScript
151 lines • 6.39 kB
JavaScript
// Copyright (c) Microsoft Corporation
// Licensed under the MIT license.
// #region Duration
/**
* Regular expression for matching ISO8601 duration strings.
*
* Yields:
* - 0: the full match
* - 1: the sign (optional)
* - 2: years (optional)
* - 3: months (optional)
* - 4: weeks (optional)
* - 5: days (optional)
* - 6: hours (optional)
* - 7: minutes (optional)
* - 8: seconds (optional)
*/
const ISO8601_DURATION_REGEX = /^(-)?P(?:((?:\d*[.,])?\d+)Y)?(?:((?:\d*[.,])?\d+)M)?(?:((?:\d*[.,])?\d+)W)?(?:((?:\d*[.,])?\d+)D)?(?:T(?:((?:\d*[.,])?\d+)H)?(?:((?:\d*[.,])?\d+)M)?(?:((?:\d*[.,])?\d+)S)?)?$/;
export const Duration = Object.freeze({
/**
* Parses an ISO8601 duration string into an object.
*
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations
*
* @param duration - the duration string to parse
* @returns an object containing the parsed duration
*/
parseISO8601(duration, maxLength = 100) {
duration = duration.trim();
if (duration.length > maxLength)
throw new Error(`ISO8601 duration string is too long: ${duration}`);
const match = duration.match(ISO8601_DURATION_REGEX);
if (!match)
throw new Error(`Invalid ISO8601 duration: ${duration}`);
return {
sign: match[1] === undefined ? "+" : match[1],
years: parseFloatNormal(match[2]),
months: parseFloatNormal(match[3]),
weeks: parseFloatNormal(match[4]),
days: parseFloatNormal(match[5]),
hours: parseFloatNormal(match[6]),
minutes: parseFloatNormal(match[7]),
seconds: parseFloatNormal(match[8]),
};
function parseFloatNormal(match) {
if (match === undefined)
return 0;
const normalized = match.replace(",", ".");
const parsed = parseFloat(normalized);
if (isNaN(parsed))
throw new Error(`Unreachable: Invalid number in ISO8601 duration string: ${match}`);
return parsed;
}
},
/**
* Writes a Duration to an ISO8601 duration string.
*
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations
*
* @param duration - the duration to write to a string
* @returns a string in ISO8601 duration format
*/
toISO8601(duration) {
const sign = duration.sign === "+" ? "" : "-";
const years = duration.years !== 0 && !isNaN(Number(duration.years)) ? `${duration.years}Y` : "";
const months = duration.months !== 0 && !isNaN(Number(duration.months)) ? `${duration.months}M` : "";
const weeks = duration.weeks !== 0 && !isNaN(Number(duration.weeks)) ? `${duration.weeks}W` : "";
const days = duration.days !== 0 && !isNaN(Number(duration.days)) ? `${duration.days}D` : "";
let time = "";
const _hours = duration.hours !== 0 && !isNaN(Number(duration.hours));
const _minutes = duration.minutes !== 0 && !isNaN(Number(duration.minutes));
const _seconds = duration.seconds !== 0 && !isNaN(Number(duration.seconds));
if (_hours || _minutes || _seconds) {
const hours = _hours ? `${duration.hours}H` : "";
const minutes = _minutes ? `${duration.minutes}M` : "";
const seconds = _seconds ? `${duration.seconds}S` : "";
time = `T${hours}${minutes}${seconds}`;
}
return `${sign}P${years}${months}${weeks}${days}${time}`;
},
/**
* Gets the total number of seconds in a duration.
*
* This method will throw an Error if the duration contains any years, months, weeks, or days, as those require a reference
* point to calculate the total number of seconds.
*
* WARNING: If the total number of seconds is larger than the maximum safe integer in JavaScript, this method will
* lose precision. @see Duration.totalSecondsBigInt for a BigInt alternative.
*
* @param duration - the duration to calculate the total number of seconds for
* @returns the total number of seconds in the duration
*/
totalSeconds(duration) {
if (duration.years !== 0 ||
duration.months !== 0 ||
duration.weeks !== 0 ||
duration.days !== 0) {
throw new Error("Cannot calculate total seconds for a duration with years, months, weeks, or days.");
}
return (duration.seconds +
duration.minutes * 60 +
duration.hours * 60 * 60 +
duration.weeks * 7 * 24 * 60 * 60);
},
/**
* Gets the total number of seconds in a duration.
*
* This method will throw an Error if the duration contains any years, months, weeks, or days, as those require a reference
* point to calculate the total number of seconds. It will also throw an error if any of the components are not integers.
*
* @param duration - the duration to calculate the total number of seconds for
* @returns the total number of seconds in the duration
*/
totalSecondsBigInt(duration) {
if (duration.years !== 0 ||
duration.months !== 0 ||
duration.weeks !== 0 ||
duration.days !== 0) {
throw new Error("Cannot calculate total seconds for a duration with years, months, weeks, or days.");
}
if (!Number.isInteger(duration.seconds) ||
!Number.isInteger(duration.minutes) ||
!Number.isInteger(duration.hours) ||
!Number.isInteger(duration.weeks)) {
throw new Error("Cannot calculate total seconds as a BigInt for a duration with non-integer components.");
}
return (BigInt(duration.seconds) +
BigInt(duration.minutes) * 60n +
BigInt(duration.hours) * 60n * 60n +
BigInt(duration.weeks) * 7n * 24n * 60n * 60n);
},
/**
* Creates a duration from a total number of seconds.
*
* The result is not normalized, so it will only contain a seconds field.
*/
fromTotalSeconds(seconds) {
return {
sign: seconds < 0 ? "-" : "+",
years: 0,
months: 0,
weeks: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: Math.abs(seconds),
};
},
});
// #endregion
//# sourceMappingURL=datetime.js.map