Подтвердить что ты не робот

Как я могу анализировать несколько (неизвестных) форматов даты в python?

У меня есть куча документов excel, из которых я извлекаю даты. Я пытаюсь преобразовать их в стандартный формат, чтобы я мог поместить их в базу данных. Есть ли функция, с которой я могу отправить эти строки и получить стандартный формат? Вот небольшой пример моих данных:

Хорошо, что я знаю, что это всегда Месяц/День

10/02/09
07/22/09
09-08-2008
9/9/2008
11/4/2010
 03-07-2009
09/01/2010

Я хочу, чтобы все они были в формате MM/DD/YYYY. Есть ли способ, которым я могу это сделать, не пробовав каждый шаблон против строки?

4b9b3361

Ответ 1

import re

ss = '''10/02/09
07/22/09
09-08-2008
9/9/2008
11/4/2010
03-07-2009
09/01/2010'''


regx = re.compile('[-/]')
for xd in ss.splitlines():
    m,d,y = regx.split(xd)
    print xd,'   ','/'.join((m.zfill(2),d.zfill(2),'20'+y.zfill(2) if len(y)==2 else y))

результат

10/02/09     10/02/2009
07/22/09     07/22/2009
09-08-2008     09/08/2008
9/9/2008     09/09/2008
11/4/2010     11/04/2010
03-07-2009     03/07/2009
09/01/2010     09/01/2010

Изменить 1

И Изменить 2: принимая во внимание информацию о '{0:0>2}'.format(day) от JBernardo, я добавил 4-е решение, которое кажется самым быстрым

import re
from time import clock
iterat = 100

from datetime import datetime
dates = ['10/02/09', '07/22/09', '09-08-2008', '9/9/2008', '11/4/2010',
         ' 03-07-2009', '09/01/2010']

reobj = re.compile(
r"""\s*  # optional whitespace
(\d+)    # Month
[-/]     # separator
(\d+)    # Day
[-/]     # separator
(?:20)?  # century (optional)
(\d+)    # years (YY)
\s*      # optional whitespace""",
re.VERBOSE)

te = clock()
for i in xrange(iterat):
    ndates = (reobj.sub(r"\1/\2/20\3", date) for date in dates)
    fdates1 = [datetime.strftime(datetime.strptime(date,"%m/%d/%Y"), "%m/%d/%Y")
               for date in ndates]
print "Tim method   ",clock()-te,'seconds'



regx = re.compile('[-/]')


te = clock()
for i in xrange(iterat):
    ndates = (reobj.match(date).groups() for date in dates)
    fdates2 = ['%s/%s/20%s' % tuple(x.zfill(2) for x in tu) for tu in ndates]
print "mixing solution",clock()-te,'seconds'


te = clock()
for i in xrange(iterat):
    ndates = (regx.split(date.strip()) for date in dates)
    fdates3 = ['/'.join((m.zfill(2),d.zfill(2),('20'+y.zfill(2) if len(y)==2 else y)))
              for m,d,y in ndates]
print "eyquem method",clock()-te,'seconds'



te = clock()
for i in xrange(iterat):
    fdates4 = ['{:0>2}/{:0>2}/20{}'.format(*reobj.match(date).groups()) for date in dates]
print "Tim + format   ",clock()-te,'seconds'


print fdates1==fdates2==fdates3==fdates4

результат

number of iteration turns : 100
Tim method    0.295053700959 seconds
mixing solution 0.0459111423379 seconds
eyquem method 0.0192239516475 seconds
Tim + format    0.0153756971906 seconds 
True

Смешивающее решение интересно, потому что оно сочетает скорость моего решения и способность регулярного выражения Тима Питцкера определять даты в строке.

Это еще более верно для решения, сочетающего Тим 1 и формирование с {:0>2}. Я не могу совместить {:0>2} с моим, потому что regx.split(date.strip()) производит год с 2 ИЛИ 4 цифрами

Ответ 2

В стороннем модуле dateutil есть функция parse, которая работает аналогично PHP strtotime: вы не нужно указать конкретный формат даты, он просто пробует кучу.

>>> from dateutil.parser import parse
>>> parse("10/02/09", fuzzy=True)
datetime.datetime(2009, 10, 2, 0, 0)  # default to be in American date format

Он также позволяет указать различные предположения:

  • dayfirst. Должно ли интерпретировать первое значение в двусмысленной 3-целой дате (например, 01/05/09) как день (True) или месяц (False). Если для yearfirst установлено значение True, это отличает YDM и YMD. Если установлено значение Нет, это значение извлекается из текущего объекта parserinfo (который сам по умолчанию имеет значение False).
  • yearfirst. Следует ли интерпретировать первое значение в двузначной 3-целой дате (например, 01/05/09) в качестве года. Если "Истина", первым числом считается год, иначе последний номер считается годом. Если для этого параметра установлено значение Нет, значение извлекается из текущего объекта parserinfo (который по умолчанию имеет значение False).

Ответ 3

Если вы не хотите устанавливать сторонний модуль, например dateutil:

import re
from datetime import datetime
dates = ['10/02/09', '07/22/09', '09-08-2008', '9/9/2008', '11/4/2010', ' 03-07-2009', '09/01/2010']
reobj = re.compile(
    r"""\s*  # optional whitespace
    (\d+)    # Month
    [-/]     # separator
    (\d+)    # Day
    [-/]     # separator
    (?:20)?  # century (optional)
    (\d+)    # years (YY)
    \s*      # optional whitespace""", 
    re.VERBOSE)
ndates = [reobj.sub(r"\1/\2/20\3", date) for date in dates]
fdates = [datetime.strftime(datetime.strptime(date,"%m/%d/%Y"), "%m/%d/%Y")
          for date in ndates]

Результат:

['10/02/2009', '07/22/2009', '09/08/2008', '09/09/2008', '11/04/2010', '03/07/2009', '09/01/2010']

Ответ 4

Вы можете использовать регулярное выражение, например r'(\d+)\D(\d+)\D(\d+)', чтобы получить месяц, день и год в кортеже с помощью функции re.findall.

то просто соедините двухзначные годы с числом 20 или 19 и используйте разделитель, который хотите присоединиться, затем обратно:

'/'.join(the_list)

Как указано Тимом:

Чтобы нормализовать дни, просто сделайте '{0:0>2}'.format(day) и то же самое, что и в месяцах.