在datetime, Timestamp和datetime64之间转换

如何将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')

注意:从Timestamp中很容易得到datetime:

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

但是我们如何从numpy.datetime64 (dt64)中提取datetimeTimestamp呢?

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

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

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

704387 次浏览

一种选择是使用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,因为它变成了"offset-aware":

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)
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

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

numpy.datetime64转换为datetime对象,该对象在numpy-1.8上表示UTC时间:

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

上面的例子假设朴素的datetime对象被np.datetime64解释为UTC时间。


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.int8np.int16等一样,并应用相同的方法在Python对象(如intdatetime)和相应的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

我可以在安装的numpy-1.8.0上重现long值,如下所示:

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,因为对于numpy.datetime64类型,.astype(datetime)等价于numpy-1.8上返回Python整数(long)的.astype(object)

要获取datetime对象,您可以:

>>> 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文档表示datetime API是实验性的,在未来的numpy版本中可能会改变。

欢迎来到地狱。

你可以直接将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也可以使用(这是开发版本之外的,还没有检查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))

你可以用pd。时间戳的构造函数。下面的图表可能对这个问题和相关问题有用。

时间表示之间的转换

如果你想将整个pandas系列的datetimes转换为常规的python datetimes,你也可以使用.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>)
....

请注意:如果你操作的是Pandas系列,你不能在整个系列上调用to_pydatetime()。你需要在每个单独的datetime64上调用.to_pydatetime(),使用一个列表理解或类似的东西:

datetimes = [val.to_pydatetime() for val in df.problem_datetime_column]
实际上,所有这些datetime类型都很困难,而且可能存在问题(必须仔细跟踪时区信息)。以下是我所做的,尽管我承认我担心至少有一部分不是“故意”的。此外,这可以根据需要做得更紧凑一些。 从numpy开始。datetime64 dt_a: < / p >

dt_a

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

dt_a1 = dt_a.tolist() #生成UTC格式的datetime对象,但不包含tzinfo

dt_a1

datetime。日期时间(2015,4,25,6,11,26,270000)

# now, make your "aware" datetime:

Dt_a2 =datetime.datetime(*list(dt_a1.timetuple()[:6]) + [dt_a1. timetuple()]微秒),tzinfo = pytz.timezone (UTC))

... 当然,也可以根据需要压缩成一行。

import numpy as np
import pandas as pd


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

使用此函数获取python的原生datetime对象

这篇文章已经写了4年了,我仍然在这个转换问题上挣扎——所以在某种意义上,这个问题在2017年仍然很活跃。numpy文档没有提供简单的转换算法,这让我有些震惊,但那是另一回事了。

我遇到了另一种只涉及模块numpydatetime的转换方法,它不需要导入pandas,对我来说,对于这样一个简单的转换来说,导入很多代码。我注意到,如果原始的datetime64微秒的单位中,而其他单元返回整数时间戳,datetime64.astype(datetime.datetime)将返回一个datetime.datetime对象。我使用模块xarray用于来自Netcdf文件的数据I/O,该文件使用纳秒单位的datetime64,使转换失败,除非你首先转换为微秒单位。下面是转换代码的示例,

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

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

我已经无数次地回到这个答案,所以我决定拼凑一个快速的小类,它将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)

我要把它放在我的工具箱里,直觉告诉我我还会用到它。

我认为可以有一个更统一的答案来更好地解释Python的datetime模块、numpy的datetime64/timedelta64和pandas的Timestamp/Timedelta对象之间的关系。

Python的datetime标准库

datetime标准库有四个主要对象

  • 时间-只有时间,以小时、分钟、秒和微秒为单位
  • 日期-只有年,月和日
  • 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')

时间增量只有一个单位

>>> 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的基础上构建了更多的功能

pandas Timestamp是一个与datetime非常相似的时刻,但具有更多的功能。你可以用pd.Timestamppd.to_datetime来构造它们。

>>> pd.Timestamp(1239.1238934) #defaults 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')

从Timestamp转换为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')

一些解决方案工作得很好,但numpy将弃用一些参数。 对我来说,更好的解决方案是将日期读取为pandas datetime,并明确地提取pandas对象的年、月和日。 下面的代码适用于最常见的情况 < /代码> < / p >

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)

唯一的方法,我设法转换列“日期”在熊猫dataframe包含时间信息numpy数组如下:(dataframe是从csv文件" csvi .csv")

import pandas as pd
import numpy as np


df = pd.read_csv("csvIn.csv")
df["date"] = pd.to_datetime(df["date"])
timestamps = np.array([np.datetime64(value) for dummy, value in df["date"].items()])

我是这样做的

import pandas as pd


# Custom function to convert Pandas Datetime to Timestamp
def toTimestamp(data):
return data.timestamp()


# Read a csv file
df = pd.read_csv("friends.csv")


# Replace the "birthdate" column by:
# 1. Transform to datetime
# 2. Apply the custom function to the column just converted
df["birthdate"] = pd.to_datetime(df["birthdate"]).apply(toTimestamp)