python:将字符串转换为datetime

短而简单。我有一个像这样的日期-时间的字符串列表:

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

我将把这些返回到数据库中适当的datetime字段中,因此我需要将它们转换为实际的datetime对象。

任何帮助(即使只是朝正确的方向踢一脚)都将受到感激。

编辑:这是通过Django的ORM进行的,所以我不能使用SQL在insert上进行转换。

  • 用于将带有日期值字符串的整个列转换为另一篇文章中给出的选项
  • 除非您确定一种格式可以处理每个单独的日期时间(没有"、没有NaNs、没有不完整、没有格式不匹配、没有尾随字符、时区、微秒时间戳或其他文本……),否则strptime()的异常幸福感会让您发疯,除非您将它包装起来。看我的答案,基于或我们的答案


datetime.strptime是将字符串解析为datetimes的主要例程。它可以处理各种格式,格式由你给它的格式字符串决定:

1
2
3
from datetime import datetime

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

得到的datetime对象是时区无关的。

链接:

用于strptime的Python文档:python2, python3

用于strptime/strftime格式字符串的Python文档:python2, python3

org对于strftime也是一个很好的参考

注:

strptime ="字符串解析时间"strftime ="字符串格式时间"今天就大声读出来吧!6个月后你就不用再找了。

  • 为什么返回的是date_object而不是datetime_object?
  • '%b'、'%p'可能在非英语语言环境中失败。
  • 什么弦没有时间,只有"2014年4月25日"
  • @User必须提前知道要排除格式字符串的这一部分,但是如果您想使用date而不是datetime,遍历datetime可以很好地处理它:datetime.strptime('Jun 1 2005', '%b %d %Y').date() == date(2005, 6, 1)
  • 解析含有时区的默认unix 'date'命令输出,例如。"Sun Oct 4 07:48:48 UTC 2015"可以使用datetime。strptime (currentDateStr"% % b % d % H: % M: % S % Z % Y")。
  • 注意,这个函数是在python 2.4.3和python 2.6之间添加的
  • 猜测strptime总是耗时的复杂任务,为此我创建了一个帮助服务。看看percepty.com/…
  • 如果您知道字符串在UTC中表示一个datetime,您可以通过在Python 3中添加这一行代码来获得一个时区感知的datetime对象:from datetime import timezone; datetime_object = datetime_object.replace(tzinfo=timezone.utc)
  • 知道在python中如何在3之前获得一个时区感知的datetime吗?
  • 我在找"%Y-%m-%d %H:%M:%S"
  • 我在找……现在似乎比2018年多了一点……
  • 我得到这个错误AttributeError: 'module' object has no attribute 'strptime'
  • @AminahNuraini我通过做from datetime import datetime而不是仅仅做import datetime来回避类似的问题。


使用第三方dateutil库:

1
2
from dateutil import parser
dt = parser.parse("Aug 28 1999 12:00AM")

它可以处理大多数日期格式,包括需要解析的格式。它比strptime更方便,因为大多数时候它都能猜出正确的格式。

它对于编写测试非常有用,因为可读性比性能更重要。

你可以安装它与:

1
pip install python-dateutil

  • 请注意,对于大数据量,这可能不是解决问题的最佳方法。每次都猜测格式可能非常慢。
  • 这很好,但是最好有一个内置的解决方案,而不是求助于第三方。
  • 当我试图解析"32 jan"时,它返回我"2032-01-06"..这是不正确的。是否有方法检查字符串是否是有效日期
  • @Reef:根据我快速而肮脏的基准测试,速度是它的5倍。没有我想象的那么慢。
  • 注意,dateutil的当前版本2.2依赖于six库,这是一个Python 2/3兼容库。这允许dateutil 2.2同时使用Python 2。x和Python 3。
  • 是否有自己的问题——例如,从times中悄悄删除时区信息:尝试parser.parse('15:55EST')并与parser.parse('15.55CST')进行比较
  • 此库通过pip install python-dateutil安装,但通过import dateutil使用。这是少数几个为pip使用不同名称的库之一。
  • 这是一个非常不幸的习惯,混淆了美国和英国的dmy和mdy格式。但是,当您很懒或者必须处理许多格式时,这是很方便的。
  • 很好的答案-很好的模块(我害怕自己写这样的东西!)有什么方法可以鼓励dateutil更喜欢英式风格而不是美式风格呢?我可以用它在不同的情况下推动它?edit—看起来文档使用dayfirst关键字覆盖了这一点


在时间模块中查看strptime。它是strftime的倒数。

1
2
3
4
5
6
$ python
>>> import 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)

  • 据我所知,这个答案只输出时间对象,而不是datetime对象——这就是为什么与Patrick的答案相比,这个答案会被隐藏起来。
  • 下面的答案(帕特里克·哈灵顿)更正确,因为时间。strptime只输出时间,而不是datetime
  • 当我们已经知道了格式时,strptime很方便,我想知道是否有像php的strtotime这样的东西不需要告诉输入格式?
  • 是否有方法设置DateTimeField的默认datetime格式?
  • 正如Alexander所说,这将返回struct_time,而不是datetime。当然,您可以将它转换为一个datetime,但是如果您希望最后有一个datetime对象,那么Patrick的回答就更直接了。
  • 在标准python库中没有类似于strtotime的东西,但是dateutil有一个解析器,可以识别许多最佳工作日期格式。
  • 随机问题:strptimestrftime怎么发音?我假设str是字符串,time是时间。那么pf是什么呢?
  • @BenBlank: '%b'、'%p'在非英语地区可能会失败。
  • 警告! !我发现及时处理时间数据是非常困难的。struct_time对象。例如,如果你想给那个对象添加特定的天数,你必须转换时间。struct_time对象到datetime。datetime对象。别无他法
  • @hobbes3 parseformat


