【问题标题】:How to parse xsd:dateTime format?如何解析 xsd:dateTime 格式?
【发布时间】:2010-02-06 00:11:09
【问题描述】:

xsd:dateTime 类型的值可以有多种形式,如described in RELAX NG

如何将所有表单解析为时间或日期时间对象?

【问题讨论】:

  • 您是在问如何用datetime.datetime.strptime 解析[-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]?还是有更多内容不在参考页面上?
  • @S.Lott:稍微多一点或者该页面有误,因为它显示微秒作为有效输入(朝向底部)。

标签: python xml


【解决方案1】:

它实际上是一种非常受限制的格式,尤其是与所有 ISO 8601 相比。使用正则表达式与使用 strptime 基本相同,加上自己处理偏移量(strptime 不这样做)。

import datetime
import re

def parse_timestamp(s):
  """Returns (datetime, tz offset in minutes) or (None, None)."""
  m = re.match(""" ^
    (?P<year>-?[0-9]{4}) - (?P<month>[0-9]{2}) - (?P<day>[0-9]{2})
    T (?P<hour>[0-9]{2}) : (?P<minute>[0-9]{2}) : (?P<second>[0-9]{2})
    (?P<microsecond>\.[0-9]{1,6})?
    (?P<tz>
      Z | (?P<tz_hr>[-+][0-9]{2}) : (?P<tz_min>[0-9]{2})
    )?
    $ """, s, re.X)
  if m is not None:
    values = m.groupdict()
    if values["tz"] in ("Z", None):
      tz = 0
    else:
      tz = int(values["tz_hr"]) * 60 + int(values["tz_min"])
    if values["microsecond"] is None:
      values["microsecond"] = 0
    else:
      values["microsecond"] = values["microsecond"][1:]
      values["microsecond"] += "0" * (6 - len(values["microsecond"]))
    values = dict((k, int(v)) for k, v in values.iteritems()
                  if not k.startswith("tz"))
    try:
      return datetime.datetime(**values), tz
    except ValueError:
      pass
  return None, None

不处理将时区偏移应用于日期时间,负年份是日期时间的问题。这两个问题都可以通过处理 xsd:dateTime 所需的全部范围的不同时间戳类型来解决。

valid = [
  "2001-10-26T21:32:52",
  "2001-10-26T21:32:52+02:00",
  "2001-10-26T19:32:52Z",
  "2001-10-26T19:32:52+00:00",
  #"-2001-10-26T21:32:52",
  "2001-10-26T21:32:52.12679",
]
for v in valid:
  print
  print v
  r = parse_timestamp(v)
  assert all(x is not None for x in r), v

  # quick and dirty, and slightly wrong
  # (doesn't distinguish +00:00 from Z among other issues)
  # but gets through the above cases

  tz = ":".join("%02d" % x for x in divmod(r[1], 60)) if r[1] else "Z"
  if r[1] > 0: tz = "+" + tz
  r = r[0].isoformat() + tz

  print r
  assert r.startswith(v[:len("CCYY-MM-DDThh:mm:ss")]), v

print "---"
invalid = [
  "2001-10-26",
  "2001-10-26T21:32",
  "2001-10-26T25:32:52+02:00",
  "01-10-26T21:32",
]
for v in invalid:
  print v
  r = parse_timestamp(v)
  assert all(x is None for x in r), v

【讨论】:

    【解决方案2】:

    尝试python-dateutil 中的dateutil.parser 模块。或者isodate(还没有使用最后一个,但看起来很有趣(并且专门用于解析 ISO 8601 格式)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      相关资源
      最近更新 更多