Conversion entre datetime, Timestamp et datetime64

290

Comment convertir un numpy.datetime64objet en datetime.datetime(ou Timestamp)?

Dans le code suivant, je crée des objets datetime, timestamp et 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')

Remarque: il est facile d'obtenir l'heure et la date de l'horodatage:

In [10]: ts.to_datetime()
Out[10]: datetime.datetime(2012, 5, 1, 0, 0)

Mais comment extraire le datetimeou Timestampd'un numpy.datetime64( dt64)?

.

Mise à jour: un exemple un peu méchant dans mon jeu de données (peut-être l'exemple motivant) semble être:

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

ce qui devrait être datetime.datetime(2002, 6, 28, 1, 0), et pas longtemps (!) ( 1025222400000000000L) ...

Andy Hayden
la source
2
vous devriez probablement accepter la réponse de @Wes McKinney qui est beaucoup plus courte et devrait fonctionner sur ces dernières numpy, les pandasversions.
jfs
@JFSebastian Hmmm, cela signifie-t-il que la réponse est "ne pas passer de np.datetime à datetime" ... utilisez simplement pd.Timestamp (car c'est une sous-classe de datetime de toute façon), ou si vous devez vraiment utiliser pd.Timestamp(dt64).to_datetime(). Je suis encore un peu insatisfait de cela, mais Wes est certainement moins spécifique à mon ancien problème (et donc meilleur pour le monde)! Merci encore d'avoir pris le temps d'y répondre. :)
Andy Hayden
Votre question dit "ou Timestamp" et Timestampest une datetime(une sous-classe de) de toute façon :)
jfs
3
Pour ceux qui viennent à cette question en 2017+, regardez ma réponse ci-dessous pour un tutoriel détaillé de datetime, datetime64 et Timestamps: stackoverflow.com/a/46921593/3707607
Ted Petrou

Réponses:

132

Pour convertir numpy.datetime64en objet datetime qui représente l'heure en UTC sur 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'

L'exemple ci-dessus suppose qu'un objet datetime naïf est interprété np.datetime64comme du temps en UTC.


Pour convertir datetime en np.datetime64 et back ( numpy-1.6):

>>> np.datetime64(datetime.utcnow()).astype(datetime)
datetime.datetime(2012, 12, 4, 13, 34, 52, 827542)

Il fonctionne à la fois sur un seul objet np.datetime64 et sur un tableau numpy de np.datetime64.

Pensez à np.datetime64 de la même manière que vous le feriez pour np.int8, np.int16, etc. et appliquez les mêmes méthodes pour convertir entre les objets Python tels que int, datetime et les objets numpy correspondants.

Votre "exemple désagréable" fonctionne correctement:

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

Je peux reproduire la longvaleur numpy-1.8.0installée sur :

pip install git+https://github.com/numpy/numpy.git#egg=numpy-dev

Le même exemple:

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

Il renvoie longcar for numpy.datetime64type .astype(datetime)est équivalent à .astype(object)celui qui renvoie Python integer ( long) on numpy-1.8.

Pour obtenir un objet datetime, vous pouvez:

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

Pour obtenir datetime64 qui utilise directement les secondes:

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

Les documents numpy indiquent que l'API datetime est expérimentale et pourrait changer dans les futures versions de numpy.

jfs
la source
1
Je crains que cela ne semble pas toujours fonctionner: par exemple dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), ce qui donne un long ( 1025222400000000000L) (!)
Andy Hayden
@hayden: essayez type(dt64). dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
jfs
@JFSebastian type(dt64)est numpy.datetime64et dt64.astype(datetime)est le même long int ...: s
Andy Hayden
@hayden: Quelle est votre version numpy? Mine: numpy.__version__->'1.6.1'
jfs
Version 1.8.0 (en python 2.7.3), si cela fonctionne pour vous, cela suggère qu'il s'agit d'un bug sur mon système!
Andy Hayden
212

Vous pouvez simplement utiliser le constructeur pd.Timestamp. Le diagramme suivant peut être utile pour cette question et les questions connexes.

Conversions entre représentations temporelles

