Преобразование между datetime, Timestamp и datetime64


292

Как мне преобразовать 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или Timestampиз numpy.datetime64( dt64)?

,

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

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

что должно быть datetime.datetime(2002, 6, 28, 1, 0), а не долго (!) ( 1025222400000000000L) ...


2
Вы , вероятно , следует принять ответ @Wes МакКинни в том , что гораздо короче , и должен работать на последних numpy, pandasверсий.
Jfs

@JFSebastian Хммм, значит ли это, что ответ «не переходить от np.datetime к datetime» ... просто используйте pd.Timestamp (так как он в любом случае является подклассом datetime), или если вы действительно должны его использовать pd.Timestamp(dt64).to_datetime(). Я все еще немного недоволен этим, но, конечно, Уэс менее специфичен для моей старой проблемы (и тем лучше для мира)! Еще раз спасибо, что нашли время, чтобы ответить на него. :)
Энди Хейден

Ваш вопрос говорит «или Timestamp» и Timestampявляется datetime(подклассом) в любом случае :)
JFS

3
Для тех, кто придет на этот вопрос в 2017+, посмотрите мой ответ ниже для подробного учебника по datetime, datetime64 и Timestamps: stackoverflow.com/a/46921593/3707607
Тед Петру

Ответы:


134

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


1
Боюсь, что это не всегда работает: например dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), что дает длинный ( 1025222400000000000L) (!)
Энди Хейден

@hayden: попробуй type(dt64). dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
JFS

@JFSebastian type(dt64)- это numpy.datetime64и dt64.astype(datetime)есть тот же длинный int ...: s
Энди Хейден

@hayden: Какая у тебя клочья версия? Моя: numpy.__version__->'1.6.1'
JFS

Версия 1.8.0 (в python 2.7.3), если она работает для вас, значит, это ошибка в моей системе!
Энди Хейден

212

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

Преобразования между представлениями времени


2
Ницца!!! (Стоит отметить, что ситуация улучшилась с тех пор, как я написал этот вопрос, здесь проделана большая работа :))
Энди Хейден,

107
Просто взглянув на эту диаграмму, я понял, что во всем этом времени что-то не так.
сумасшедший ежик

4
Это очень запутанно, что pd.to_datetime будет производить метку времени, если дано количество мс или нс, но будет производить datetime.datetime, если дано datetime.datetime или np.datetime64, если дано np.datetime64 ... Зачем кому-то думаете это разумно?
Mr.WorshipMe

7
@ Mr.WorshipMe Эта диаграмма должна быть обновлена. pd.to_datetimeпреобразует все в pd.Timestamp. У pd.Timestampобъекта есть метод to_pydatetimeдля возврата обратно к datetime.datetimeобъекту и to_datetime64метод для преобразования np.datetime64.
Тед Петру

2
Как я могу получить более высокое разрешение этой картинки?
user3226167

137

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

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

7
pd.to_datetime('2012-05-01T01:00:00.000000+0100')возвращается Timestamp('2012-05-01 00:00:00')хотя бы в пандах 0.17.1.
Антон Протопопов

97

Я думаю, что ответ может быть более консолидированным, чтобы лучше объяснить взаимосвязь между модулем datetime в Python, datetime64 / timedelta64 от numpy и объектами 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)

Объекты datetime64 и timedelta64 в NumPy

NumPy не имеет отдельных объектов даты и времени, только один объект datetime64, представляющий один момент времени. Объект datetime модуля datetime имеет микросекундную точность (одна миллионная доли секунды). Объект datetime64 в NumPy позволяет вам устанавливать его точность от часов до аттосекунд (10 ^ -18). Его конструктор более гибкий и может принимать различные входные данные.

Создайте объекты datetime64 и timedelta64 в NumPy

Передайте целое число со строкой для единиц. Посмотреть все единицы здесь . Он преобразован в такое количество единиц после эпохи 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.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')

Конвертировать из 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')

