Преобразование между 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 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 или Timestamp из numpy.datetime64 (dt64)?

.

Обновление: несколько неприятный пример в моем наборе данных (возможно, мотивирующий пример):

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

который должен быть datetime.datetime(2002, 6, 28, 1, 0), а не длинным (!) (1025222400000000000L)...

Ответ 1

Чтобы преобразовать numpy.datetime64 в объект datetime, который представляет время в 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'

В приведенном выше примере предполагается, что наивный объект 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, так и на массиве numpy np.datetime64.

Подумайте о 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, потому что для numpy.datetime64 тип .astype(datetime) эквивалентен .astype(object), который возвращает целое число Python (long) на numpy-1.8.

Чтобы получить объект 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 говорят, что API-интерфейс datetime является экспериментальным и может измениться в будущих версиях numpy.

Ответ 2

Вы можете просто использовать конструктор pd.Timestamp. Следующая диаграмма может быть полезна для этого и связанных вопросов.

Conversions between time representations

Ответ 3

Добро пожаловать в ад.

Вы можете просто передать объект 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))

Ответ 4

Я думаю, что ответ может быть более консолидированным, чтобы лучше объяснить взаимосвязь между модулем datetime Python, numpy datetime64/timedelta64 и объектами Timestamp/Timedelta от pandas.

Стандартная библиотека даты и времени Python

Стандартная библиотека 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: 1 января 1970 г.

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

Timedeltas имеют одну единицу

>>> 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.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 datetime
datetime.datetime(2017, 10, 24, 4, 24, 33, 654321)

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

Ответ 5

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

Для DatetimeIndex, tolist возвращает список объектов datetime. Для одного объекта datetime64 он возвращает один объект datetime.

Ответ 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() для всей серии. Вам нужно будет вызывать .to_pydatetime() для каждого отдельного datetime64, используя понимание списка или что-то подобное:

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)

Ответ 8

Это сообщение было в течение 4 лет, и я по-прежнему боролся с этой проблемой конверсии - так что проблема по-прежнему активна в 2017 году в некотором смысле. Я был несколько шокирован тем, что документация numpy не дает простого алгоритма преобразования, но эта другая история.

Я столкнулся с другим способом сделать преобразование, которое включает только модули numpy и datetime, для импорта не требуется импортировать pandas, который, как мне кажется, содержит много кода для импорта для такого простой конвертация. Я заметил, что datetime64.astype(datetime.datetime) вернет объект datetime.datetime, если исходный datetime64 находится в микросекундных единицах, в то время как другие единицы возвращают целочисленную метку времени. Я использую модуль xarray для ввода/вывода данных из файлов Netcdf, который использует 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 с недавним дистрибутивом Anaconda 2017 года. Я только посмотрел на скалярное преобразование и не проверил преобразования на основе массива, хотя я предполагаю, что это будет хорошо. Я также не посмотрел исходный код 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)

Я собираюсь держать это в сумке для инструмента, что-то подсказывает мне, что мне понадобится еще раз.

Ответ 10

действительно, все эти типы datetime могут быть трудными и потенциально проблематичными (необходимо внимательно следить за информацией о часовом поясе). вот что я сделал, хотя я признаю, что меня беспокоит, что по крайней мере часть его "не по дизайну". Кроме того, это может быть сделано немного более компактным по мере необходимости. начиная с numpy.datetime64 dt_a:

dt_a

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

dt_a1 = dt_a.tolist() # дает объект datetime в 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'))

... и, конечно, это может быть сжато в одну строку по мере необходимости.

Ответ 11

import numpy as np
import pandas as pd 

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

используйте эту функцию, чтобы получить собственный объект datetime для pythons

Ответ 12

Некоторые решения работают хорошо для меня, но 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)