在datetime,Timestamp和datetime64之间转换


289

如何将numpy.datetime64对象转换为datetime.datetime(或Timestamp)?

在下面的代码中,我创建一个datetime,timestamp和datetime64对象。

import datetime
import numpy as np
import pandas as pd
dt = datetime.datetime(2012, 5, 1)
# A strange way to extract a Timestamp object, there's surely a better way?
ts = pd.DatetimeIndex([dt])[0]
dt64 = np.datetime64(dt)

In [7]: dt
Out[7]: datetime.datetime(2012, 5, 1, 0, 0)

In [8]: ts
Out[8]: <Timestamp: 2012-05-01 00:00:00>

In [9]: dt64
Out[9]: numpy.datetime64('2012-05-01T01:00:00.000000+0100')

注意:很容易从时间戳获取日期时间:

In [10]: ts.to_datetime()
Out[10]: datetime.datetime(2012, 5, 1, 0, 0)

但是我们如何从()中提取datetime或?Timestampnumpy.datetime64dt64

更新:我的数据集中的一个令人讨厌的例子(也许是激励性的例子)似乎是:

dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')

应该是datetime.datetime(2002, 6, 28, 1, 0),而不是长(!)(1025222400000000000L)...


2
你应该接受@Wes麦金尼的回答是短得多,应该在最近的工作numpypandas版本。
jfs 2015年

@JFSebastian Hmmm,是否表示答案是“不要从np.datetime移到datetime” ...只需使用pd.Timestamp(因为它始终是datetime的子类),或者如果您真的必须使用pd.Timestamp(dt64).to_datetime()。我对此还有些不满意,但是可以肯定的是,韦斯对我的旧问题不太专一(对整个世界来说更好)!再次感谢您抽出宝贵时间来回答。:)
安迪·海登

您的问题说“或Timestamp”,并且无论如何Timestamp都是datetime(的子类:)
jfs 2015年

3
对于那些在2017年以上遇到此问题的人,请看下面我的答案,以获取有关日期时间,datetime64和时间戳的详细教程:stackoverflow.com/a/46921593/3707607
Ted Petrou

Answers:


132

要将numpy.datetime64日期时间对象转换为代表UTC时间的日期时间对象,请执行以下操作numpy-1.8

>>> from datetime import datetime
>>> import numpy as np
>>> dt = datetime.utcnow()
>>> dt
datetime.datetime(2012, 12, 4, 19, 51, 25, 362455)
>>> dt64 = np.datetime64(dt)
>>> ts = (dt64 - np.datetime64('1970-01-01T00:00:00Z')) / np.timedelta64(1, 's')
>>> ts
1354650685.3624549
>>> datetime.utcfromtimestamp(ts)
datetime.datetime(2012, 12, 4, 19, 51, 25, 362455)
>>> np.__version__
'1.8.0.dev-7b75899'

上面的示例假定np.datetime64在UTC中将朴素的datetime对象解释为时间。


要将datetime转换为np.datetime64并返回(numpy-1.6):

>>> np.datetime64(datetime.utcnow()).astype(datetime)
datetime.datetime(2012, 12, 4, 13, 34, 52, 827542)

它既可用于单个np.datetime64对象,又可用于np.datetime64的numpy数组。

想想np.datetime64的方式与处理np.int8,np.int16等的方式相同,并应用相同的方法在Python对象(如int,datetime和相应的numpy对象)之间转换甜菜。

您的“讨厌的例子”可以正常工作:

>>> from datetime import datetime
>>> import numpy 
>>> numpy.datetime64('2002-06-28T01:00:00.000000000+0100').astype(datetime)
datetime.datetime(2002, 6, 28, 0, 0)
>>> numpy.__version__
'1.6.2' # current version available via pip install numpy

我可以将安装时的long值复制numpy-1.8.0为:

pip install git+https://github.com/numpy/numpy.git#egg=numpy-dev

相同的例子:

>>> from datetime import datetime
>>> import numpy
>>> numpy.datetime64('2002-06-28T01:00:00.000000000+0100').astype(datetime)
1025222400000000000L
>>> numpy.__version__
'1.8.0.dev-7b75899'

