web-dev-qa-db-fra.com

obtenir l'horodatage UTC dans python avec date-heure

Existe-t-il un moyen d’obtenir l’horodatage UTC en spécifiant la date? Ce que j'attendrais:

datetime(2008, 1, 1, 0, 0, 0, 0)

devrait aboutir à

 1199145600

La création d'un objet date/heure naïf signifie qu'il n'y a pas d'informations de fuseau horaire. Si je regarde la documentation de datetime.utcfromtimestamp, créer un horodatage UTC signifie laisser de côté les informations de fuseau horaire. Donc, je suppose que la création d’un objet date/heure naïf (comme je l’ai fait) aurait pour résultat un horodatage UTC. Toutefois:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

résulte en

2007-12-31 23:00:00

Y a-t-il encore des informations de fuseau horaire masquées dans l'objet datetime? Qu'est-ce que je fais mal?

71
pat

Qu'est-ce qu'un naïf datetime?

Les objets par défaut datetime sont dits "naïfs": ils conservent les informations de l'heure sans les informations de fuseau horaire. Considérez naïf datetime en tant que nombre relatif (par exemple: +4) sans origine claire (en fait, votre origine sera commune dans toutes les limites de votre système). Pensez à connaître datetime en tant que nombres absolus (c'est-à-dire: 8) ayant une origine commune pour le monde entier.

Sans information de fuseau horaire , vous ne pouvez pas convertir le date/heure "naïf" en une représentation temporelle non naïve (où +4 est-il une cible si nous ne savons pas par où commencer?). C'est pourquoi vous ne pouvez pas utiliser une méthode datetime.datetime.toutctimestamp(). (cf: http://bugs.python.org/issue1457227 )

Pour vérifier si votre datetimedt est naïf, vérifiez dt.tzinfo, si None, alors c'est naïf:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

J'ai des dates naïves, que puis-je faire?