我做了一个项目,可以转换一些非常简洁的表达式。查看timestring。

下面是一些例子:pip install timestring

1
2
3
4
5
6
7
8
9
>>> 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))

  • 哇。哇。哇。哇。这很简单。我有一个datetime字符串,我只想取出年份。就像:import timestring timestring.Date('27 Mar 2014 12:32:29 GMT').year这个库让它变得如此简单!谢谢你!
  • 你非常受欢迎。我想听听你对改进这个方案的意见和想法。让我知道,使用github问题。谢谢!
  • @Steve Peak timestring非常棒!需要用scrapy解析文章日期,这已经完美地转换了它们。
  • 嗨,史蒂夫,这个模块很棒。最好也有一个工作日字符串属性。否则,不确定你是从周一还是周日开始上班
  • @Anake你可以创建一个问题来请求添加到github.com/stevepeak/timestring谢谢!
  • 看起来很有趣. .如果它包含了dateutil的解析器(也许还有其他一些好东西),那就更棒了。不过做得不错。
  • Range的概念非常好。
  • 这是一个很好的套餐。射程异常强大。如何将timestring对象转换为datetime?我想把时间取消,但.date()没空。
  • 是的。timestring.Range('this week').starttimestring.Range('this week').end
  • 这个模块使用起来很方便。但是要注意不太好的性能。i7膝上型电脑的分析结果:Python\Python27\site-packages\timestring\Date.py.__init__:20 2458 1.42 0.41 (ncall ttot tsub)执行2400个timestring.Date('19:36:23 06/05/2015').to_unixtime()调用需要1.4秒以上
  • 识别各种输入的能力真的很棒。如果它还能识别不太正式的时间范围,比如"下午5-6点",那就更好了。更棒的是能够识别"530pm-6"之类的短信对话中经常使用的时间范围的样式(不需要同时使用冒号或am/pm)。
  • 警告:timestring还没有正确处理次秒:timestring.Date('Aug 28 1999 12:53:45.123 AM').date给出日期时间。datetime(1999、8、28、0、53、45、0),但是dateutil.parser.parse('Aug 28 1999 12:53:45.123 AM')正确地给出了datetime。日期时间(1999年8月28日0月53日45日123日)
  • 我当时想,这是行不通的,但在我试着用它之后,"你是一个编程之神"善良的先生。这就是python包应该如何工作。
  • 它不能正确地转换诸如"2017年2月5日"和"2017年2月5日"之类的格式(这些格式在一些圈子里很流行,在我看来,为了清晰和可读性,这些格式是最好的日期格式)。它将它们存储为2017-02-01。2017年2月5日也是一样的(不过2月5日是正确的);后两种格式我都没有见过,但我还是想指出来。