Quant
la source
2
Agréable!!! (À noter que la situation s'est améliorée depuis que j'ai écrit cette question, beaucoup de travail a été fait ici :))
Andy Hayden
107
Le simple fait de regarder ce diagramme me dit qu'il y a quelque chose de fondamentalement mauvais avec tout ce temps.
hérisson dément
4
Il est très déroutant que pd.to_datetime produise un TimeStamp si on lui donne le nombre de ms ou ns, mais produira un datetime.datetime si on lui donne un datetime.datetime ou un np.datetime64 si on lui donne un np.datetime64 ... Pourquoi quelqu'un pense que c'est raisonnable?
Mr.WorshipMe
7
@ Mr.WorshipMe Ce diagramme doit être mis à jour. pd.to_datetimeconvertit tout pd.Timestamp. Un pd.Timestampobjet a la méthode to_pydatetimepour revenir à un datetime.datetimeobjet et une to_datetime64méthode pour convertir np.datetime64.
Ted Petrou
2
Comment puis-je obtenir une résolution plus élevée de cette photo?
user3226167
137

Bienvenue en enfer.

Vous pouvez simplement passer un objet datetime64 à pandas.Timestamp:

In [16]: Timestamp(numpy.datetime64('2012-05-01T01:00:00.000000'))
Out[16]: <Timestamp: 2012-05-01 01:00:00>

J'ai remarqué que cela ne fonctionne pas correctement dans NumPy 1.6.1:

numpy.datetime64('2012-05-01T01:00:00.000000+0100')

En outre, pandas.to_datetimepeut être utilisé (ce qui est hors de la version dev, ne sont pas vérifiées 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))
Wes McKinney
la source
5
Vous devez mentionner que issubclass(pd.Timestamp, datetime)c'est True. Et la Timestampclasse elle-même a une to_datetime()méthode.
jfs
7
pd.to_datetime('2012-05-01T01:00:00.000000+0100')revient Timestamp('2012-05-01 00:00:00')au moins chez les pandas 0.17.1.
Anton Protopopov
96

Je pense qu'il pourrait y avoir un effort plus consolidé dans une réponse pour mieux expliquer la relation entre le module datetime de Python, datetime64 / timedelta64 de numpy et les objets Timestamp / Timedelta des pandas.

La bibliothèque standard datetime de Python

La bibliothèque standard datetime a quatre objets principaux

  • temps - seul temps, mesuré en heures, minutes, secondes et microsecondes
  • date - uniquement année, mois et jour
  • datetime - Toutes les composantes de l'heure et de la date
  • timedelta - Un temps avec une unité de jours maximum

Créez ces quatre objets

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

Objets datetime64 et timedelta64 de NumPy

NumPy n'a pas d'objets de date et d'heure séparés, juste un seul objet datetime64 pour représenter un seul instant dans le temps. L'objet datetime du module datetime a une précision en microsecondes (un millionième de seconde). L'objet datetime64 de NumPy vous permet de régler sa précision des heures jusqu'à attosecondes (10 ^ -18). Son constructeur est plus flexible et peut prendre une variété d'entrées.

Construire les objets datetime64 et timedelta64 de NumPy

Passez un entier avec une chaîne pour les unités. Voir toutes les unités ici . Il est converti en autant d'unités après l'époque UNIX: 1 janvier 1970

>>> np.datetime64(5, 'ns') 
numpy.datetime64('1970-01-01T00:00:00.000000005')

>>> np.datetime64(1508887504, 's')
numpy.datetime64('2017-10-24T23:25:04')

Vous pouvez également utiliser des chaînes tant qu'elles sont au format ISO 8601.

>>> np.datetime64('2017-10-24')
numpy.datetime64('2017-10-24')

Les timedeltas ont une seule unité

>>> np.timedelta64(5, 'D') # 5 days
>>> np.timedelta64(10, 'h') 10 hours

Peut également les créer en soustrayant deux objets datetime64

>>> np.datetime64('2017-10-24T05:30:45.67') - np.datetime64('2017-10-22T12:35:40.123')
numpy.timedelta64(147305547,'ms')

Pandas Timestamp et Timedelta construisent beaucoup plus de fonctionnalités en plus de NumPy