long之所以返回,是因为for numpy.datetime64类型.astype(datetime)等于在.astype(object)上返回Python整数(longnumpy-1.8

要获取日期时间对象,您可以:

>>> dt64.dtype
dtype('<M8[ns]')
>>> ns = 1e-9 # number of seconds in a nanosecond
>>> datetime.utcfromtimestamp(dt64.astype(int) * ns)
datetime.datetime(2002, 6, 28, 0, 0)

要获取直接使用秒的datetime64:

>>> dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100', 's')
>>> dt64.dtype
dtype('<M8[s]')
>>> datetime.utcfromtimestamp(dt64.astype(int))
datetime.datetime(2002, 6, 28, 0, 0)

numpy的文档说,日期时间API是实验性的,并在未来的版本中numpy的可能改变。


1
恐怕这似乎并不总能奏效:例如dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'),给出一个长(1025222400000000000L)(!)
Andy Hayden 2012年

@hayden:尝试type(dt64)dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
jfs 2012年

@JFSebastian type(dt64)numpy.datetime64并且dt64.astype(datetime)是相同的长整数...:s
Andy Hayden

@hayden:您的numpy版本是什么?我的:numpy.__version__->'1.6.1'
jfs

版本1.8.0(在python 2.7.3中),如果它对您有用,则确实表明它是我系统上的错误!
安迪·海登

211

您可以只使用pd.Timestamp构造函数。下图可能对此问题和相关问题有用。

时间表示之间的转换


2
很好!!! (最值得一提的是,自从我写了这个问题以来情况已经有所改善,这里已经做了很多工作:))
Andy Hayden

106
只看这张图就可以告诉我,所有这些东西从根本上来说都是错的。
痴呆的刺猬

4
如果给定ms或ns的数量,pd.to_datetime将产生一个TimeStamp,但是如果给定datetime.datetime或如果给出np.datetime64,则将产生datetime.datetime,这真是令人困惑。认为这合理吗?
Mr.WorshipMe'2

7
@ Mr.WorshipMe此图需要更新。pd.to_datetime将所有内容转换为pd.Timestamp。甲pd.Timestamp对象具有方法to_pydatetime回复到一个datetime.datetime对象和一个to_datetime64要转换为方法np.datetime64
Ted Petrou

2
如何获得此图片的更高分辨率?
user3226167 '18

136

欢迎来到地狱。

您可以将datetime64对象传递给pandas.Timestamp

In [16]: Timestamp(numpy.datetime64('2012-05-01T01:00:00.000000'))
Out[16]: <Timestamp: 2012-05-01 01:00:00>

我注意到虽然在NumPy 1.6.1中这是行不通的:

numpy.datetime64('2012-05-01T01:00:00.000000+0100')

pandas.to_datetime可以使用(这是dev版本的版本,尚未检查v0.9.1):

In [24]: pandas.to_datetime('2012-05-01T01:00:00.000000+0100')
Out[24]: datetime.datetime(2012, 5, 1, 1, 0, tzinfo=tzoffset(None, 3600))

5
您应该提到的issubclass(pd.Timestamp, datetime)True。并且Timestamp类本身具有to_datetime()方法。
jfs 2015年

7
pd.to_datetime('2012-05-01T01:00:00.000000+0100')Timestamp('2012-05-01 00:00:00')至少以熊猫返回0.17.1
安东·普罗托波夫

96

我认为答案中可能需要做更多的整合工作,以更好地解释Python的datetime模块,numpy的datetime64 / timedelta64和熊猫的Timestamp / Timedelta对象之间的关系。

Python的日期时间标准库

日期时间标准库有四个主要对象

  • 时间-仅时间,以小时,分钟,秒和微秒为单位
  • 日期-仅年,月和日
  • datetime-时间和日期的所有组成部分
  • timedelta-以天为单位的最大时间量

创建这四个对象

>>> import datetime
>>> datetime.time(hour=4, minute=3, second=10, microsecond=7199)
datetime.time(4, 3, 10, 7199)

>>> datetime.date(year=2017, month=10, day=24)
datetime.date(2017, 10, 24)

>>> datetime.datetime(year=2017, month=10, day=24, hour=4, minute=3, second=10, microsecond=7199)
datetime.datetime(2017, 10, 24, 4, 3, 10, 7199)

