Преобразование строки в дату и время

У меня есть огромный список таких дат в виде строк:

Jun 1 2005  1:33PM
Aug 28 1999 12:00AM

Я собираюсь засунуть их обратно в соответствующие поля datetime в базе данных, поэтому мне нужно превратить их в реальные объекты datetime.

Это происходит через ORM Django, поэтому я не могу использовать SQL для преобразования при вставке.


person Oli    schedule 21.01.2009    source источник
comment
Если вы не уверены, что один формат обрабатывает каждую дату и время (нет '', нет NaN, нет неполных данных, нет несоответствий формата, нет конечных символов, часовых поясов, микросекундных временных меток или другого текста ...), счастье-исключение strptime() сведет вас с ума, если вы его не завернете. См. Мой ответ, основанный на или ответе Вайса на это   -  person smci    schedule 15.12.2017
comment
Самый ленивый и наиболее широко используемый подход, который я знаю, - это dateparser (проверьте blog.scrapinghub.com/2015/11/09/). Он работает даже с выражениями времени на естественном языке на нескольких языках из коробки. Я думаю, это может быть медленным.   -  person Armando    schedule 01.11.2019
comment
Здесь есть полезная ссылка: stackabuse.com/converting-strings-to- datetime-in-python   -  person GoingMyWay    schedule 04.01.2020
comment
datetime.strptime, как упоминали другие. Для тех, кто предпочитает видеообъяснения, см. здесь.   -  person Ben    schedule 03.02.2021


Ответы (22)


datetime.strptime - это основная процедура для разбора строк на даты и время. Он может обрабатывать всевозможные форматы, причем формат определяется строкой формата, которую вы ему указываете:

from datetime import datetime

datetime_object = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

Результирующий объект datetime не зависит от часового пояса.

Ссылки:

  • Документация Python для strptime: Python 2, Python 3

  • Документация Python для строк формата _5 _ / _ 6_: Python 2, Python 3

  • strftime.org также является отличным справочником по strftime.

Примечания:

  • strptime = "время синтаксического анализа строки"
  • strftime = "строковый формат времени"
  • Произнесите это вслух сегодня, и вам не придется искать его снова через 6 месяцев.
person Patrick Harrington    schedule 21.01.2009
comment
"% b", "% p" может завершиться ошибкой в ​​неанглийской локали. - person jfs; 29.04.2014
comment
На какую строку нет времени, только 25 апреля 2014 г. - person User; 30.04.2014
comment
@User Вам нужно будет заранее знать, чтобы исключить эту часть строки формата, но если вы хотите date вместо datetime, переход через datetime прекрасно справится с этим: datetime.strptime('Jun 1 2005', '%b %d %Y').date() == date(2005, 6, 1) - person Izkata; 11.11.2014
comment
Если вы знаете, что строка представляет дату и время в формате UTC, вы можете получить объект datetime с учетом часового пояса, добавив эту строку в Python 3: from datetime import timezone; datetime_object = datetime_object.replace(tzinfo=timezone.utc) - person Flimm; 08.12.2016

Используйте стороннюю библиотеку dateutil:

from dateutil import parser
parser.parse("Aug 28 1999 12:00AM")  # datetime.datetime(1999, 8, 28, 0, 0)

Он может обрабатывать большинство форматов даты, включая тот, который вам нужно проанализировать. Это удобнее, чем strptime, так как большую часть времени может угадывать правильный формат.

Это очень полезно для написания тестов, где удобочитаемость важнее производительности.

Вы можете установить его с помощью:

pip install python-dateutil
person Simon Willison    schedule 22.01.2009
comment
Имейте в виду, что для больших объемов данных это может быть не самый оптимальный способ решения проблемы. Угадывать формат каждый раз может быть ужасно медленным. - person Paweł Polewicz; 03.07.2011
comment
Это хорошо, но было бы неплохо иметь встроенное решение, а не обращаться к третьему лицу. - person brian buck; 13.10.2011

Ознакомьтесь с strptime в time. Это противоположность strftime.

$ python
>>> import time
>>> my_time = time.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')
time.struct_time(tm_year=2005, tm_mon=6, tm_mday=1,
                 tm_hour=13, tm_min=33, tm_sec=0,
                 tm_wday=2, tm_yday=152, tm_isdst=-1)