Un horodatage pandas est un moment très semblable à un datetime mais avec beaucoup plus de fonctionnalités. Vous pouvez les construire avec pd.Timestampou 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 fonctionne de manière très similaire (avec quelques options supplémentaires) et peut convertir une liste de chaînes en horodatages.

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

Conversion de datetime Python en datetime64 et 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')

Conversion de numpy datetime64 en datetime et 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)

Convertir en horodatage

>>> pd.Timestamp(dt64)
Timestamp('2017-10-24 05:34:20.123456')

Conversion de timestamp en datetime et datetime64

C'est assez facile car les horodatages pandas sont très puissants

>>> 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')
Ted Petrou
la source
3
C'est fou à quel point numpy to datetime est toujours difficile / hacky ... n'y a-t-il vraiment pas de meilleure façon? C'est une bonne réponse, je pense à accepter de le déplacer au niveau supérieur je dois lire les autres plus profondément une fois par ordinateur.
Andy Hayden
Qu'est-ce qui est si bizarre? Les horodatages Pandas fonctionnent bien et sont assez simples.
Ted Petrou
2
Numpy à datetime.
Andy Hayden
1
Je pense que c'est la meilleure réponse que j'aie jamais vue. Venant d'Excel, VBA, SAS ou SQL, Python semble bizarre car il n'y a pas qu'une "façon" de travailler avec les dates / heures. Comme pour beaucoup de choses en Python ou R, il semble que l'on doive choisir une méthode / module / classe préférée et s'y tenir.
Sean McCarthy
Ansewer incroyable
gioxc88
29
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

Pour DatetimeIndex, le tolistrenvoie une liste d' datetimeobjets. Pour un seul datetime64objet, il renvoie un seul datetimeobjet.

eumiro
la source
J'aurais vraiment dû essayer toutes les méthodes :) (Je suis choqué de voir combien de temps je me débattais avec celle-ci) Merci
Andy Hayden
5
@hayden si vous savez que c'est un tableau scalaire / 0-d, je préfère utiliser .item()ce qui est beaucoup plus explicite (et personne ne peut venir et commencer à argumenter qu'il devrait retourner une liste).
seberg
1
Je crains que cela ne semble pas toujours fonctionner: par exemple dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), ce qui donne un long ( 1025222400000000000L) (!)
Andy Hayden
4
@hayden: le type renvoyé par .item()(suggéré par @seberg), .tolist()dépend des unités utilisées par datetime64, par exemple, Dproduit datetime.date(), us(microsecondes) produit datetime.datetime(), ns(nanosecondes) produit long. Et les unités changent en fonction des valeurs d'entrée, par exemple, numpy.datetime64('2012-05-01')utilisations 'D', numpy.datetime64('2012-05-01T00:00:00.000')utilisations ms, numpy.datetime64('2012-05-01T00:00:00.000000000')utilisations ns. Vous pouvez ouvrir un problème si vous le trouvez déroutant.
jfs
@AndyHayden Vous pouvez également simplement ajouter un argument supplémentaire, «us» ou «ms» pour garantir que le même format est appliqué, ce qui entraîne la production du même élément datetime dans tolist ()
NM
11

Si vous souhaitez convertir une série entière d'heures de données pandas en heures régulières de python, vous pouvez également utiliser .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)
   ....

Il prend également en charge les fuseaux horaires:

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

REMARQUE : Si vous utilisez une série Pandas, vous ne pouvez pas appeler to_pydatetime()la série entière. Vous devrez appeler .to_pydatetime()chaque datetime64 individuel en utilisant une compréhension de liste ou quelque chose de similaire:

datetimes = [val.to_pydatetime() for val in df.problem_datetime_column]
fantabolique
la source
10

Une option consiste à utiliser str, puis to_datetime(ou similaire):

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

Remarque: il n'est pas égal à dtcar il est devenu "compatible avec le décalage" :

In [13]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[13]: datetime.datetime(2012, 5, 1, 1, 0)

Cela semble inélégant.

.

