web-dev-qa-db-fra.com

Conversion entre date/heure, horodatage et date/heure64

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

Dans le code suivant, je crée un objet 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 la date et l'heure de l'horodatage:

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

Mais comment extraire-t-on la datetime ou Timestamp à partir d'un numpy.datetime64 (dt64)?

.

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

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

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

216
Andy Hayden

Pour convertir numpy.datetime64 en objet datetime représentant l'heure en UTC le 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é par np.datetime64 en tant qu'heure au format UTC.


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

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

Cela 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 utiliseriez np.int8, np.int16, etc. et appliquez les mêmes méthodes pour convertir entre des objets Python tels que int, date-heure et objets numpy correspondants.

Votre "mauvais exemple" 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 valeur long sur numpy-1.8.0 installé en tant que:

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 retourne long car pour numpy.datetime64, type .astype(datetime) est équivalent à .astype(object) qui renvoie un entier Python (long) sur 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 peut changer dans les futures versions de numpy.

102
jfs

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

Conversions between time representations

157
Quant

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

De plus, pandas.to_datetime peut être utilisé (ceci n’est pas dans la version dev, n’a pas vérifié la version 0.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))
108
Wes McKinney

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, les objets datetime64/timedelta64 de numpy et les objets Timestamp/Timedelta de pandas.

La bibliothèque standard datetime de Python

La bibliothèque standard datetime a quatre objets principaux

  • time - seul le temps, mesuré en heures, minutes, secondes et microsecondes
  • date - seulement année, mois et jour
  • datetime - Tous les composants de l'heure et de la date
  • timedelta - Une durée avec un nombre maximal de jours

Créer 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 distincts, mais un seul objet datetime64 pour représenter un moment unique. 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 définir sa précision d'heures à attosecondes (10 ^ -18). Son constructeur est plus flexible et peut prendre diverses 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: le 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')

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

Un horodatage de pandas est un moment très similaire à un datetime mais avec beaucoup plus de fonctionnalités. Vous pouvez les construire avec pd.Timestamp ou 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 en horodatage

>>> 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 date et heure et en horodatage

>>> 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 l'horodatage en datetime et datetime64

C'est assez facile car les horodatages des 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')
59
Ted Petrou
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

Pour DatetimeIndex, la tolist renvoie une liste d'objets datetime. Pour un seul objet datetime64, il retourne un seul objet datetime.

25
eumiro

Si vous souhaitez convertir une série entière de dates-heures de pandas en dates-heures python standard, 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>)
....
8
fantabolous

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

Note: il n'est pas égal à dt car c'est devenu "offset-aware" :

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 du "mauvais exemple":

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

Ce poste existe depuis 4 ans et le problème de la conversion me causait toujours des difficultés. Le problème est donc toujours actif en 2017. J'ai été quelque peu choqué par le fait que la documentation numpy n'offre pas facilement un algorithme de conversion simple, mais c'est une autre histoire.

J'ai trouvé une autre façon de faire la conversion qui implique uniquement les modules numpy et datetime, elle n'exige pas que les pandas soient importés, ce qui me semble être beaucoup de code à importer pour une conversion aussi simple. J'ai remarqué que datetime64.astype(datetime.datetime) retournera un objet datetime.datetime si le datetime64 original est dans unités de micro-seconde alors que les autres unités renvoient un horodatage entier. J'utilise le module xarray pour les E/S de données à partir de fichiers Netcdf utilisant le datetime64 en nanosecondes. La conversion échoue, à moins que vous ne convertissiez d'abord en unités de micro-seconde. 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

Son seul test sur ma machine, qui est Python 3.6 avec une distribution récente 2017 Anaconda. J'ai seulement regardé la conversion scalaire et je n'ai pas vérifié les conversions basées sur les tableaux, bien que je suppose que ce sera bien. Je n'ai pas non plus regardé le code source numpy datetime64 pour voir si l'opération est logique ou non.

4
ndl303

Je suis revenu sur cette réponse plus de fois que je ne pouvais compter, alors j'ai décidé de lancer une petite classe rapide qui convertit une valeur Numpy datetime64 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 mon sac à outils, quelque chose me dit que j'en aurai encore besoin.

1
MikeyE

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

dt_a

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

dt_a1 = dt_a.tolist () # donne 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 ligne si nécessaire.

0
yoder
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 date/heure natif pythons

0
Crystal