timestamp = time.mktime(my_time)
# convert time object to datetime
from datetime import datetime
my_datetime = datetime.fromtimestamp(timestamp)
# convert time object to date
from datetime import date
my_date = date.fromtimestamp(timestamp)
person florin    schedule 21.01.2009
comment
Насколько я понимаю, этот ответ выводит только объекты времени, а не объекты datetime, поэтому ответ будет похоронен по сравнению с ответом Патрика. - person Alexander Bird; 07.09.2010

Я собрал проект, который может преобразовывать некоторые действительно изящные выражения. Ознакомьтесь с временной строкой.

Вот несколько примеров ниже:

pip install timestring
>>> import timestring
>>> timestring.Date('monday, aug 15th 2015 at 8:40 pm')
<timestring.Date 2015-08-15 20:40:00 4491909392>
>>> timestring.Date('monday, aug 15th 2015 at 8:40 pm').date
datetime.datetime(2015, 8, 15, 20, 40)
>>> timestring.Range('next week')
<timestring.Range From 03/10/14 00:00:00 to 03/03/14 00:00:00 4496004880>
>>> (timestring.Range('next week').start.date, timestring.Range('next week').end.date)
(datetime.datetime(2014, 3, 10, 0, 0), datetime.datetime(2014, 3, 14, 0, 0))
person Steve Peak    schedule 02.03.2014

python ›= 3.7

для преобразования строки ГГГГ-ММ-ДД в объект datetime можно использовать datetime.fromisoformat.

from datetime import datetime

date_string = "2012-12-12 10:10:10"
print (datetime.fromisoformat(date_string))
2012-12-12 10:10:10
person SuperNova    schedule 22.02.2019

Помните об этом, и вам не нужно снова запутываться при преобразовании даты и времени.

Строка для объекта datetime = strptime

объект datetime в другие форматы = strftime

Jun 1 2005 1:33PM

равно

%b %d %Y %I:%M%p

% b Месяц в качестве сокращенного названия локали (июнь)

% d День месяца в виде десятичного числа с нулями (1)

% Y Год с десятичным числом столетия (2015)

% I Час (12-часовой формат) в виде десятичного числа с нулями (01)

% M Минута в виде десятичного числа с нулями (33)

% p Локальный эквивалент AM или PM (PM)

поэтому вам нужно strptime i-e преобразование string в

>>> dates = []
>>> dates.append('Jun 1 2005  1:33PM')
>>> dates.append('Aug 28 1999 12:00AM')
>>> from datetime import datetime
>>> for d in dates:
...     date = datetime.strptime(d, '%b %d %Y %I:%M%p')
...     print type(date)
...     print date
... 

Выход

<type 'datetime.datetime'>
2005-06-01 13:33:00
<type 'datetime.datetime'>
1999-08-28 00:00:00

Что делать, если у вас другой формат дат, вы можете использовать panda или dateutil.parse

>>> import dateutil
>>> dates = []
>>> dates.append('12 1 2017')
>>> dates.append('1 1 2017')
>>> dates.append('1 12 2017')
>>> dates.append('June 1 2017 1:30:00AM')
>>> [parser.parse(x) for x in dates]

Выход

[datetime.datetime(2017, 12, 1, 0, 0), datetime.datetime(2017, 1, 1, 0, 0), datetime.datetime(2017, 1, 12, 0, 0), datetime.datetime(2017, 6, 1, 1, 30)]
person Rizwan Mumtaz    schedule 10.12.2014

Многие временные метки подразумевают часовой пояс. Чтобы гарантировать, что ваш код будет работать в каждом часовом поясе, вы должны использовать UTC внутренне и прикреплять часовой пояс каждый раз, когда посторонний объект входит в систему.

Python 3.2+:

>>> datetime.datetime.strptime(
...     "March 5, 2014, 20:13:50", "%B %d, %Y, %H:%M:%S"
... ).replace(tzinfo=datetime.timezone(datetime.timedelta(hours=-3)))

Предполагается, что вы знаете смещение. Если вы этого не сделаете, но знаете, например, местоположение, вы можете использовать пакет pytz для запроса смещения в базе данных часовых поясов IANA. Я буду использовать Тегеран в качестве примера, потому что у него есть получасовое смещение:

>>> tehran = pytz.timezone("Asia/Tehran")
>>> local_time = tehran.localize(
...   datetime.datetime.strptime("March 5, 2014, 20:13:50",
...                              "%B %d, %Y, %H:%M:%S")
... )
>>> local_time
datetime.datetime(2014, 3, 5, 20, 13, 50, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)

