在python中解析日期而不使用默认值

Mar*_*zzi 13 python python-dateutil

我正在使用python的dateutil.parser工具来解析我从第三方提要获得的一些日期.它允许指定一个默认日期,它本身默认为今天,用于填充已解析日期的缺失元素.虽然这通常很有用,但我的用例没有合理的默认值,我宁愿将部分日期视为我根本没有得到日期(因为它几乎总是意味着我的数据乱码).我写了以下工作:

from dateutil import parser
import datetime

def parse_no_default(dt_str):
  dt = parser.parse(dt_str, default=datetime.datetime(1900, 1, 1)).date()
  dt2 = parser.parse(dt_str, default=datetime.datetime(1901, 2, 2)).date()
  if dt == dt2:
    return dt
  else:
    return None
Run Code Online (Sandbox Code Playgroud)

(这个片段只查看日期,因为我只关心我的应用程序,但类似的逻辑可以扩展到包含时间组件.)

我想知道(希望)有更好的方法.解析相同的字符串两次只是为了看它是否填写不同的默认值似乎是浪费资源,至少可以说.

这是针对预期行为的一组测试(使用nosetest生成器):

import nose.tools
import lib.tools.date

def check_parse_no_default(sample, expected):
  actual = lib.tools.date.parse_no_default(sample)
  nose.tools.eq_(actual, expected)

def test_parse_no_default():
  cases = ( 
      ('2011-10-12', datetime.date(2011, 10, 12)),
      ('2011-10', None),
      ('2011', None),
      ('10-12', None),
      ('2011-10-12T11:45:30', datetime.date(2011, 10, 12)),
      ('10-12 11:45', None),
      ('', None),
      )   
  for sample, expected in cases:
    yield check_parse_no_default, sample, expected
Run Code Online (Sandbox Code Playgroud)

ILY*_*tov 8

根据您的域,以下解决方案可能有效:

DEFAULT_DATE = datetime.datetime(datetime.MINYEAR, 1, 1)

def parse_no_default(dt_str):    
    dt = parser.parse(dt_str, default=DEFAULT_DATE).date()
    if dt != DEFAULT_DATE:
       return dt
    else:
       return None
Run Code Online (Sandbox Code Playgroud)

另一种方法是猴子补丁解析器类(这是非常hackiesh,所以如果你有其他选择,我不会推荐它):

import dateutil.parser as parser
def parse(self, timestr, default=None,
          ignoretz=False, tzinfos=None,
          **kwargs):
    return self._parse(timestr, **kwargs)
parser.parser.parse = parse
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式使用它:

>>> ddd = parser.parser().parse('2011-01-02', None)
>>> ddd
_result(year=2011, month=01, day=02)
>>> ddd = parser.parser().parse('2011', None)
>>> ddd
_result(year=2011)
Run Code Online (Sandbox Code Playgroud)

通过检查结果(ddd)中可用的成员,您可以确定何时返回None.当所有字段都可用时,您可以将ddd转换为datetime对象:

# ddd might have following fields:
# "year", "month", "day", "weekday",
# "hour", "minute", "second", "microsecond",
# "tzname", "tzoffset"
datetime.datetime(ddd.year, ddd.month, ddd.day)
Run Code Online (Sandbox Code Playgroud)