>>> datetime.timedelta(days=3, minutes = 55)
datetime.timedelta(3, 3300)

>>> # add timedelta to datetime
>>> datetime.timedelta(days=3, minutes = 55) + \
    datetime.datetime(year=2017, month=10, day=24, hour=4, minute=3, second=10, microsecond=7199)
datetime.datetime(2017, 10, 27, 4, 58, 10, 7199)

NumPy的datetime64和timedelta64对象

NumPy没有单独的日期和时间对象,只有一个datetime64对象代表一个时间点。datetime模块的datetime对象的精度为微秒(百万分之一秒)。NumPy的datetime64对象使您可以将其精度设置为从小时到十亿分之一秒(10 ^ -18)。它的构造函数更加灵活,可以接受各种输入。

构造NumPy的datetime64和timedelta64对象

传递带有字符串的整数作为单位。在这里查看所有单位。在UNIX时代之后,它转换为这么多单位:1970年1月1日

>>> np.datetime64(5, 'ns') 
numpy.datetime64('1970-01-01T00:00:00.000000005')

>>> np.datetime64(1508887504, 's')
numpy.datetime64('2017-10-24T23:25:04')

您也可以使用ISO 8601格式的字符串。

>>> np.datetime64('2017-10-24')
numpy.datetime64('2017-10-24')

Timedelta有一个单位

>>> np.timedelta64(5, 'D') # 5 days
>>> np.timedelta64(10, 'h') 10 hours

也可以通过减去两个datetime64对象来创建它们

>>> np.datetime64('2017-10-24T05:30:45.67') - np.datetime64('2017-10-22T12:35:40.123')
numpy.timedelta64(147305547,'ms')

Pandas Timestamp和Timedelta在NumPy之上构建了更多功能

大熊猫时间戳记与日期时间非常相似,但是功能更多。您可以使用pd.Timestamp或构造它们pd.to_datetime

>>> pd.Timestamp(1239.1238934) #defautls to nanoseconds
Timestamp('1970-01-01 00:00:00.000001239')

>>> pd.Timestamp(1239.1238934, unit='D') # change units
Timestamp('1973-05-24 02:58:24.355200')

>>> pd.Timestamp('2017-10-24 05') # partial strings work
Timestamp('2017-10-24 05:00:00')

pd.to_datetime 的工作方式非常相似(有更多选择),并且可以将字符串列表转换为时间戳。

>>> pd.to_datetime('2017-10-24 05')
Timestamp('2017-10-24 05:00:00')

>>> pd.to_datetime(['2017-1-1', '2017-1-2'])
DatetimeIndex(['2017-01-01', '2017-01-02'], dtype='datetime64[ns]', freq=None)

将Python datetime转换为datetime64和Timestamp

>>> dt = datetime.datetime(year=2017, month=10, day=24, hour=4, 
                   minute=3, second=10, microsecond=7199)
>>> np.datetime64(dt)
numpy.datetime64('2017-10-24T04:03:10.007199')

>>> pd.Timestamp(dt) # or pd.to_datetime(dt)
Timestamp('2017-10-24 04:03:10.007199')

将numpy datetime64转换为datetime和Timestamp

>>> dt64 = np.datetime64('2017-10-24 05:34:20.123456')
>>> unix_epoch = np.datetime64(0, 's')
>>> one_second = np.timedelta64(1, 's')
>>> seconds_since_epoch = (dt64 - unix_epoch) / one_second
>>> seconds_since_epoch
1508823260.123456

>>> datetime.datetime.utcfromtimestamp(seconds_since_epoch)
>>> datetime.datetime(2017, 10, 24, 5, 34, 20, 123456)

转换为时间戳

>>> pd.Timestamp(dt64)
Timestamp('2017-10-24 05:34:20.123456')

从时间戳转换为datetime和datetime64

这很简单,因为熊猫时间戳非常强大

>>> ts = pd.Timestamp('2017-10-24 04:24:33.654321')

>>> ts.to_pydatetime()   # Python's datetime
datetime.datetime(2017, 10, 24, 4, 24, 33, 654321)

>>> ts.to_datetime64()
numpy.datetime64('2017-10-24T04:24:33.654321000')