Как видите, pytz определил, что смещение было +3:30 в эту конкретную дату. Теперь вы можете преобразовать это время в UTC, и оно применит смещение:

>>> utc_time = local_time.astimezone(pytz.utc)
>>> utc_time
datetime.datetime(2014, 3, 5, 16, 43, 50, tzinfo=<UTC>)

Обратите внимание, что даты до принятия часовых поясов дадут вам странные смещения. Это связано с тем, что IANA решило использовать среднее местное время:

>>> chicago = pytz.timezone("America/Chicago")
>>> weird_time = chicago.localize(
...   datetime.datetime.strptime("November 18, 1883, 11:00:00",
...                              "%B %d, %Y, %H:%M:%S")
... )
>>> weird_time.astimezone(pytz.utc)
datetime.datetime(1883, 11, 18, 7, 34, tzinfo=<UTC>)

Странные 34 секунды получены из долготы Чикаго. Я использовал эту дату, потому что это день, когда было усыновлен в Чикаго.

person Janus Troelsen    schedule 06.03.2014

Вот два решения с использованием Pandas для преобразования дат, отформатированных в виде строк, в объекты datetime.date.

import pandas as pd

dates = ['2015-12-25', '2015-12-26']

# 1) Use a list comprehension.
>>> [d.date() for d in pd.to_datetime(dates)]
[datetime.date(2015, 12, 25), datetime.date(2015, 12, 26)]

# 2) Convert the dates to a DatetimeIndex and extract the python dates.
>>> pd.DatetimeIndex(dates).date.tolist()
[datetime.date(2015, 12, 25), datetime.date(2015, 12, 26)]

Время

dates = pd.DatetimeIndex(start='2000-1-1', end='2010-1-1', freq='d').date.tolist()

>>> %timeit [d.date() for d in pd.to_datetime(dates)]
# 100 loops, best of 3: 3.11 ms per loop

>>> %timeit pd.DatetimeIndex(dates).date.tolist()
# 100 loops, best of 3: 6.85 ms per loop

А вот как преобразовать исходные примеры даты и времени OP:

datetimes = ['Jun 1 2005  1:33PM', 'Aug 28 1999 12:00AM']

>>> pd.to_datetime(datetimes).to_pydatetime().tolist()
[datetime.datetime(2005, 6, 1, 13, 33), 
 datetime.datetime(1999, 8, 28, 0, 0)]

Существует множество вариантов преобразования строк в метки времени Pandas с использованием to_datetime, поэтому проверьте docs, если вам нужно что-то особенное.

Аналогичным образом, метки времени имеют множество свойств и методов, которые можно доступно в дополнение к .date

person Alexander    schedule 20.12.2015

Мне лично нравится решение с использованием модуля parser, который является вторым ответом на этот вопрос и красивым, поскольку вам не нужно создавать какие-либо строковые литералы, чтобы заставить его работать. НО, недостатком является то, что он на 90% медленнее, чем принятый ответ с strptime.

from dateutil import parser
from datetime import datetime
import timeit

def dt():
    dt = parser.parse("Jun 1 2005  1:33PM")
def strptime():
    datetime_object = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

print(timeit.timeit(stmt=dt, number=10**5))
print(timeit.timeit(stmt=strptime, number=10**5))
>10.70296801342902
>1.3627995655316933

Пока вы не делаете это миллион раз снова и снова, я все же думаю, что метод parser более удобен и будет обрабатывать большую часть форматов времени автоматически.

person user1767754    schedule 02.01.2018

То, что здесь не упомянуто и полезно: добавление суффикса к дню. Я отделил логику суффикса, чтобы вы могли использовать ее для любого числа, которое вам нравится, а не только для дат.

import time

def num_suffix(n):
    '''
    Returns the suffix for any given int
    '''
    suf = ('th','st', 'nd', 'rd')
    n = abs(n) # wise guy
    tens = int(str(n)[-2:])
    units = n % 10
    if tens > 10 and tens < 20:
        return suf[0] # teens with 'th'
    elif units <= 3:
        return suf[units]
    else:
        return suf[0] # 'th'

def day_suffix(t):
    '''
    Returns the suffix of the given struct_time day
    '''
    return num_suffix(t.tm_mday)

