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
) ...
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.
Vous pouvez simplement utiliser le constructeur pd.Timestamp. Le diagramme suivant peut être utile pour cette question et les questions connexes.
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))
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 a quatre objets principaux
>>> 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 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.
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')
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)
>>> 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')
>>> 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')
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')
>>> 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
.
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>)
....
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)
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.
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.
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.
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