durationFromStringExtension top-level constant

String const durationFromStringExtension

Implementation

const durationFromStringExtension = r'''
extension DurationFromString on Duration {
  /// Parses an interval in Postgres' default IntervalStyle, such as
  /// "04:05:06.5", "3 days" or "1 year 2 mons -3 days +04:05:06".
  ///
  /// Months and years have no fixed length. As in Postgres' extract(epoch),
  /// a month counts as 30 days and a year as 365.25 days.
  static Duration fromString(String str) {
    final part = RegExp(r'([+-]?\d+) (year|mon|day)s?'
        r'|([+-]?)(\d+):(\d+):(\d+)(?:\.(\d+))?');
    if (str.replaceAll(part, '').trim().isNotEmpty) {
      throw FormatException('Unsupported interval format', str);
    }

    const day = Duration.microsecondsPerDay;
    var micros = 0;
    for (final m in part.allMatches(str)) {
      if (m[1] != null) {
        final n = int.parse(m[1]!);
        micros += switch (m[2]) {
          'year' => n * day * 1461 ~/ 4,
          'mon' => n * day * 30,
          _ => n * day,
        };
      } else {
        final fraction = (m[7] ?? '').padRight(6, '0').substring(0, 6);
        final time = int.parse(m[4]!) * Duration.microsecondsPerHour +
            int.parse(m[5]!) * Duration.microsecondsPerMinute +
            int.parse(m[6]!) * Duration.microsecondsPerSecond +
            int.parse(fraction);
        micros += m[3] == '-' ? -time : time;
      }
    }
    return Duration(microseconds: micros);
  }
}
''';