记住这一点,您不需要在datetime转换中再次感到困惑。

datetime对象的字符串= strptime

其他格式的datetime对象= strftime

Jun 1 2005 1:33PM

等于

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

%b Month as locale’s abbreviated name(Jun)

%d Day of the month as a zero-padded decimal number(1)

%Y Year with century as a decimal number(2015)

%I Hour (12-hour clock) as a zero-padded decimal number(01)

%M Minute as a zero-padded decimal number(33)

%p Locale’s equivalent of either AM or PM(PM)

因此,需要将strptime i-e转换为string

1
2
3
4
5
6
7
8
9
>>> 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
...

输出

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

如果您有不同格式的日期,您可以使用panda或dateutil.parse

1
2
3
4
5
6
7
>>> 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]

输出

1
[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)]

  • %S表示秒的小数形式
  • 如果在没有英语语言环境的机器上解析英语日期,%b不会中断吗?


许多时间戳都有一个隐含的时区。为了确保您的代码能够在每个时区工作,您应该在内部使用UTC,并在每次外部对象进入系统时附加一个时区。

Python 3.2 +:

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

  • 如果您知道第二种方法(datetime.strptime()),为什么要保留丑陋的、有时是错误的(mktime()在DST转换期间)第一种方法?如果希望在闰秒期间避免异常(第二个方法失败),可以使用calendar.timegm代替:(datetime(1970,1,1)+timedelta(seconds=timegm(time.strptime(.‌​.)))).replace(tzinfo‌​=timezone(timedelta(‌​-3)))


这里没有提到但很有用的东西:在一天中添加后缀。我解耦了后缀逻辑,所以你可以用它来表示任何你喜欢的数字,而不仅仅是日期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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"))???????

下面是两个使用panda将格式化为字符串的日期转换为datetime的解决方案。日期对象。

1
2
3
4
5
6
7
8
9
10
11
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)]

计时

1
2
3
4
5
6
7
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的原始日期-时间示例:

1
2
3
4
5
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)]

使用to_datetime将字符串转换为panda时间戳有很多选项,所以如果需要特殊的东西,请检查文档。

同样,除了.date之外,时间戳还有许多可以访问的属性和方法


我个人喜欢使用parser模块的解决方案,这是这个问题的第二个答案,而且很漂亮,因为您不需要构造任何字符串文字来让它工作。但是,一个缺点是它比使用strptime的公认答案慢90%。

1
2
3
4
5
6
7
8
9
10
11
12
13
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方法更方便,并且可以自动处理大多数时间格式。


Django时区感知的datetime对象示例。

1
2
3
4
5
6
7
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)

当您有USE_TZ = True时,这种转换对Django和Python非常重要:

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

  • 所以你的观点是使用tz.localize?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
In [34]: import datetime

In [35]: _now = datetime.datetime.now()

In [36]: _now
Out[36]: datetime.datetime(2016, 1, 19, 9, 47, 0, 432000)

In [37]: print _now
2016-01-19 09:47:00.432000

In [38]: _parsed = datetime.datetime.strptime(str(_now),"%Y-%m-%d %H:%M:%S.%f")

In [39]: _parsed
Out[39]: datetime.datetime(2016, 1, 19, 9, 47, 0, 432000)

In [40]: assert _now == _parsed

适用于unix / mysql格式2018-10-15 20:59:29

1
2
3
from datetime import datetime

datetime_object = datetime.strptime('2018-10-15 20:59:29', '%Y-%m-%d %H:%M:%S')