Mise à jour: cela peut traiter de "l'exemple désagréable":

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)
Andy Hayden
la source
Merci Andy d'avoir partagé ce conseil. Pour une raison quelconque, je ne suis pas en mesure de le faire fonctionner, comme je l'explique ici: stackoverflow.com/questions/22825349/…
Amelio Vazquez-Reina
@ user815423426 ce n'était jamais une solution très robuste, je suppose que vous pouvez passer un format au constructeur datetime pour travailler plus généralement. Pas très pandastique cependant!
Andy Hayden
8

Ce message existe depuis 4 ans et j'ai toujours eu du mal avec ce problème de conversion - donc le problème est toujours actif en 2017 dans un certain sens. J'ai été quelque peu choqué que la documentation numpy n'offre pas facilement un algorithme de conversion simple, mais c'est une autre histoire.

Je suis tombé sur une autre façon de faire la conversion qui n'implique que des modules numpyet datetime, il ne nécessite pas d'importer des pandas, ce qui me semble être beaucoup de code à importer pour une conversion aussi simple. J'ai remarqué que datetime64.astype(datetime.datetime)retournera un datetime.datetimeobjet si l'original datetime64est en micro-secondes tandis que les autres unités renvoient un horodatage entier. J'utilise un module xarraypour les E / S de données à partir de fichiers Netcdf qui utilise les datetime64unités en nanosecondes, ce qui fait échouer la conversion, sauf si vous convertissez d'abord en unités micro-secondes. Voici l'exemple de code de conversion,

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

Il est uniquement testé sur ma machine, qui est Python 3.6 avec une récente distribution Anaconda 2017. Je n'ai regardé que la conversion scalaire et je n'ai pas vérifié les conversions basées sur les tableaux, même si je suppose que ce sera bon. Je n'ai pas non plus regardé le code source de numpy datetime64 pour voir si l'opération a du sens ou non.

ndl303
la source
C'est bien. Merci d'avoir fait ça.
Yu Chen
Bon produit. Je vous remercie.
misantroop
1

Je suis revenu à cette réponse plus de fois que je ne peux en compter, j'ai donc décidé de créer une petite classe rapide, qui convertit une datetime64valeur Numpy en valeur Python datetime. J'espère que cela aide les autres là-bas.

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)

Je vais garder ça dans ma trousse à outils, quelque chose me dit que j'en aurai encore besoin.

MikeyE
la source
2
Tu pourrais juste le fairets.to_pydatetime()
Ted Petrou
0
import numpy as np
import pandas as pd 

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

utiliser cette fonction pour obtenir un objet datetime natif pythons

Cristal
la source
J'ai une erreur en disantreplace() got an unexpected keyword argument 'tzinfo'
ogogmad
quelle version de pandas utilisez-vous? J'ai la version: 0.18.1 (pip show pandas)
Crystal
même chose que vous. . .
ogogmad
Je ne sais pas alors mais ça marche pour moi comme du charme. pix.toile-libre.org/upload/original/1475645621.png
Crystal
0

Certaines solutions fonctionnent bien pour moi, mais numpy dépréciera certains paramètres. La solution qui fonctionne mieux pour moi est de lire la date en tant que date / heure pandas et d'excréter explicitement l'année, le mois et le jour d'un objet pandas. Le code suivant fonctionne pour la situation la plus courante.

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)
João Gabriel John
la source
-1

en effet, tous ces types de datetime peuvent être difficiles et potentiellement problématiques (doivent garder une trace précise des informations de fuseau horaire). voici ce que j'ai fait, bien que j'avoue que je crains qu'au moins une partie ne soit "pas par conception". aussi, cela peut être rendu un peu plus compact au besoin. commençant par un numpy.datetime64 dt_a:

dt_a

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

dt_a1 = dt_a.tolist () # renvoie un objet datetime en UTC, mais sans 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'))

... et bien sûr, cela peut être compressé en une seule ligne au besoin.

yoder
la source
docs.scipy.org/doc/numpy/reference/… pour les changements dans la gestion du fuseau horaire.
hpaulj
Veuillez vous editconformer à la bonne mise en forme du code, à la mise en forme des devis et à la mise en forme du texte. En outre, s'il vous plaît adhérer à la capitalisation adéquate, la grammaire, et vérifier les fautes de frappe, selon les directives SO - voir: Comment publier et exemples de code
SherylHohman