tryParseIsoDateTime static method

DateTime? tryParseIsoDateTime(
  1. String value
)

Parses value as an ISO-8601 date or date-time, or returns null when it is not one.

The value must start with YYYY-MM-DD, and a time part may follow after a T or a space (HH, HH:mm, or HH:mm:ss, with optional fractional seconds and a Z or numeric offset).

This is deliberately stricter than DateTime.parse, which accepts unpunctuated runs such as 20240131 that are far more likely to be identifiers than dates, and which silently rolls impossible values over (2024-13-45 becomes 2025-02-14). Every field is range-checked first, so an impossible date or time stays text instead of becoming the wrong one.

Implementation

static DateTime? tryParseIsoDateTime(String value) {
  final len = value.length;
  // 'YYYY-MM-DD' at the shortest; a fractional offset date-time fits in 32.
  if (len < 10 || len > 40) return null;
  if (value.codeUnitAt(4) != _minus || value.codeUnitAt(7) != _minus) {
    return null;
  }
  final year = _twoOrFourDigits(value, 0, 4);
  final month = _twoOrFourDigits(value, 5, 7);
  final day = _twoOrFourDigits(value, 8, 10);
  if (year < 0 || month < 1 || month > 12) return null;
  if (day < 1 || day > _daysInMonth(year, month)) return null;

  if (len > 10) {
    final sep = value.codeUnitAt(10);
    if ((sep != _upperT && sep != _space) || len < 13) return null;
    final hour = _twoOrFourDigits(value, 11, 13);
    if (hour < 0 || hour > 23) return null;
    if (len > 13 && value.codeUnitAt(13) == _colon) {
      if (len < 16) return null;
      final minute = _twoOrFourDigits(value, 14, 16);
      if (minute < 0 || minute > 59) return null;
      if (len > 16 && value.codeUnitAt(16) == _colon) {
        if (len < 19) return null;
        final second = _twoOrFourDigits(value, 17, 19);
        if (second < 0 || second > 59) return null;
      }
    } else if (len > 13) {
      // Unpunctuated time (T0930): rejected, as the date part is.
      final c = value.codeUnitAt(13);
      if (c >= _zero && c <= _nine) return null;
    }
  }
  return DateTime.tryParse(value);
}