Converting between datetime, Timestamp and datetime64
如何将
在下面的代码中,我创建了一个datetime、timestamp和datetime64对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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') |
注意:很容易从时间戳中获取日期时间:
1 2 | In [10]: ts.to_datetime() Out[10]: datetime.datetime(2012, 5, 1, 0, 0) |
号
但是我们如何从
.
更新:在我的数据集中,一个有点讨厌的例子(可能是激励性的例子)似乎是:
1 | dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100') |
它应该是
您只能使用pd.timestamp构造函数。下面的图表可能对这个问题和相关问题有用。
。
欢迎来到地狱。
只需将datetime64对象传递给
1 2 | In [16]: Timestamp(numpy.datetime64('2012-05-01T01:00:00.000000')) Out[16]: <Timestamp: 2012-05-01 01:00:00> |
号
我注意到,在numpy 1.6.1中,这并不适用:
1 | numpy.datetime64('2012-05-01T01:00:00.000000+0100') |
号
另外,可以使用
1 2 | 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)) |
号
要将
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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对象被
要将datetime转换为np.datetime64并返回(
1 2 | >>> 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对象)之间的beatetween。
你的"坏榜样"工作正常:
1 2 3 4 5 6 | >>> 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 |
。
我可以复制安装在
1 | pip install git+https://github.com/numpy/numpy.git#egg=numpy-dev |
同样的例子:
1 2 3 4 5 6 | >>> 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' |
。
它返回
要获取日期时间对象,可以:
1 2 3 4 5 | >>> 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,请执行以下操作:
1 2 3 4 5 | >>> 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版本中可能会发生变化。
我认为,为了更好地解释python的datetime模块、numpy的datetime64/timedelta64和pandas的timestamp/timedelta对象之间的关系,可能有一个更为统一的解决方案。
python的日期时间标准库日期时间标准库有四个主要对象
- 仅时间-以小时、分钟、秒和微秒为单位测量的时间
- 日期-仅限年、月和日
- 日期时间-时间和日期的所有组件
- 时间增量-最大天数单位的时间量
创建这四个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> 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日
1 2 3 4 5 | >>> 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格式。
1 2 | >>> np.datetime64('2017-10-24') numpy.datetime64('2017-10-24') |
TimeDelta只有一个单位
1 2 | >>> np.timedelta64(5, 'D') # 5 days >>> np.timedelta64(10, 'h') 10 hours |
。
也可以通过减去两个datetime64对象来创建它们
1 2 | >>> np.datetime64('2017-10-24T05:30:45.67') - np.datetime64('2017-10-22T12:35:40.123') numpy.timedelta64(147305547,'ms') |
。熊猫时间戳和TimeDelta在numpy之上构建了更多的功能
熊猫时间戳与日期时间非常相似,但具有更多的功能。您可以使用
1 2 3 4 5 6 7 8 | >>> 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') |
1 2 3 4 5 | >>> 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
1 2 3 4 5 6 7 | >>> 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
1 2 3 4 5 6 7 8 9 | >>> 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) |
。
转换为时间戳
1 2 | >>> pd.Timestamp(dt64) Timestamp('2017-10-24 05:34:20.123456') |
号从时间戳转换为日期时间和日期时间64
这很容易,因为熊猫的时间戳非常强大
1 2 3 4 5 6 7 | >>> 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') |
号
1 2 | >>> dt64.tolist() datetime.datetime(2012, 5, 1, 0, 0) |
。
对于
如果要将整个熊猫系列的日期时间转换为常规的python日期时间,也可以使用
1 2 3 4 5 | 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) .... |
号
它还支持时区:
1 2 3 4 5 | 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>) .... |
号
注:如果您正在操作熊猫系列,则不能在整个系列中调用
1 | datetimes = [val.to_pydatetime() for val in df.problem_datetime_column] |
号
一种选择是使用
1 2 3 4 5 | 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)) |
注:它不等于
1 2 | In [13]: pd.to_datetime(str(dt64)).replace(tzinfo=None) Out[13]: datetime.datetime(2012, 5, 1, 1, 0) |
号
这看起来不雅。
.
更新:这可以处理"令人讨厌的例子":
1 2 3 4 | 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) |
这篇文章已经发表了4年,我仍然在努力解决这个转换问题,因此在某种意义上,这个问题在2017年仍然很活跃。我有点惊讶于numpy文档没有提供简单的转换算法,但这是另一回事。
我遇到了另一种方法来进行转换,只涉及模块
1 2 3 4 5 6 | 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年有一个Python发行版。我只看了标量转换,并没有检查基于数组的转换,尽管我猜想它会很好。我也没有看过numpy-datetime64源代码,看看这个操作是否有意义。
我回到这个答案的次数太多了,所以我决定快速地组织一个小类,它将一个麻木的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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) |
号
我要把这个放在我的工具袋里,有东西告诉我我需要它。
有些解决方案对我很有效,但numpy会取消某些参数。对于我来说,更好的解决方案是将日期读作熊猫的日期时间,并明确地执行熊猫对象的年、月和日。以下代码适用于最常见的情况。
1 2 3 4 | 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 2 3 4 5 | import numpy as np import pandas as pd def np64toDate(np64): return pd.to_datetime(str(np64)).replace(tzinfo=None).to_datetime() |
号
使用此函数获取pythons本机日期时间对象
事实上,所有这些日期时间类型都可能很困难,而且可能有问题(必须仔细跟踪时区信息)。这就是我所做的,尽管我承认我担心其中至少有一部分是"不按设计"。此外,还可以根据需要使其更加紧凑。从numpy.datetime64 dt_a开始:
dt_a
号
数字日期时间64('2015-04-24t23:11:26.270000-0700')
dt_a1 = dt_a.tolist() # yields a datetime object in UTC, but without tzinfo
dt_a1
号
日期时间.datetime(2015,4,25,6,11,26,270000)
1 | # now, make your"aware" datetime: |
号
dt_a2=datetime.datetime(*list(dt_a1.timetuple()[:6]) + [dt_a1.microsecond], tzinfo=pytz.timezone('UTC'))
号
…当然,可以根据需要压缩成一行。