3
多么疯狂的约会时间仍然很困难/ hacky ...真的没有更好的方法吗?这是一个很好的答案,我正在考虑接受将其移至顶层,我必须通过计算机更深入地阅读其他内容。
安迪·海登

这有什么奇怪的地方?熊猫时间戳可以很好地工作并且非常简单。
泰德·彼得鲁

2
顽皮到约会时间。
安迪·海登

1
我认为这是我见过的最好的答案。来自Excel,VBA,SAS或SQL的Python看起来很奇怪,因为使用日期/时间的方式不只是“一种方式”。与Python或R中的许多东西一样,似乎必须选择一种喜欢的方法/模块/类并坚持使用。
肖恩·麦卡锡

惊人的答案
gioxc88

29
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

对于DatetimeIndextolist返回datetime对象列表。对于单个datetime64对象,它返回一个datetime对象。


我真的应该尝试所有的方法:)(我为解决这个问题多久而感到震惊)谢谢
Andy Hayden 2012年

5
@hayden,如果您知道它是一个标量/ 0-d数组,我宁愿使用.item()它更显式(而且没有人可以绕过并开始争论它应该返回一个列表)。
seberg 2012年

1
恐怕这似乎并不总能奏效:例如dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'),给出一个长(1025222400000000000L)(!)
Andy Hayden 2012年

4
@hayden:由返回的类型.item()(由@seberg建议的),.tolist()取决于什么单位datetime64用途例如,D产生datetime.date()us(微秒)产生datetime.datetime()ns(纳秒)产生long。并且单位根据输入值(例如numpy.datetime64('2012-05-01')使用'D'numpy.datetime64('2012-05-01T00:00:00.000')使用msnumpy.datetime64('2012-05-01T00:00:00.000000000')使用)而变化ns。如果您感到困惑,则可以打开一个问题
jfs 2012年

@AndyHayden您还可以添加一个额外的参数“ us”或“ ms”以确保应用相同的格式,从而导致在tolist()中生成相同的datetime元素
NM

11

如果要将整个熊猫系列日期时间转换为常规python日期时间,也可以使用.to_pydatetime()

pd.date_range('20110101','20110102',freq='H').to_pydatetime()