Vous devez faire une hypothèse en fonction de votre contexte particulier: La question que vous devez vous poser est la suivante: votre datetime at-il été sur UTC? ou était-ce l'heure locale?

  • Si vous utilisiez UTC (vous n’avez plus de problèmes):

    import calendar
    
    def dt2ts(dt):
        """Converts a datetime object to UTC timestamp
    
        naive datetime will be considered UTC.
    
        """
    
        return calendar.timegm(dt.utctimetuple())
    
  • Si vous n'utilisiez PAS l'UTC , bienvenue en enfer.

    Vous devez rendre votre datetime non-naïve avant d'utiliser la fonction précédente, en leur rendant le fuseau horaire souhaité.

    Vous aurez besoin du nom du fuseau horaire et des informations indiquant si DST était en vigueur lors de la génération de la date/heure naïve cible (le La dernière information à propos de DST est requise pour les cas de lettres):

    import pytz     ## pip install pytz
    
    mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone
    
    dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly
    

    Conséquences de ne pas fournir is_dst:

    Ne pas utiliser is_dst générera une heure incorrecte (et un horodatage UTC) si la date-heure cible a été générée alors qu'un DST arrière a été mis en place (par exemple, changer l'heure DST en supprimant une heure).

    Fournir is_dst incorrect générera bien sûr une heure incorrecte (et un horodatage UTC) uniquement sur les chevauchements ou les trous DST. Et, lorsque vous fournissez également une heure incorrecte, se produisant dans des "trous" (heure qui n'a jamais existé à cause de l'heure d'été avancée), is_dst donnera une interprétation de la manière de considérer cette heure fictive, et c'est le seul cas où .normalize(..) fera réellement quelque chose ici, car il le traduira alors comme une heure de validité réelle (en modifiant le date/heure ET l'objet DST si nécessaire). Notez que .normalize() n'est pas nécessaire pour obtenir un horodatage UTC correct à la fin, mais qu'il est probablement recommandé si vous n'aimez pas l'idée de présenter des temps erronés dans vos variables, en particulier si vous réutilisez cette variable ailleurs.

    et ÉVITEZ D'UTILISER CE QUI SUIT : (cf: conversion du fuseau horaire Datetime avec pytz )

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    Pourquoi? Parce que .replace() remplace aveuglément le tzinfo sans prendre en compte l'heure cible et choisira un objet DST incorrect. Considérant que .localize() utilise l'heure cible et votre indicateur is_dst pour sélectionner le bon objet DST.

ANCIENNE réponse incorrecte (merci @ J.F.Sebastien pour l'avoir signalé):

Espérons qu'il est assez facile de deviner le fuseau horaire (votre origine locale) lorsque vous créez votre objet naïf datetime car il est lié à la configuration système et ne devrait pas changer entre la création d'objet datetime naïf et le moment où vous souhaitez l'obtenir. l'horodatage UTC. Cette astuce peut être utilisée pour donner une question imparfaite .

En utilisant time.mktime, nous pouvons créer un utc_mktime:

def utc_mktime(utc_Tuple):
    """Returns number of seconds elapsed since Epoch

    Note that no timezone are taken into consideration.

    utc Tuple must be: (year, month, day, hour, minute, second)

    """

    if len(utc_Tuple) == 6:
        utc_Tuple += (0, 0, 0)
    return time.mktime(utc_Tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))

def datetime_to_timestamp(dt):
    """Converts a datetime object to UTC timestamp"""

    return int(utc_mktime(dt.timetuple()))

Vous devez vous assurer que votre objet datetime est créé sur le même fuseau horaire que celui qui a créé votre datetime.

Cette dernière solution est incorrecte car elle suppose que le décalage UTC est désormais identique au décalage UTC depuis Epoch. Ce qui n'est pas le cas pour beaucoup de fuseaux horaires (à l'année pour les décalages de l'heure d'été (DST)).

76
vaab

Une autre possibilité est:

d = datetime.datetime.utcnow()
Epoch = datetime.datetime(1970,1,1)
t = (d - Epoch).total_seconds()

Cela fonctionne car "d" et "Epoch" sont des dates-heures naïves rendant l'opérateur "-" valide et renvoyant un intervalle. total_seconds() transforme l'intervalle en secondes. Notez que total_seconds() renvoie un float, même d.microsecond == 0

23
Chris Cogdon

Notez également que calendar.timegm () fonctionne comme décrit par this entrée de blog:

import calendar
calendar.timegm(utc_timetuple)

Le résultat devrait correspondre à la solution de vaab.

19
Mr. Mr.

Si l'objet date/heure en entrée est au format UTC:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

Remarque: il retourne float, c'est-à-dire que les microsecondes sont représentées sous forme de fractions de seconde.

Si l'objet de date saisi est en UTC:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

Voir plus de détails à la page Conversion de datetime.date en horodatage UTC en Python .

12
jfs

Je pense que la réponse principale n’est toujours pas aussi claire et qu’il vaut la peine de prendre le temps de comprendre temps et fuseaux horaires.

La chose la plus importante à comprendre dans le traitement du temps est que le temps est relatif!

  • 2017-08-30 13:23:00: (une date et heure naïve), représente un temps local quelque part dans le monde, mais notez que 2017-08-30 13:23:00 à Londres est PAS LE MÊME TEMPS que 2017-08-30 13:23:00 à San Francisco.

Étant donné que la même chaîne temporelle peut être interprétée comme différents points dans le temps, cela dépend de votre position dans le monde. Par conséquent, une notion de temps absolue est nécessaire.

Un horodatage UTC est un nombre en secondes (ou millisecondes) de Epoch (défini comme 1 January 1970 00:00:00 à GMT fuseau horaire +00: 00 offset).

Epoch est ancré sur le fuseau horaire GMT et constitue donc un point absolu dans le temps. Un horodatage UTC étant un offset à partir d'une heure absolue définit donc un absolu heure .

Ceci permet de classer les événements dans le temps.

Sans information de fuseau horaire, l'heure est relative et ne peut pas être convertie en une notion absolue absolue sans indiquer le fuseau horaire auquel la date/heure naïve doit être ancrée. .

Quels sont les types de temps utilisés dans un système informatique?

  • Date/heure naïve : généralement pour l'affichage, en heure locale (c'est-à-dire dans le navigateur), où le système d'exploitation peut fournir des informations sur le fuseau horaire au programme.

  • Horodatage UTC : un horodatage UTC est un instant absolu, comme mentionné ci-dessus, mais il est ancré dans un fuseau horaire donné, de sorte qu'un horodatage UTC peut être converti en date/heure dans tout fuseau horaire , mais pas contient informations sur le fuseau horaire. Qu'est-ce que ça veut dire? Cela signifie que 1504119325 correspond à 2017-08-30T18:55:24Z, ou 2017-08-30T17:55:24-0100 ou aussi 2017-08-30T10:55:24-0800. Il ne vous dit pas d'où vient la date et l'heure enregistrées. Il est généralement utilisé du côté serveur pour enregistrer des événements (journaux, etc ...) ou pour convertir un date/heure en connaissance de timezone à un point absolu dans le temps et calcule le décalage horaire .

  • Date-heure ISO-8601 chaîne: La norme ISO-8601 est un format normalisé pour enregistrer la date et l'heure avec un fuseau horaire. (Il s'agit en fait de plusieurs formats, lisez ce qui suit: https://en.wikipedia.org/wiki/ISO_8601 ) Il est utilisé pour communiquer des informations de date/heure sensibles au fuseau horaire de manière sérialisable entre les systèmes.

