(value: string)
| 259 | * @returns A DateTimeDuration object. |
| 260 | */ |
| 261 | export function parseDuration(value: string): Required<DateTimeDuration> { |
| 262 | const match = value.match(DATE_TIME_DURATION_RE); |
| 263 | |
| 264 | if (!match) { |
| 265 | throw new Error(`Invalid ISO 8601 Duration string: ${value}`); |
| 266 | } |
| 267 | |
| 268 | const parseDurationGroup = (group: string | undefined, isNegative: boolean): number => { |
| 269 | if (!group) { |
| 270 | return 0; |
| 271 | } |
| 272 | try { |
| 273 | const sign = isNegative ? -1 : 1; |
| 274 | return sign * Number(group.replace(',', '.')); |
| 275 | } catch { |
| 276 | throw new Error(`Invalid ISO 8601 Duration string: ${value}`); |
| 277 | } |
| 278 | }; |
| 279 | |
| 280 | const isNegative = !!match.groups?.negative; |
| 281 | |
| 282 | const hasRequiredGroups = requiredDurationGroups.some(group => match.groups?.[group]); |
| 283 | |
| 284 | if (!hasRequiredGroups) { |
| 285 | throw new Error(`Invalid ISO 8601 Duration string: ${value}`); |
| 286 | } |
| 287 | |
| 288 | const durationStringIncludesTime = match.groups?.time; |
| 289 | |
| 290 | if (durationStringIncludesTime) { |
| 291 | const hasRequiredDurationTimeGroups = requiredDurationTimeGroups.some( |
| 292 | group => match.groups?.[group] |
| 293 | ); |
| 294 | if (!hasRequiredDurationTimeGroups) { |
| 295 | throw new Error(`Invalid ISO 8601 Duration string: ${value}`); |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | const duration: Mutable<DateTimeDuration> = { |
| 300 | years: parseDurationGroup(match.groups?.years, isNegative), |
| 301 | months: parseDurationGroup(match.groups?.months, isNegative), |
| 302 | weeks: parseDurationGroup(match.groups?.weeks, isNegative), |
| 303 | days: parseDurationGroup(match.groups?.days, isNegative), |
| 304 | hours: parseDurationGroup(match.groups?.hours, isNegative), |
| 305 | minutes: parseDurationGroup(match.groups?.minutes, isNegative), |
| 306 | seconds: parseDurationGroup(match.groups?.seconds, isNegative) |
| 307 | }; |
| 308 | |
| 309 | if ( |
| 310 | duration.hours !== undefined && |
| 311 | duration.hours % 1 !== 0 && |
| 312 | (duration.minutes || duration.seconds) |
| 313 | ) { |
| 314 | throw new Error( |
| 315 | `Invalid ISO 8601 Duration string: ${value} - only the smallest unit can be fractional` |
| 316 | ); |
| 317 | } |
| 318 |
no test coverage detected