parse 静态方法

DateTime parse(
  1. String formattedString
)

根据 formattedString 构造一个新的 DateTime 实例。

如果输入字符串无法解析,则抛出 FormatException

该函数解析 ISO 8601 的子集,包括 RFC 3339 接受的子集。

目前接受的输入包括

  • 日期:带符号的四到六位年份,两位月份和两位日期,可选地由 - 字符分隔。例如:"19700101","-0004-12-24","81030-04-01"。
  • 可选的时间部分,由 T 或空格与日期分隔。时间部分是两位数字的小时,然后是可选的两位分钟值,然后是可选的两位秒值,然后是可选的 '.' 或 ',' 后跟至少一位数字的秒分数。分钟和秒可以由 ':' 与前面的部分分隔。例如:"12","12:30:24.124","12:30:24,124","123010.50"。
  • 可选的时间区域偏移部分,可能由空格与前面的部分分隔。时区是 'z' 或 'Z',或者是带符号的两位数字的小时部分和可选的两位数字的分钟部分。符号必须是 "+" 或 "-",不能省略。分钟可以由小时分隔。例如:"Z","-10","+01:30","+1130"。

这包括 toStringtoIso8601String 的输出,这些输出将被解析回具有与原始相同的时间的 DateTime 对象。

结果总是本地时间或 UTC。如果指定了非 UTC 的时间区域偏移量,则将时间转换为等效的 UTC 时间。

接受字符串的示例

  • "2012-02-27"
  • "2012-02-27 13:27:00"
  • "2012-02-27 13:27:00.123456789z"
  • "2012-02-27 13:27:00,123456789z"
  • "20120227 13:27:00"
  • "20120227T132700"
  • "20120227"
  • "+20120227"
  • "2012-02-27T14Z"
  • "2012-02-27T14+00:00"
  • "-123450101 00:00:00 Z":在 -12345 年。
  • "2002-02-27T14:00:00-0500":与 "2002-02-27T19:00:00Z" 相同。

此方法接受超出范围的组件值,并将它们解释为溢出到下一个较大的组件。例如,"2020-01-42" 将被解析为 2020-02-11,因为那个月的最后有效日期是 2020-01-31,所以 42 天被解释为那个月的 31 天加上下一个月的 11 天。

要检测和拒绝无效的组件值,请使用来自 intl 包的 DateFormat.parseStrict

实现

static DateTime parse(String formattedString) {
  var re = _parseFormat;
  Match? match = re.firstMatch(formattedString);
  if (match != null) {
    int parseIntOrZero(String? matched) {
      if (matched == null) return 0;
      return int.parse(matched);
    }

    // Parses fractional second digits of '.(\d+)' into the combined
    // microseconds. We only use the first 6 digits because of DateTime
    // precision of 999 milliseconds and 999 microseconds.
    int parseMilliAndMicroseconds(String? matched) {
      if (matched == null) return 0;
      int length = matched.length;
      assert(length >= 1);
      int result = 0;
      for (int i = 0; i < 6; i++) {
        result *= 10;
        if (i < matched.length) {
          result += matched.codeUnitAt(i) ^ 0x30;
        }
      }
      return result;
    }

    int years = int.parse(match[1]!);
    int month = int.parse(match[2]!);
    int day = int.parse(match[3]!);
    int hour = parseIntOrZero(match[4]);
    int minute = parseIntOrZero(match[5]);
    int second = parseIntOrZero(match[6]);
    int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
    int millisecond =
        milliAndMicroseconds ~/ Duration.microsecondsPerMillisecond;
    int microsecond = milliAndMicroseconds
        .remainder(Duration.microsecondsPerMillisecond) as int;
    bool isUtc = false;
    if (match[8] != null) {
      // timezone part
      isUtc = true;
      String? tzSign = match[9];
      if (tzSign != null) {
        // timezone other than 'Z' and 'z'.
        int sign = (tzSign == '-') ? -1 : 1;
        int hourDifference = int.parse(match[10]!);
        int minuteDifference = parseIntOrZero(match[11]);
        minuteDifference += 60 * hourDifference;
        minute -= sign * minuteDifference;
      }
    }
    DateTime? result = _finishParse(years, month, day, hour, minute, second,
        millisecond, microsecond, isUtc);
    if (result == null) {
      throw FormatException("Time out of range", formattedString);
    }
    return result;
  } else {
    throw FormatException("Invalid date format", formattedString);
  }
}