首页 > 解决方案 > 从字符串确定日期时间格式

问题描述

假设我有一些包含任意日期和时间信息的字符串,例如'2020-01-01T10:00:10.200', '2020-01-01 10:00', '2020-Jan-01'等。

datetime通过尝试将每个字符串转换为对象来确保每个字符串确实包含此类信息是相对直接的:

from dateutil.parser import parse

def is_datetime(mystring):
    try: 
        parse(mystring)
        return True
    except ValueError:
        return False

如果知道日期时间格式,也很容易将字符串转换为datetime对象:

import datetime
dt_1 = datetime.datetime.strptime('2020-01-01T10:00:10.200', '%Y-%m-%dT%H:%M:%S.%f')
dt_2 = datetime.datetime.strptime('2020-01-01 10:00', '%Y-%m-%d %H:%M')
dt_3 = datetime.datetime.strptime('2020-Jan-01', '%Y-%b-%d')

但是,有没有办法从给定的日期时间字符串确定日期时间格式?例如:

get_dt_format('2020-01-01T10:00:10.200') # should return '%Y-%m-%dT%H:%M:%S.%f'
get_dt_format('2020-01-01 10:00') # should return '%Y-%m-%d %H:%M'
get_dt_format('2020-Jan-01') # should return '%Y-%b-%d'

我设法通过检查每个字符串与可能的日期时间格式的集合来做到这一点,直到匹配,但是有没有更好和更有效的方法来做到这一点?

简化的当前解决方案:

def _try_format(mystring, dt_format):
    try:
        datetime.datetime.strptime(mystring, dt_format)
        return True
    except ValueError:
        return False


def get_dt_format(mystring):
    possible_formats = ['%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%b-%d'] # and many others
    for possible_format in possible_formats:
        if _try_format(mystring, possible_format):
            return possible_format
    return 'Cannot determine format for ' + mystring

谢谢!

标签: pythonpython-3.xdatetimecasting

解决方案


如果需要,您可以使用正则表达式模块。我认为你的方法有点难,因为你必须写出所有的可能性。

例如,如果您想捕捉像 2020-Jan-01 00:00 这样的日期

import re
date=2020-Jan-01 00:00

re.finditer(r"20\d\d-[a-z]{3}-[0123]\d \d\d:\d\d",date)

它将找到适合该模式的所有匹配项。该示例模式并非特定于日期,即它也可以匹配 2020-abc-39 99:99 但您可以找到更大的模式。或者您可以使用 %Y %M 键来查找它。

或者我有另一个解决方案:

from itertools import permutations
import datetime
dates_str="20-Jan-2020 2000/May/06 11-Feb-2006 Mar-20-2013 We have an example about the date finding. You can write anything to here: 20/Jul/2020"

year_full="%Y"
month_abb="%b"
p_day="%d"      #1

for s_date in dates_str.split(" "):   #2
  for i in permutations([p_day,month_abb,year_full]):   #3
    for c in " -/.":   #4
      try:
        if datetime.datetime.strptime(s_date,f"{c}".join(list(i))):
          print(datetime.datetime.strptime(s_date,f"{c}".join(list(i))),"We found a date")
          break
      except:
        pass

让我解释一下那个代码......

#1 我在日期模块中写了表示年、月和日期的键。如果你愿意,你可以写一些其他的键来搜索。

#2 在这里,我们从字符串中获取所有单词。对于此代码,术语“单词”表示由空格 (" ") 分隔的字符

#3 for 循环很重要。在这里,我们尝试所有模式,这意味着一些日期信息,所有单词。该生成器包含以下项目:('%d', '%b', '%Y'), ('%d', '%Y', '%b'), ('%b', '%d' , '%Y'), ('%b', '%Y', '%d'), ('%Y', '%d', '%b'), ('%Y', '%b ', '%d')

#4 你想要关于日期的所有可能性,所以我们需要一些规范。日期可能在数字或任何位置之间有“.”、“-”、“/”或“”:2020 年 1 月 20 日或 2020 年 1 月 20 日。

为了捕捉这些日期,我在函数join中使用了一个 f 字符串。最后,代码可以捕获任何模式中包含“/”、“-”或“”的日期。我们有 24 种模式,我想写这些模式:

“%d %b %Y”、“%d-%b-%Y”、“%d/%b/%Y”、“%d.%b.%Y”、

“%d %Y %b”、“%d-%Y-%b”、“%d/%Y/%b”、“%d.%Y.%b”、

'%b %d %Y', '%b-%d-%Y', '%b/%d/%Y', '%b.%d.%Y',

'%b %Y %d', '%b-%Y-%d', '%b/%Y/%d', '%b.%Y.%d',

'%Y %d %b'、'%Y-%d-%b'、'%Y/%d/%b'、'%Y.%d.%b'、

“%Y %b %d”、“%Y-%b-%d”、“%Y/%b/%d”、“%Y.%b.%d”

但是这段代码有一些问题:

1-如果日期有 2012 年 1 月 5 日这样的空格,我不确定这段代码是否能找到它。因为我们将字符串与空格分开。

2-我使用生成器来节省 RAM,但一个小问题是时间。对于非常长的字符串,可能需要一段时间,因为我们会尝试每个单词的每个模式。

3-我无法将这些循环写在一行中,因为我们需要一个 try/except 块,但该块不可写在一行中。

如果您发现在正则表达式中使用键“%Y”、“%d”来搜索日期,请通知我...


推荐阅读