# Examples
print num_suffix(123)
print num_suffix(3431)
print num_suffix(1234)
print ''
print day_suffix(time.strptime("1 Dec 00", "%d %b %y"))
print day_suffix(time.strptime("2 Nov 01", "%d %b %y"))
print day_suffix(time.strptime("3 Oct 02", "%d %b %y"))
print day_suffix(time.strptime("4 Sep 03", "%d %b %y"))
print day_suffix(time.strptime("13 Nov 90", "%d %b %y"))
print day_suffix(time.strptime("14 Oct 10", "%d %b %y"))​​​​​​​
person Aram Kocharyan    schedule 14.10.2011

Пример объекта datetime, учитывающего часовой пояс Django.

import datetime
from django.utils.timezone import get_current_timezone
tz = get_current_timezone()

format = '%b %d %Y %I:%M%p'
date_object = datetime.datetime.strptime('Jun 1 2005  1:33PM', format)
date_obj = tz.localize(date_object)

Это преобразование очень важно для Django и Python, когда у вас USE_TZ = True:

RuntimeWarning: DateTimeField MyModel.created received a naive datetime (2016-03-04 00:00:00) while time zone support is active.
person Ryu_hayabusa    schedule 20.11.2014

Это было бы полезно для преобразования строки в datetime, а также с часовым поясом

def convert_string_to_time(date_string, timezone):
    from datetime import datetime
    import pytz
    date_time_obj = datetime.strptime(date_string[:26], '%Y-%m-%d %H:%M:%S.%f')
    date_time_obj_timezone = pytz.timezone(timezone).localize(date_time_obj)

    return date_time_obj_timezone

date = '2018-08-14 13:09:24.543953+00:00'
TIME_ZONE = 'UTC'
date_time_obj_timezone = convert_string_to_time(date, TIME_ZONE)
person Kanish Mathew    schedule 16.08.2018

Создайте небольшую служебную функцию, например:

def date(datestr="", format="%Y-%m-%d"):
    from datetime import datetime
    if not datestr:
        return datetime.today().date()
    return datetime.strptime(datestr, format).date()

Это достаточно универсально:

  • Если вы не передадите никаких аргументов, он вернет сегодняшнюю дату.
  • По умолчанию используется формат даты, который вы можете изменить.
  • Вы можете легко изменить его, чтобы он возвращал дату и время.
person Mackraken    schedule 04.02.2016

Стрелка предлагает множество полезных функций для даты и времени. Этот фрагмент кода дает ответ на вопрос и показывает, что стрелка также может легко форматировать даты и отображать информацию для других языков.

>>> import arrow
>>> dateStrings = [ 'Jun 1  2005 1:33PM', 'Aug 28 1999 12:00AM' ]
>>> for dateString in dateStrings:
...     dateString
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').datetime
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').format('ddd, Do MMM YYYY HH:mm')
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').humanize(locale='de')
...
'Jun 1  2005 1:33PM'
datetime.datetime(2005, 6, 1, 13, 33, tzinfo=tzutc())
'Wed, 1st Jun 2005 13:33'
'vor 11 Jahren'
'Aug 28 1999 12:00AM'
datetime.datetime(1999, 8, 28, 0, 0, tzinfo=tzutc())
'Sat, 28th Aug 1999 00:00'
'vor 17 Jahren'

Подробнее см. http://arrow.readthedocs.io/en/latest/.

person Bill Bell    schedule 28.02.2017

Если ваша строка имеет формат ISO8601 и у вас установлен Python 3.7+, вы можете использовать следующий простой код:

import datetime

aDate = datetime.date.fromisoformat('2020-10-04')

для свиданий и

import datetime

aDateTime = datetime.datetime.fromisoformat('2020-10-04 22:47:00')

для строк, содержащих дату и время. Если временные метки включены, функция datetime.datetime.isoformat() поддерживает следующий формат

YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]

где * соответствует любому одиночному символу. См. Также здесь и здесь

person jjm    schedule 04.10.2020

Вы можете использовать easy_date, чтобы упростить задачу:

import date_converter
converted_date = date_converter.string_to_datetime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')
person Raphael Amoedo    schedule 01.06.2015

Вы также можете ознакомиться с dateparser

dateparser предоставляет модули для простого анализа локализованных дат практически в любых строковых форматах, обычно встречающихся на веб-страницах.

Установить:

$ pip install dateparser