创建一个小的实用函数,如:

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

这是多才多艺的:

如果您不传递任何参数,它将返回今天的日期。有一个默认的日期格式,您可以覆盖它。您可以轻松地修改它以返回一个datetime。

  • format是python中的保留字,不应该用作变量名。


datetime Python模块非常适合获取日期时间和转换日期时间格式。

1
2
3
4
5
6
import datetime

new_date_format1 = datetime.datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')
new_date_format2 = datetime.datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p').strftime('%Y/%m/%d %I:%M%p')
print new_date_format1
print new_date_format2

输出:

1
2
2005-06-01 13:33:00
2005/06/01 01:33PM


arrow为日期和时间提供了许多有用的函数。这段代码为这个问题提供了一个答案,并显示出arrow还能够方便地格式化日期和显示其他地区的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> 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 /最近/。


在Python中>= 3.7.0,

要将YYYY-MM-DD字符串转换为datetime对象,可以使用datetime.fromisoformat

1
2
3
4
5
>>> from datetime import datetime

>>> date_string ="2012-12-12 10:10:10"
>>> print (datetime.fromisoformat(date_string))
>>> 2012-12-12 10:10:10

你可以使用easy_date来简化:

1
2
import date_converter
converted_date = date_converter.string_to_datetime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

如果你只想要日期格式,你可以手动转换它通过传递你的个人字段如下:

1
2
3
4
5
6
>>> import datetime
>>> date = datetime.date(int('2017'),int('12'),int('21'))
>>> date
datetime.date(2017, 12, 21)
>>> type(date)
<type 'datetime.date'>

您可以传递拆分字符串值,将其转换为日期类型,如下所示:

1
2
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]))

您将得到日期格式的结果值。


它将有助于将字符串转换为datetime和时区

1
2
3
4
5
6
7
8
9
10
11
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)

  • 我需要一个带时区的datetime字符串??


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

它显示"开始日期时间"列和"最后登录时间"都是数据帧中的"object = string"

1
2
3
4
5
<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
1
2
3
Start Date           1000 non-null object

Last Login Time      1000 non-null object
1
2
3
4
5
6
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

通过使用read_csv中的parse_dates选项,可以将字符串datetime转换为panda datetime格式。

1
2
3
4
5
6
7
8
9
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
1
2
Start Date           1000 non-null datetime64[ns]
Last Login Time      1000 non-null datetime64[ns]
1
2
3
4
5
6
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

看到我的答案。

在实际数据中,这是一个真正的问题:多个、不匹配的、不完整的、不一致的和多语言/区域的数据格式,常常在一个数据集中自由混合。生产代码失败是不好的,更不用说像狐狸一样快乐了。

我们需要试一试……捕获多个日期时间格式fmt1、fmt2、…,fmtn和抑制/处理所有那些不匹配的异常(来自strptime())(特别是,避免需要一个糟糕的n-deep缩进阶梯的尝试..赶上条款)。从我的解决方案

1
2
3
4
5
6
7
8
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

  • 该问题没有提到"多种、不匹配、不完整、不一致和多语言/地区的日期格式"等。这可能是一个真正的问题,但在这里无关紧要。
  • @RoG:它从来没有说过它们不是,而是暗示它们是:"巨大的列表……数据库"。在我处理过的大多数数据库/日志文件中(即使很小),都有多种日期格式、时区标识符、MM-DD等。在生产中,编写脆弱的代码是不可接受的,这些代码以格式硬编码,当没有得到预期的格式时(甚至返回None或"更可接受"),就会崩溃。因此需要多种格式。因此,这确实解决了所问的问题,我花了一些时间来找出处理多种格式错误的最符合python风格的方法。
  • "巨大的名单……"数据库"仅仅意味着它们有很多,而不是它们都是不同的格式。如果您知道输入中只有一种格式,那么编写读取单一格式的代码是完全可以接受的。在本例中,如果传递的内容格式不正确,则会崩溃。