> [datetime.datetime(2011, 1, 1, 0, 0) datetime.datetime(2011, 1, 1, 1, 0)
   datetime.datetime(2011, 1, 1, 2, 0) datetime.datetime(2011, 1, 1, 3, 0)
   ....

它还支持时区:

pd.date_range('20110101','20110102',freq='H').tz_localize('UTC').tz_convert('Australia/Sydney').to_pydatetime()

[ datetime.datetime(2011, 1, 1, 11, 0, tzinfo=<DstTzInfo 'Australia/Sydney' EST+11:00:00 DST>)
 datetime.datetime(2011, 1, 1, 12, 0, tzinfo=<DstTzInfo 'Australia/Sydney' EST+11:00:00 DST>)
....

注意:如果您使用的是熊猫系列,则不能调用to_pydatetime()整个系列。您将需要.to_pydatetime()使用列表推导或类似方法在每个单独的datetime64 上调用:

datetimes = [val.to_pydatetime() for val in df.problem_datetime_column]

10

一种选择是使用str,然后使用to_datetime(或类似方法):

In [11]: str(dt64)
Out[11]: '2012-05-01T01:00:00.000000+0100'

In [12]: pd.to_datetime(str(dt64))
Out[12]: datetime.datetime(2012, 5, 1, 1, 0, tzinfo=tzoffset(None, 3600))

注意:它不等于,dt因为它变得“可偏移”

In [13]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[13]: datetime.datetime(2012, 5, 1, 1, 0)

这似乎不雅。

更新:这可以处理“讨厌的例子”:

In [21]: dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')

In [22]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[22]: datetime.datetime(2002, 6, 28, 1, 0)

感谢Andy分享此技巧。出于某种原因,我不能让它的工作,因为我在这里讨论:stackoverflow.com/questions/22825349/...
阿梅里奥巴斯克斯-雷纳

@ user815423426这从来都不是一个非常可靠的解决方案,我想您可以将格式传递给datetime构造函数以使其更通用。虽然不是很泛泛!
安迪·海登

8

这篇文章已经发表了四年,但我仍然在为这个转换问题而苦苦挣扎-因此从某种意义上说,该问题在2017年仍然很活跃。numpy文档没有提供简单的转换算法,这让我有些震惊,但这是另一回事了。

我遇到了另一种仅涉及模块numpy和的转换方法datetime,它不需要导入熊猫,在我看来,要进行这种简单转换,需要导入很多代码。我注意到,如果原始单位微秒单位,则datetime64.astype(datetime.datetime)它将返回一个datetime.datetime对象,而其他单位则返回整数时间戳。我使用Netcdf文件中的数据I / O 模块,该模块使用纳秒级单位进行转换,除非您首先转换为微秒级单位,否则转换将失败。这是示例转换代码,datetime64xarraydatetime64

import numpy as np
import datetime

def convert_datetime64_to_datetime( usert: np.datetime64 )->datetime.datetime:
    t = np.datetime64( usert, 'us').astype(datetime.datetime)
return t

它仅在我的机器上进行过测试,该机器是带有最新的2017 Anaconda发行版的Python 3.6。我只是看过标量转换,没有检查基于数组的转换,尽管我猜这会很好。我也没有查看numpy datetime64源代码,以查看该操作是否有意义。


这很棒。谢谢你这样做。
Yu Chen

好东西。谢谢。
misantroop

1

我回来这个答案的次数超出了我的预期,因此我决定召集一个快速的小类,将Numpy datetime64值转换为Python datetime值。我希望它可以帮助其他人。

from datetime import datetime
import pandas as pd

class NumpyConverter(object):
    @classmethod
    def to_datetime(cls, dt64, tzinfo=None):
        """
        Converts a Numpy datetime64 to a Python datetime.
        :param dt64: A Numpy datetime64 variable
        :type dt64: numpy.datetime64
        :param tzinfo: The timezone the date / time value is in
        :type tzinfo: pytz.timezone
        :return: A Python datetime variable
        :rtype: datetime
        """
        ts = pd.to_datetime(dt64)
        if tzinfo is not None:
            return datetime(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, tzinfo=tzinfo)
        return datetime(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second)

我要把它放在我的工具袋里,告诉我我将再次需要它。


2
您可以做ts.to_pydatetime()
泰德·彼得鲁

0
import numpy as np
import pandas as pd 

def np64toDate(np64):
    return pd.to_datetime(str(np64)).replace(tzinfo=None).to_datetime()

使用此函数获取pythons本机datetime对象


replace() got an unexpected keyword argument 'tzinfo'
说错

您使用哪个熊猫版本?我有版本:0.18.1(点显熊猫)
Crystal

和你一样。。。
ogogmad

那时候我不知道,但是对我来说就像魅力一样。pix.toile-libre.org/upload/original/1475645621.png
水晶

0

一些解决方案对我来说效果很好,但是numpy将弃用某些参数。对我来说更好的解决方案是将日期作为熊猫的日期时间读取,并明确地提取熊猫对象的年,月和日。以下代码适用于最常见的情况。

def format_dates(dates):
    dt = pd.to_datetime(dates)
    try: return [datetime.date(x.year, x.month, x.day) for x in dt]    
    except TypeError: return datetime.date(dt.year, dt.month, dt.day)

-1

实际上,所有这些日期时间类型都可能很困难,并且可能有问题(必须仔细跟踪时区信息)。这是我所做的,尽管我承认我担心至少其中一部分是“不是设计造成的”。同样,这可以根据需要变得更紧凑。以numpy.datetime64 dt_a开头:

dt_a

numpy.datetime64('2015-04-24T23:11:26.270000-0700')

dt_a1 = dt_a.tolist()#以UTC格式生成日期时间对象,但不包含tzinfo

dt_a1

datetime.datetime(2015,4,25,6,11,26,270000)

# now, make your "aware" datetime:

dt_a2 = datetime.datetime(* list(dt_a1.timetuple()[:6])+ [dt_a1.microsecond],tzinfo = pytz.timezone('UTC'))

...当然,可以根据需要将其压缩为一行。



edit遵循正确的代码格式,引号格式和文本格式。另外,请遵循SO准则,坚持正确的大小写,语法和拼写检查-请参阅:如何发布代码示例
SherylHohman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.