在 datetime、Timestamp 和 datetime64 之间转换
Posted
技术标签:
【中文标题】在 datetime、Timestamp 和 datetime64 之间转换【英文标题】:Converting between datetime, Timestamp and datetime64 【发布时间】:2012-11-22 03:03:00 【问题描述】:如何将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)
但是我们如何从numpy.datetime64
(dt64
) 中提取datetime
或Timestamp
?
.
更新:我的数据集中的一个有点讨厌的例子(也许是激励例子)似乎是:
dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')
应该是datetime.datetime(2002, 6, 28, 1, 0)
,而不是很长的 (!) (1025222400000000000L
)...
【问题讨论】:
您可能应该接受更短的@Wes McKinney's answer,并且应该适用于最近的numpy
、pandas
版本。
@JFSebastian 嗯,这是否意味着答案是“不要从 np.datetime 移动到 datetime”......只需使用 pd.Timestamp (因为它是 datetime 的子类),或者如果你真的必须使用pd.Timestamp(dt64).to_datetime()
。我对此仍然有点不满意,但 Wes 肯定对我的老问题没有那么具体(对世界来说更好)!再次感谢您花时间回答它。 :)
你的问题是 "or Timestamp
" 和 Timestamp
是 datetime
(一个子类)反正:)
对于那些在 2017 年及以上提出这个问题的人,请查看下面我的答案以获取有关 datetime、datetime64 和 Timestamps 的详细教程:***.com/a/46921593/3707607
对于 Numpy -> datetime,截至 2020 年的 str 转换是最优雅的选择。
【参考方案1】:
您可以只使用 pd.Timestamp 构造函数。下图可能对这个问题和相关问题有用。
【讨论】:
看看这张图就告诉我,所有这些时间的东西都存在根本性的问题。 如果给定 ms 或 ns 的数量,pd.to_datetime 会产生一个 TimeStamp,但如果给定一个 datetime.datetime 或一个 np.datetime64 如果给定一个 np,它会产生一个 datetime.datetime,这非常令人困惑.datetime64... 为什么会有人认为这是合理的? @Mr.WorshipMe 此图需要更新。pd.to_datetime
将所有内容转换为 pd.Timestamp
。 pd.Timestamp
对象具有 to_pydatetime
方法以恢复为 datetime.datetime
对象和 to_datetime64
方法以转换为 np.datetime64
。
我怎样才能得到这张图片的更高分辨率?
这个图表需要string
-> 映射。试试这些:x = pd.to_datetime('2012-05-01T01:00:00.000000+0100'); print(type(x)); print(type(x.to_datetime());
——第一个是class 'pandas._libs.tslib.Timestamp'
,第二个是class 'datetime.datetime'
。 (并且您会收到警告,to_datetime()
已弃用 to_pydatetime()
)(在 Pandas 0.22.0 和 Python 3.5.2 中)【参考方案2】:
欢迎来到地狱。
您可以将 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))
【讨论】:
您应该提到issubclass(pd.Timestamp, datetime)
是True
。而Timestamp
类本身有to_datetime()
方法。
pd.to_datetime('2012-05-01T01:00:00.000000+0100')
至少在熊猫0.17.1
中返回Timestamp('2012-05-01 00:00:00')
。【参考方案3】:
将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.int8
、np.int16
等相同的方式考虑 np.datetime64
,并应用相同的方法在 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
我可以在安装为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 docs 表示 datetime API 是实验性的,可能会在未来的 numpy 版本中发生变化。
【讨论】:
恐怕这似乎并不总是有效:例如dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')
,它给出了一个很长的 (1025222400000000000L
) (!)
@hayden:试试type(dt64)
。 dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
@JFSebastian type(dt64)
是 numpy.datetime64
和 dt64.astype(datetime)
是相同的长整数...:s
@hayden:你的 numpy 版本是什么?我的:numpy.__version__
-> '1.6.1'
版本 1.8.0(在 python 2.7.3 中),如果它适用于你,它确实表明它是我系统上的一个错误!【参考方案4】:
我认为在答案中可能需要更统一的努力来更好地解释 Python 的 datetime 模块、numpy 的 datetime64/timedelta64 和 pandas 的 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 对象
为单位传递一个带有字符串的整数。 See all units here。在 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 时间戳是与日期时间非常相似但功能更多的时刻。您可以使用pd.Timestamp
或pd.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 日期时间转换为 datetime64 和时间戳
>>> 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
这很容易,因为 pandas 时间戳非常强大
>>> 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 到 datetime 仍然很难/hacky 真是太疯狂了......真的没有更好的方法吗?这是一个很好的答案,我正在考虑接受将其移至顶层,我必须通过计算机更深入地阅读其他内容。 它有什么奇怪的地方? Pandas 时间戳运行良好且相当简单。 Numpy 到日期时间。 我认为这是我见过的最好的答案。来自 Excel、VBA、SAS 或 SQL 的 Python 看起来很奇怪,因为不仅仅是“一种方式”来处理日期/时间。与 Python 或 R 中的许多东西一样,似乎必须选择一个最喜欢的方法/模块/类并坚持下去。 是的,很好的答案。我终于更好地理解了这一点。貌似还有matplotlib.dates
,为什么???【参考方案5】:
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)
对于DatetimeIndex
,tolist
返回datetime
对象的列表。对于单个 datetime64
对象,它返回单个 datetime
对象。
【讨论】:
@hayden 如果你知道它是一个标量/0-d 数组,我宁愿使用更明确的.item()
(并且没有人可以开始争论它应该返回一个列表) .
恐怕这似乎并不总是有效:例如dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')
,它给出了一个很长的 (1025222400000000000L
) (!)
@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')
使用 ms
,numpy.datetime64('2012-05-01T00:00:00.000000000')
使用 ns
。如果您觉得困惑,可以open an issue。
@AndyHayden 您也可以只添加一个额外的参数“us”或“ms”以确保应用相同的格式,从而在 tolist() 中生成相同的日期时间元素【参考方案6】:
如果要将整个 pandas 系列日期时间转换为常规 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>)
....
注意:如果您在 Pandas 系列上进行操作,则不能在整个系列上调用 to_pydatetime()
。您需要使用列表理解或类似方法在每个 datetime64 上调用 .to_pydatetime()
:
datetimes = [val.to_pydatetime() for val in df.problem_datetime_column]
【讨论】:
【参考方案7】:一种选择是使用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)
【讨论】:
感谢安迪分享这个技巧。出于某种原因,我无法使其工作,正如我在这里讨论的那样:***.com/questions/22825349/… @user815423426 这从来都不是一个非常健壮的解决方案,我想您可以将格式传递给 datetime 构造函数以更普遍地工作。虽然不是很熊猫!【参考方案8】:这篇文章已经发布了 4 年,我仍然在为这个转换问题而苦苦挣扎 - 所以从某种意义上说,这个问题在 2017 年仍然很活跃。 numpy 文档没有提供简单的转换算法,这让我感到有些震惊,但那是另一回事了。
我遇到了另一种只涉及模块numpy
和datetime
的转换方法,它不需要导入pandas,在我看来,对于这样一个简单的转换,要导入很多代码.我注意到datetime64.astype(datetime.datetime)
将返回一个datetime.datetime
对象,如果原始datetime64
是微秒单位 而其他单位返回一个整数时间戳。我使用模块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 源代码来查看操作是否有意义。
【讨论】:
【参考方案9】:我回到这个答案的次数已经数不胜数了,所以我决定组合一个快速的小类,它将 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)
我要把它放在我的工具包里,有东西告诉我我会再次需要它。
【讨论】:
你可以这样做ts.to_pydatetime()
【参考方案10】:
import numpy as np
import pandas as pd
def np64toDate(np64):
return pd.to_datetime(str(np64)).replace(tzinfo=None).to_datetime()
使用该函数获取python原生的日期时间对象
【讨论】:
我收到一条错误消息replace() got an unexpected keyword argument 'tzinfo'
你用的是哪个pandas版本?我有版本:0.18.1(pip show pandas)
和你一样。 . .
那时我不知道,但它对我来说就像魅力一样。 pix.toile-libre.org/upload/original/1475645621.png【参考方案11】:
一些解决方案对我来说效果很好,但 numpy 会弃用一些参数。
对我来说更好的解决方案是将日期读取为 pandas 日期时间,并明确提取 pandas 对象的年、月和日。
以下代码适用于最常见的情况。
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)
【讨论】:
【参考方案12】:我设法将包含时间信息的 pandas 数据框中的“日期”列转换为 numpy 数组的唯一方法如下:(从 csv 文件“csvIn.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()])
【讨论】:
【参考方案13】:我喜欢这个
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)
【讨论】:
【参考方案14】:确实,所有这些日期时间类型都可能很困难,并且可能存在问题(必须仔细跟踪时区信息)。这就是我所做的,尽管我承认我担心它至少有一部分是“不是设计使然”。此外,这可以根据需要变得更紧凑。 从 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'))
...当然,可以根据需要压缩成一行。
【讨论】:
docs.scipy.org/doc/numpy/reference/… 了解时区处理的变化。 请edit
遵守正确的:代码格式、引用格式和文本格式。此外,请按照 SO 指南遵守正确的大小写、语法并检查拼写错误 - 请参阅:How to Post 和 Code Samples以上是关于在 datetime、Timestamp 和 datetime64 之间转换的主要内容,如果未能解决你的问题,请参考以下文章