【问题标题】:alternative to strptime for comparing dates?替代 strptime 来比较日期?
【发布时间】:2016-09-02 15:42:37
【问题描述】:

有没有什么方法可以比较两个日期而无需每次在 python 中调用 strptime?我确定我的问题没有其他办法,但我想确保我已经检查了所有选项。

我正在查看一个非常大的日志文件,每一行都有一个日期,我需要比较该日期以查看该日期是否在其他两个日期的范围内。我必须用 strptime 转换每一行的每个日期,这会导致很大的瓶颈;

Fri Sep  2 15:12:43 2016    output2.file

         63518075 function calls (63517618 primitive calls) in 171.409 seconds

   Ordered by: cumulative time
   List reduced from 571 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.003    0.003  171.410  171.410 script.py:3(<module>)
        1    0.429    0.429  171.367  171.367 scipt.py:1074(main)
        1    3.357    3.357  162.009  162.009 script.py:695(get_data)
  1569898   14.088    0.000  141.175    0.000 script.py:648(check_line)
  1569902    6.899    0.000   71.706    0.000 {built-in method strptime}
  1569902   31.198    0.000   64.805    0.000 /usr/lib64/python2.7/_strptime.py:295(_strptime)
  1569876   15.324    0.000   43.170    0.000 script.py:626(dict_add)
  4709757   23.370    0.000   23.370    0.000 {method 'strftime' of 'datetime.date' objects}
  1569904    1.655    0.000   18.799    0.000 /usr/lib64/python2.7/_strptime.py:27(_getlang)
  1569899    2.103    0.000   17.452    0.000 script.py:592(reverse)

日期的格式是这样的;

current_date = 01/Aug/1995:23:59:53

我是这样比较它们的;

with open(logfile) as file:
    for line in file:
        current_date = strptime_method(line)
        if current_date => end_date:
            break

在比较日期方面是否有其他选择?

编辑:谢谢大家,特别是 user2539738。这是根据他/她的建议得出的结果,速度差异很大

Fri Sep  2 16:14:59 2016    output3.file

         24270567 function calls (24270110 primitive calls) in 105.466 seconds

   Ordered by: cumulative time
   List reduced from 571 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.002    0.002  105.466  105.466 script.py:3(<module>)
        1    0.487    0.487  105.433  105.433 script.py:1082(main)
        1    3.159    3.159   95.861   95.861 script.py:702(get_data)
  1569898   21.663    0.000   77.138    0.000 script.py:648(check_line)
  1569876   14.979    0.000   43.408    0.000 script.py:626(dict_add)
  4709757   23.865    0.000   23.865    0.000 {method 'strftime' of 'datetime.date' objects}
  1569899    1.943    0.000   15.556    0.000 script.py:592(reverse)
        1    0.000    0.000    9.078    9.078 script.py:1066(print_data)
        1    0.021    0.021    9.044    9.044 script.py:1005(print_ip)
       10    0.001    0.000    7.067    0.707 script.py:778(ip_api)

【问题讨论】:

  • 如果输入日志记录是按日期排序的,您可能不必检查每个日志记录是否在日期范围内,并且可以执行二进制搜索来确定开始和您的范围的结束记录。只是想法。
  • strptime_method 是什么?你自己的一些代码?另外,您使用的是time(处理日期和时间的功能模块)还是datetime(相同的基于类的模块)?
  • @alecxe 这就是我目前已经在做的事情。如果发现日期超出范围,它将从循环中中断。但是,如果您的范围很大,那么正如我的结果所示,这可能会很耗时,主要是由于调用的每一行上的 strptime 方法。
  • @DavidHeyman strptime_method 只是我自己的代码,我用函数中的行做了一些事情。我正在使用 datetime 进行转换,所以我正在这样做; current_time = datetime.datetime.strptime(date_from_line, "%d/%b/%Y:%H:%M:%S")
  • 嗯。您是否尝试过多处理或线程?您可以通过同时搜索范围内的第一个和最后一个日期来节省一些时间。此外,如果您将每个日志放在不同的文件中而不是全部放在一个文件中,事情可能(可能)处理得更快。

标签: python regex loops strptime


【解决方案1】:

我假设 current_date 是一个字符串

首先,制作字典

moDict = {"Aug":8, "Jan":1} #etc

然后,查找年/月/日等

current_date = "01/Aug/1995:23:59:53"

Yr = int(current_date[7:11])
Mo = moDict[(current_date[3:6])]
Day = int(current_date[0:2])

m_date = datetime.datetime(Yr,Mo,Day)

你可以用它来进行比较

【讨论】:

  • 如果我发现strptime 已经在内部执行此操作,我完全不会感到惊讶。你实际测试过速度吗?
  • @DavidHeyman 即使strptime 在内部执行此操作,它也必须解释格式字符串。另一方面,它不必解释 Python。 :)
【解决方案2】:

由于您的日期似乎采用固定长度格式,因此解析起来非常容易,您不需要strptime 来解析。您可以将它们重新排列到ISO 8601 date/time format 中并直接将它们作为字符串进行比较!

mos = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06', 'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}

def custom_to_8601(dt):
    return dt[7:11] + '-' + mos[dt[3:6]] + '-' + dt[0:2] + 'T' + dt[12:]

>>> custom_to_8601('01/Aug/1995:23:59:53')
'1995-08-01T23:59:53'

使用join 代替字符串连接并省略标点符号可能会快一点:

def comparable_date(dt):
    return ''.join([dt[7:11], mos[dt[3:6]], dt[0:2], dt[12:]])

>>> comparable_date('01/Aug/1995:23:59:53')
'1995080123:59:53'

对我来说,以 1000000 次重复运行 cProfile 会产生这些时间:

  • custom_to_8601:0.978 秒
  • comparable_date:0.937 秒
  • strptime 的原始代码:15.492 秒
  • 使用datetime 构造函数的较早答案:1.134 秒

【讨论】:

  • 谢谢,我要试试这个,然后就我的结果回复你!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 2018-11-24
  • 2018-06-18
  • 1970-01-01
  • 2020-08-12
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多