3
Это сумасшествие, как нудистка к свиданиям все еще трудна / хакерна ... разве нет лучшего способа? Это хороший ответ, я думаю о том, чтобы согласиться перевести его на верхний уровень, и я должен прочесть остальные один раз с помощью компьютера.
Энди Хейден

Что в этом странного? Отметки времени панд работают хорошо и довольно просты.
Тед Петру

2
Numpy для даты и времени.
Энди Хейден

1
Я думаю, что это лучший ответ, который я когда-либо видел. Исходя из Excel, VBA, SAS или SQL, Python кажется странным, потому что не существует только одного способа работы с датами / временем. Как и во многих вещах в Python или R, кажется, что нужно выбрать любимый метод / модуль / класс и придерживаться его.
Шон Маккарти

Удивительный ответ
gioxc88

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

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


Я действительно должен был попробовать все методы :) (Я шокирован тем, как долго я боролся с этим) Спасибо
Энди Хейден

5
@hayden, если вы знаете, что это скалярный / 0-d массив, я бы предпочел использовать его, .item()который гораздо более явный (и никто не может прийти в себя и начать утверждать, что он должен возвращать список).
Себерг

1
Боюсь, что это не всегда работает: например dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), что дает длинный ( 1025222400000000000L) (!)
Энди Хейден

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')использует ms, numpy.datetime64('2012-05-01T00:00:00.000000000')использует ns. Вы можете открыть вопрос, если сочтете это непонятным.
JFS

@AndyHayden Вы также можете просто добавить дополнительный аргумент 'us' или 'ms', чтобы убедиться, что применяется тот же формат, в результате чего тот же элемент datetime создается в tolist ()
NM

11

Если вы хотите преобразовать целую серию дат и времени панд в обычные даты-питоны, вы также можете использовать .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()каждую отдельную дату / время64, используя понимание списка или что-то подобное:

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)

Спасибо Энди за то, что поделился этим советом. По какой-то причине я не могу заставить это работать, как я обсуждаю здесь: stackoverflow.com/questions/22825349/…
Амелио Васкес-Рейна

@ user815423426 это никогда не было очень надежным решением, я думаю, вы можете передать формат конструктору datetime, чтобы он работал более широко. Хотя и не очень пандистично!
Энди Хейден

8

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

Я нашел другой способ сделать преобразование, которое включает только модули numpyи datetimeне требует импорта панд, что мне кажется большим количеством кода для импорта для такого простого преобразования. Я заметил, что 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 года. Я только посмотрел на скалярное преобразование и не проверял преобразования на основе массива, хотя я предполагаю, что это будет хорошо. Также я не посмотрел на обалденный исходный код datetime64, чтобы понять, имеет ли эта операция смысл или нет.


Это круто. Спасибо за это.
Ю Чен,

Хорошая вещь. Спасибо.
misantroop

1

Я возвращался к этому ответу больше раз, чем могу сосчитать, поэтому я решил собрать небольшой быстрый класс, который преобразует datetime64значение Numpy в значение 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()

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


Я получил сообщение об ошибкеreplace() got an unexpected keyword argument 'tzinfo'
ogogmad

какую версию панд вы используете? У меня есть версия: 0.18.1 (pand show pandas)
Crystal

такой же как ты. , ,
Огогмад

Я не знаю тогда, но это работает для меня как шарм. 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 () # возвращает объект datetime в UTC, но без tzinfo

dt_a1

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

# now, make your "aware" datetime:

dt_a2 = datetime.datetime (* список (dt_a1.timetuple () [: 6]) + [dt_a1.microsecond], tzinfo = pytz.timezone ('UTC'))

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


docs.scipy.org/doc/numpy/reference/… за изменения в обработке часовых поясов .
hpaulj

Пожалуйста, editсоблюдайте правильность: форматирование кода, форматирование цитаты и форматирование текста. Кроме того, соблюдайте правильную
прописную букву
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.