提问



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


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


我将把它们推回到数据库中的正确日期时间字段中,因此我需要将它们变成真正的日期时间对象。


任何帮助(即使它只是一个正确的方向踢)将不胜感激。


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

最佳参考


datetime.strptime是将字符串解析为日期时间的主要例程。它可以处理各种格式,格式由您提供的格式字符串确定:


from datetime import datetime

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


由此产生的datetime对象是时区的。


链接:



  • strptime的Python文档:Python 2,Python 3 [47] [48]

  • strptime/strftime格式字符串的Python文档:Python 2,Python 3 [49] [50]

  • strftime.org也是strftime的一个非常好的参考[51]



笔记:



  • strptime =字符串解析时间

  • strftime =字符串格式时间

  • 今天大声宣读它&你不会在6个月内再次搜索它。


其它参考1


使用第三方dateutil库:[52]


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


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


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


你可以安装它:


pip install python-dateutil

其它参考2


查看时间模块中的strptime。它是strftime的反转。[53] [54] [55]


$ 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)

其它参考3


我已经整理了一个可以转换一些非常简洁的表达式的项目。查看 timestring [56]


以下是一些例子:



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))

其它参考4


记住这一点,你不需要再次对日期时间转换感到困惑。


字符串到datetime对象= strptime


datetime对象为其他格式= strftime


Jun 1 2005 1:33PM


等于


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



  %b月份为区域设置的缩写名称(Jun)

  
  %d作为零填充十进制数的月中的某一天(1)

  
  %Y年份以世纪为十进制数(2015年)

  
  %I小时(12小时制)作为零填充十进制数(01)

  
  %M分钟为零填充十进制数(33)

  
  %p Locale相当于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)]

其它参考5


许多时间戳都有隐含的时区。为了确保您的代码在每个时区都有效,您应该在内部使用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)))

其它参考6


这里没有提到并且有用的东西:为当天添加后缀。我将后缀逻辑分离,以便您可以将它用于您喜欢的任何数字,而不仅仅是日期。


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"))​​​​​​​

其它参考7


以下是使用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)]


有很多选项可以使用to_datetime从字符串转换为Pandas时间戳,因此如果您需要任何特殊内容,请检查文档。[57]


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

其它参考8


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)


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


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

其它参考9


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

其它参考10


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


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


这是多才多艺的:



  • 如果你没有通过任何论据,它将在今天返回。

  • 默认情况下,您可以覆盖日期格式。

  • 您可以轻松修改它以返回日期时间。


其它参考11


日期时间Python模块适用于获取日期时间和转换日期时间格式。[59]


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


输出:


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

其它参考12


我个人喜欢使用parser模块的解决方案,这是这个问题的第二个答案并且非常漂亮,因为你不必构造任何字符串文字来使它工作。但是,一个缺点是它是比strptime接受的答案慢90%。


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方法更方便,并且会自动处理大部分时间格式。

其它参考13


箭头为日期和时间提供了许多有用的功能。这段代码提供了问题的答案,并显示箭头还能够轻松地格式化日期并显示其他区域设置的信息。


>>> 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/。[60]

其它参考14


您可以使用easy_date轻松实现:[61]


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

其它参考15


如果您只想要日期格式,那么您可以通过传递以下各个字段来手动转换它:


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


您将以日期格式获得结果值。

其它参考16


看我的答案。


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


我们需要尝试...捕获多个日期时间格式fmt1,fmt2,...,fmtn并抑制/处理所有不匹配的异常(来自strptime())(特别是,避免需要yukky n- try..catch子句的深缩进梯子)。见我的解决方案