Quand utiliser lequel? ou plutôt quand avez-vous besoin de vous soucier des fuseaux horaires?

  • Si vous devez vous préoccuper de l'heure , vous avez besoin d'informations de fuseau horaire. Un calendrier ou une alarme a besoin de l'heure pour organiser une réunion au bon moment pour tous les utilisateurs du monde. Si ces données sont enregistrées sur un serveur, le serveur doit savoir à quel fuseau horaire correspond le fuseau horaire.

  • L’horodatage UTC suffit pour calculer les différences de temps entre des événements venant de différents endroits du monde, mais vous perdez la possibilité d’analyser à quel moment de la journée les événements se sont produits (par exemple, pour l’analyse Web, vous voudrez peut-être savoir quand site à leur heure locale : voyez-vous plus d'utilisateurs le matin ou le soir? Vous ne pouvez pas comprendre cela sans informations sur l'heure.

Décalage du fuseau horaire dans une chaîne de date :

Un autre point important est que le décalage du fuseau horaire dans une chaîne de date est non fixé . Cela signifie que parce que 2017-08-30T10:55:24-0800 dit le décalage -0800 ou 8 heures en arrière, ça ne veut pas dire que ça le sera toujours!

En été, il se peut que l’heure soit au crépuscule et qu’il soit -0700

Cela signifie que le décalage du fuseau horaire (+0100) n’est pas identique à nom du fuseau horaire (Europe/France) ou même désignation du fuseau horaire (CET)

America/Los_Angeles le fuseau horaire est un place dans le monde, mais il se transforme en PST (Pacific Standard Heure) notation de décalage horaire en hiver et PDT (heure avancée du Pacifique) en été.

Ainsi, en plus d'obtenir le décalage de fuseau horaire de la chaîne de données, vous devez également obtenir le nom du fuseau horaire pour qu'il soit précis.

La plupart des forfaits seront capables de convertir eux-mêmes les décalages numériques de l'heure d'été en heure standard, mais ce n'est pas nécessairement trivial avec juste un décalage. Par exemple, WAT désignation du fuseau horaire en Afrique occidentale, correspond à UTC + 0100, tout comme CET fuseau horaire en France, mais la France observe l'heure d'été, alors que l'Afrique de l'Ouest ne le fait pas (car ils sont proches du équateur)

Donc, en bref, c'est compliqué. TRÈS compliqué, et c'est pourquoi vous ne devriez pas le faire vous-même, mais faites confiance à un paquet qui le fait pour vous et gardez-le à jour!

7
MrE

Il existe en effet un problème d'utilisation de utcfromtimestamp et de la spécification des fuseaux horaires. Un bel exemple/explication est disponible sur la question suivante:

Comment spécifier le fuseau horaire (UTC) lors de la conversion en heure Unix? (Python)

1
CamilleLDN

La réponse acceptée ne semble pas fonctionner pour moi. Ma solution:

import time
utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple()))
def datetime2ts(dt):
    """Converts a datetime object to UTC timestamp"""
    return int(time.mktime(dt.utctimetuple())) - utc_0
0
dreamingcloud