Думаю, это самый простой способ разбирать даты.

Самый простой способ - использовать функцию dateparser.parse, которая охватывает большую часть функций модуля.

Пример кода:

import dateparser

t1 = 'Jun 1 2005  1:33PM'
t2 = 'Aug 28 1999 12:00AM'

dt1 = dateparser.parse(t1)
dt2 = dateparser.parse(t2)

print(dt1)
print(dt2)

Вывод:

2005-06-01 13:33:00
1999-08-28 00:00:00
person Bilesh Ganguly    schedule 12.01.2020

Если вам нужен только формат даты, вы можете вручную преобразовать его, передав свои отдельные поля, например:

>>> import datetime
>>> date = datetime.date(int('2017'),int('12'),int('21'))
>>> date
datetime.date(2017, 12, 21)
>>> type(date)
<type 'datetime.date'>

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

selected_month_rec = '2017-09-01'
date_formate = datetime.date(int(selected_month_rec.split('-')[0]),int(selected_month_rec.split('-')[1]),int(selected_month_rec.split('-')[2]))

Вы получите результат в формате даты.

person Javed    schedule 21.12.2017

См. мой ответ.

В реальных данных это настоящая проблема: множественные, несовпадающие, неполные, несовместимые и многоязычные / региональные форматы даты, часто свободно смешанные в одном наборе данных. Это не нормально, если производственный код терпит неудачу, не говоря уже о том, чтобы быть счастливым в исключениях, как лиса.

Нам нужно попробовать ... поймать несколько форматов даты и времени fmt1, fmt2, ..., fmtn и подавить / обработать исключения (из strptime()) для всех тех, которые не совпадают (и, в частности, избежать необходимости в уродливой лестнице с глубоким отступом n try..catch clauses). Из моего решения

def try_strptime(s, fmts=['%d-%b-%y','%m/%d/%Y']):
    for fmt in fmts:
        try:
            return datetime.strptime(s, fmt)
        except:
            continue

    return None # or reraise the ValueError if no format matched, if you prefer
person smci    schedule 18.12.2017

emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv")
emp.info()

он показывает столбец «Дата начала» и «Время последнего входа в систему», оба являются «объект = строки» во фрейме данных

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 8 columns):
First Name           933 non-null object
Gender               855 non-null object
Start Date           1000 non-null object

Last Login Time      1000 non-null object
Salary               1000 non-null int64
Bonus %              1000 non-null float64
Senior Management    933 non-null object
Team                 957 non-null object
dtypes: float64(1), int64(1), object(6)
memory usage: 62.6+ KB

Используя параметр parse_dates в read_csv упоминании, вы можете преобразовать строку datetime в формат даты и времени pandas.

emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv", parse_dates=["Start Date", "Last Login Time"])
emp.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 8 columns):
First Name           933 non-null object
Gender               855 non-null object
Start Date           1000 non-null datetime64[ns]
Last Login Time      1000 non-null datetime64[ns]
Salary               1000 non-null int64
Bonus %              1000 non-null float64
Senior Management    933 non-null object
Team                 957 non-null object
dtypes: datetime64[ns](2), float64(1), int64(1), object(4)
memory usage: 62.6+ KB
person Riz.Khan    schedule 01.01.2019

Кажется, используется pandas Timestamp самый быстрый

import pandas as pd 

N = 1000

l = ['Jun 1 2005  1:33PM'] * N

list(pd.to_datetime(l, format=format))

%timeit _ = list(pd.to_datetime(l, format=format))
1.58 ms ± 21.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Другие решения

from datetime import datetime
%timeit _ = list(map(lambda x: datetime.strptime(x, format), l))
9.41 ms ± 95.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

from dateutil.parser import parse
%timeit _ = list(map(lambda x: parse(x), l))
73.8 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Если строка является строкой ISO8601, используйте csio8601.

import ciso8601

l = ['2014-01-09'] * N

%timeit _ = list(map(lambda x: ciso8601.parse_datetime(x), l))
186 µs ± 4.13 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
person Grzegorz    schedule 29.09.2020

Краткий пример сопоставления строки даты yyyy-mm-dd с объектом datetime.date:

from datetime import date
date_from_yyyy_mm_dd = lambda δ : date(*[int(_) for _ in δ.split('-')])
date_object = date_from_yyyy_mm_dd('2021-02-15')
person John Forbes    schedule 26.03.2021