jsonDecodeDurationFromISO8601 function
Parses ISO 8601 duration format to a Duration.
ISO 8601 duration format is a standardized way to represent time periods using the format "PnYnMnWnDTnHnMnS" where:
- P: Period designator (required in strict ISO 8601, but optional for Y/M/W/D units in this implementation)
- n: Number of years, months, weeks, or days
- Y: Years
- M: Months (when before T) or Minutes (when after T)
- W: Weeks
- D: Days
- T: Time designator (separates date and time components)
- H: Hours
- M: Minutes (when after T)
- S: Seconds
This function supports combined date components (Y, M, W, D) without the time portion for simplicity. It's commonly used in:
- API specifications (OpenAPI, GraphQL)
- Configuration files
- Data serialization formats
- Calendar applications
- Business process modeling
- Legal documents and contracts
Examples:
- "P1Y" = 1 year (365 days)
- "P6M" = 6 months (180 days)
- "P2W" = 2 weeks (14 days)
- "P30D" = 30 days
- "P1Y6M" = 1 year 6 months (540 days)
- "P1Y6M2W3D" = 1 year 6 months 2 weeks 3 days (557 days)
- "1Y" = 1 year (365 days) - shorthand without 'P'
- "6M" = 6 months (180 days) - shorthand without 'P'
- "2W" = 2 weeks (14 days) - shorthand without 'P'
- "30D" = 30 days - shorthand without 'P'
Note: This implementation uses approximate conversions:
- 1 year = 365 days
- 1 month = 30 days
- 1 week = 7 days
- 1 day = 1 day
The leading 'P' is optional for Y/M/W/D units, providing ergonomic shorthand while maintaining compatibility with strict ISO 8601 format.
Returns Duration.zero for null, empty, or invalid input.
jsonDecodeDurationFromISO8601('P1Y'); // 365 days
jsonDecodeDurationFromISO8601('P6M'); // 180 days
jsonDecodeDurationFromISO8601('P2W'); // 14 days
jsonDecodeDurationFromISO8601('P30D'); // 30 days
jsonDecodeDurationFromISO8601('P1Y6M'); // 540 days
jsonDecodeDurationFromISO8601(null); // Duration.zero
@ai Use this function to parse ISO 8601 duration strings into Duration objects.
Implementation
Duration jsonDecodeDurationFromISO8601(final String? iso8601Duration) {
if (iso8601Duration == null || iso8601Duration.isEmpty) {
return Duration.zero;
}
// Accept strings with or without leading 'P'. Time portion (after 'T')
//is not supported.
final input = iso8601Duration.trim();
if (input.isEmpty) return Duration.zero;
if (input.contains('T')) {
return Duration.zero; // explicitly ignore time portion
}
final reg = RegExp(r'^P?(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?$');
final match = reg.firstMatch(input);
if (match == null) return Duration.zero;
int toInt(final String? s) => s == null ? 0 : int.tryParse(s) ?? 0;
final years = toInt(match.group(1));
final months = toInt(match.group(2));
final weeks = toInt(match.group(3));
final days = toInt(match.group(4));
// Negative values are not allowed (regex prevents '-' anyway),
//treat zero as Duration.zero.
final totalDays = years * 365 + months * 30 + weeks * 7 + days;
if (totalDays <= 0) return Duration.zero;
return Duration(days: totalDays);
}