Перетворення між датою, міткою та датою64


291

Як перетворити numpy.datetime64об'єкт у datetime.datetime(абоTimestamp )?

У наступному коді я створюю об'єкти datetime, timetamp and 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 Hmmm, чи означає це, що відповідь "не переходити з np.datetime на дату" ... просто використовуйте pd.Timestamp (так як це підклас datetime так чи інакше), або якщо ви дійсно повинні використовувати pd.Timestamp(dt64).to_datetime(). Я все ще трохи незадоволений цим, але, безумовно, Вес менш специфічний для моєї старої проблеми (і так краще для світу)! Ще раз дякую, що знайшли час, щоб відповісти на це. :)
Енді Хейден

Ваше питання говорить «або Timestamp» і Timestampє datetime(підклас) в будь-якому випадку :)
JFS

3
Для тих , хто прибуває на це питання в 2017+, подивіться на мою відповідь нижче для докладного підручник дати і часу, datetime64 і відмітками часу: stackoverflow.com/a/46921593/3707607
Тед Petrou

Відповіді:


133

Для перетворення 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'

Вищенаведений приклад передбачає, що наївний об’єкт дати інтерпретується np.datetime64як час у UTC.


Щоб конвертувати дату в 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 ( 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)

Щоб отримати timetime64, який безпосередньо використовує секунди:

>>> 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 часу і часу є експериментальним і може змінюватись у майбутніх версіях 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 створює TimeStamp, якщо вказується кількість мс або ns, але створює 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
Як я можу отримати більш високу роздільну здатність цього малюнка?
користувач3226167

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

Я думаю, що можна було б зробити більш консолідовані зусилля у відповіді, щоб краще пояснити взаємозв'язок між модулем часу дату Python, числом timetime date64 / timedelta64 і об'єктами Pandaas 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)

Об'єкти dateum64 та timedelta64 NumPy

У NumPy немає окремих об'єктів дати та часу, лише один об'єкт datetime64, який представляє єдиний момент часу. Об'єкт дати модуля datetime має точність мікросекунди (одна мільйонна частина секунди). Об'єкт datetime64 NumPy дозволяє встановити його точність від годин аж до секунди (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')

Тімедельти мають єдине ціле

>>> 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 в 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 в timetime та timetamp

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

Перетворити в Timestamp

>>> 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
Зрозумілий до дат.
Енді Хейден

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

Дивовижний передник
gioxc88

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

Для DatetimeIndex, в tolistповертає список datetimeоб'єктів. Для одного datetime64об’єкта він повертає один datetimeоб'єкт.


Я дійсно повинен був спробувати всі методи :) (Я вражений тим, як довго я боровся з цим) Дякую
Енді Хейден

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

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", щоб забезпечити застосований той самий формат, що призведе до того, що в tolist ()
NM

11

Якщо ви хочете перетворити цілу серію панд datetimes у звичайну дату 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()на кожну окрему дату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 з останнім розповсюдженням 2017 Anaconda. Я дивився лише скалярну конверсію і не перевіряв конверсії на основі масиву, хоча гадаю, що це буде добре. Я також не переглянув numpy 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 (pip show pandas)
Crystal

те саме, що і ти. . .
ogogmad

Я тоді не знаю, але це працює для мене як шарм. pix.toile-libre.org/upload/original/1475645621.png
Crystal

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 () # дає об’єкт дати в 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відповідайте правильному: форматування коду, форматування цитат та форматування тексту. Крім того, будь ласка, дотримуйтесь належної літери, граматики та перевірки на помилки помилок, відповідно до вказівок SO - див.: Як
розміщувати
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.