Comment convertir une chaîne d'heure locale en UTC?

308

Comment convertir une chaîne datetime en heure locale en une chaîne en temps UTC ?

Je suis sûr que je l'ai déjà fait, mais je ne le trouve pas et SO, je l'espère, m'aidera (et d'autres) à le faire à l'avenir.

Clarification : Par exemple, si j'ai 2008-09-17 14:02:00dans mon fuseau horaire local ( +10), je voudrais générer une chaîne avec l'équivalent UTCtemps: 2008-09-17 04:02:00.

De plus, à partir de http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ , notez qu'en général ce n'est pas possible car avec l'heure d'été et d'autres problèmes il n'y a pas de conversion unique de l'heure locale en Heure UTC.

À M
la source
1
Veuillez noter que la méthode mktime () prend une "heure locale" en entrée qui peut ne pas être celle que vous attendiez, je l'ai utilisée et elle a tout gâché. Veuillez jeter un coup d'œil à ce lien
Haifeng Zhang

Réponses:

288

Tout d'abord, analysez la chaîne dans un objet datetime naïf. Il s'agit d'une instance datetime.datetimesans informations de fuseau horaire jointes. Consultez la documentation pour plus datetime.strptimed'informations sur l'analyse de la chaîne de date.

Utilisez le pytzmodule, qui comprend une liste complète des fuseaux horaires + UTC. Déterminez ce qu'est le fuseau horaire local, construisez un objet de fuseau horaire à partir de celui-ci, et manipulez-le et attachez-le à la date / heure naïve.

Enfin, utilisez la datetime.astimezone()méthode pour convertir le datetime en UTC.

Code source, en utilisant le fuseau horaire local "America / Los_Angeles", pour la chaîne "2001-2-3 10:11:12":

import pytz, datetime
local = pytz.timezone ("America/Los_Angeles")
naive = datetime.datetime.strptime ("2001-2-3 10:11:12", "%Y-%m-%d %H:%M:%S")
local_dt = local.localize(naive, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)

À partir de là, vous pouvez utiliser la strftime()méthode pour formater le datetime UTC selon vos besoins:

utc_dt.strftime ("%Y-%m-%d %H:%M:%S")
John Millikin
la source
7
Veuillez modifier votre réponse avec le code suivant: [code] local.localize (naive) [/ code] Voir le document: lien Malheureusement, l'utilisation de l'argument tzinfo des constructeurs standard datetime '' ne fonctionne pas '' avec pytz pour de nombreux fuseaux horaires. >>> datetime (2002, 10, 27, 12, 0, 0, tzinfo = amsterdam) .strftime (fmt) '2002-10-27 12:00:00 AMT + 0020'
Sam Stoelinga
2
Apparemment, l'étape "comprendre ce qu'est le fuseau horaire local" s'avère plus difficile qu'il n'y paraît (pratiquement impossible).
Jason R. Coombs,
2
Utilisez le local.localize comme suggéré par @SamStoelinga, sinon vous ne prendrez pas en compte l'heure d'été.
Emil Stenström
Cette réponse m'a été très utile, mais je voudrais souligner un piège que j'ai rencontré. Si vous fournissez l'heure mais pas la date, vous pouvez obtenir des résultats inattendus. Assurez-vous donc de fournir un horodatage complet.
Steven Mercatante
145

La fonction utcnow () du module datetime peut être utilisée pour obtenir l'heure UTC actuelle.

>>> import datetime
>>> utc_datetime = datetime.datetime.utcnow()
>>> utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2010-02-01 06:59:19'

Comme le lien mentionné ci-dessus par Tom: http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ dit:

L'UTC est un fuseau horaire sans heure d'été et toujours un fuseau horaire sans modifications de configuration dans le passé.

Toujours mesurer et stocker le temps en UTC .

Si vous devez enregistrer où le temps a été pris, stockez-le séparément. Ne stockez pas l'heure locale + les informations de fuseau horaire!

REMARQUE - Si l'une de vos données se trouve dans une région qui utilise l'heure d'été, utilisez pytzet consultez la réponse de John Millikin.

Si vous souhaitez obtenir l'heure UTC à partir d'une chaîne donnée et que vous avez la chance d'être dans une région du monde qui n'utilise pas l'heure d'été, ou si vous avez des données qui sont uniquement décalées de l'heure UTC sans application de l'heure d'été:

-> en utilisant l'heure locale comme base pour la valeur de décalage:

>>> # Obtain the UTC Offset for the current system:
>>> UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now()
>>> local_datetime = datetime.datetime.strptime("2008-09-17 14:04:00", "%Y-%m-%d %H:%M:%S")
>>> result_utc_datetime = local_datetime + UTC_OFFSET_TIMEDELTA
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

-> Ou, à partir d'un décalage connu, en utilisant datetime.timedelta ():

>>> UTC_OFFSET = 10
>>> result_utc_datetime = local_datetime - datetime.timedelta(hours=UTC_OFFSET)
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

METTRE À JOUR:

Depuis python 3.2 datetime.timezoneest disponible. Vous pouvez générer un objet datetime sensible au fuseau horaire avec la commande ci-dessous:

import datetime

timezone_aware_dt = datetime.datetime.now(datetime.timezone.utc)

Si vous êtes prêt à effectuer des conversions de fuseau horaire, lisez ceci:

https://medium.com/@eleroy/10-things-you-need-to-know-about-date-and-time-in-python-with-datetime-pytz-dateutil-timedelta-309bfbafb3f7

monkut
la source
14
Cela ne convertit que l'heure actuelle, je dois prendre n'importe quel temps (sous forme de chaîne) et convertir en UTC.
Tom
Je ne pense pas que cela devrait avoir d'importance ici, si vous utilisez des valeurs de décalage standard. local_time = utc_time + utc_offset ET utc_time = local_time - utc_offset.
Monkut
5
Il ne fonctionne qu'avec l'heure actuelle car les horodatages passés et futurs peuvent avoir un décalage UTC différent en raison de l'heure d'été.
Alex B
bon point ... si vous devez faire face à l'heure d'été, vous devriez probablement utiliser pytz comme mentionné par John Millikin.
monkut
1
Il existe un delta sporadique entre les appels à utcnow () et now (). C'est une ligne de code dangereuse qui pourrait conduire à des erreurs étranges plus tard tzinfo.utcoffset() must return a whole number of minutes, etc.
Pavel Vlasov
62

Merci @rofly, la conversion complète de chaîne en chaîne est la suivante:

time.strftime("%Y-%m-%d %H:%M:%S", 
              time.gmtime(time.mktime(time.strptime("2008-09-17 14:04:00", 
                                                    "%Y-%m-%d %H:%M:%S"))))

Mon résumé des time/ calendarfonctions:

time.strptime
string -> tuple (aucun fuseau horaire appliqué, correspond donc à string)

time.mktime
tuple d'heure locale -> secondes depuis l'époque (toujours heure locale)

time.gmtime
secondes depuis l'époque -> tuple en UTC

et

calendar.timegm
tuple en UTC -> secondes depuis l'époque

time.localtime
secondes depuis l'époque -> tuple dans le fuseau horaire local

À M
la source
4
(always local time)semble être faux: l'entrée de mktime () est l'heure locale, la sortie est en secondes depuis epoch ( 1970-01-01 00:00:00 +0000 (UTC)) qui ne dépend pas du fuseau horaire.
jfs
3
Il y a également 50% de chances qu'il échoue pendant la transition DST. Voir Problèmes avec Localtime
jfs
38

Voici un résumé des conversions de temps Python courantes.

Certaines méthodes perdent des fractions de secondes et sont marquées par (s) . Une formule explicite telle que ts = (d - epoch) / unitpeut être utilisée à la place (merci jfs).

  • struct_time (UTC) → POSIX (s) :
    calendar.timegm(struct_time)
  • Datetime naïf (local) → POSIX (s) :
    calendar.timegm(stz.localize(dt, is_dst=None).utctimetuple())
    (exception lors des transitions DST, voir commentaire de jfs)
  • Datetime naïf (UTC) → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • Datetime conscient → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • POSIX → struct_time (UTC, s ):
    time.gmtime(t)
    (voir commentaire de jfs)
  • Datetime naïf (local) → struct_time (UTC, s ):
    stz.localize(dt, is_dst=None).utctimetuple()
    (exception lors des transitions DST, voir commentaire de jfs)
  • Datetime naïf (UTC) → struct_time (UTC, s ):
    dt.utctimetuple()
  • Datetime conscient → struct_time (UTC, s ):
    dt.utctimetuple()
  • POSIX → Naïve datetime (local):
    datetime.fromtimestamp(t, None)
    (peut échouer dans certaines conditions, voir le commentaire de jfs ci-dessous)
  • struct_time (UTC) → Naïve datetime (local, s ):
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
    (ne peut pas représenter les secondes intercalaires, voir le commentaire de jfs)
  • Datetime naïf (UTC) → Datetime naïf (local):
    dt.replace(tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
  • Datetime conscient → Datetime naïf (local):
    dt.astimezone(tz).replace(tzinfo=None)
  • POSIX → Naïve datetime (UTC):
    datetime.utcfromtimestamp(t)
  • struct_time (UTC) → Naïve datetime (UTC, s ):
    datetime.datetime(*struct_time[:6])
    (ne peut pas représenter les secondes intercalaires, voir le commentaire de jfs)
  • Naïve datetime (local) → Naïve datetime (UTC):
    stz.localize(dt, is_dst=None).astimezone(UTC).replace(tzinfo=None)
    (exception lors des transitions DST, voir commentaire de jfs)
  • Datetime conscient → Datetime naïf (UTC):
    dt.astimezone(UTC).replace(tzinfo=None)
  • POSIX → Datetime conscient:
    datetime.fromtimestamp(t, tz)
    (peut échouer pour les fuseaux horaires non pytz)
  • struct_time (UTC) → Datetime (s) conscient (s) :
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz)
    (ne peut pas représenter les secondes intercalaires, voir le commentaire de jfs)
  • Datetime naïf (local) → Datetime conscient:
    stz.localize(dt, is_dst=None)
    (exception lors des transitions DST, voir commentaire de jfs)
  • Datetime naïf (UTC) → Datetime conscient:
    dt.replace(tzinfo=UTC)

Source: taaviburns.ca

akaihola
la source
1
(1) fromtimestamp(t, None)peut échouer si le fuseau horaire local a un décalage utc différent t et que la bibliothèque C n'a pas accès à la base de données tz sur la plateforme donnée. Vous pouvez utiliser tzlocal.get_localzone()pour fournir des tzdata de manière portable. (2) fromtimestamp(t, tz)peut échouer pour les fuseaux horaires non pytz. (3) datetime(*struct_time[:6])vous manquez *. (4) timegm(), utctimetuple(), des struct_timesolutions à base tomber quelques fractions de seconde. Vous pouvez utiliser une formule explicite telle que: à la ts = (d - epoch) / unitplace.
jfs
1
(5) stz.localize(dt, is_dst=None)lève une exception pour les heures locales ambiguës ou inexistantes, par exemple, pendant les transitions DST. Pour éviter l'exception, l'utilisation stz.normalize(stz.localize(dt))qui peut renvoyer des résultats imprécis. (6) datetime () ne peut pas représenter une seconde intercalaire. Convertissez struct_timeen "secondes depuis l'époque" comme solution de contournement en premier. (7) time.gmtime(t)contrairement à ce qui calendar.timegm()peut s’attendre à une entrée non-POSIX si un fuseau horaire "correct" est utilisé. Utilisez plutôt la formule explicite si l'entrée est POSIX:gmtime = lambda t: datetime(1970,1,1, tzinfo=utc) + timedelta(seconds=t)
jfs
je souhaite que ce soit dans un tableau, plus facile à lire (c'est dans le lien)
MichaelChirico
1
@MichaelChirico, cette réponse indique que "Nous n'autorisons pas (et n'autoriserons pas) les <table>balises. Désolé. C'est intentionnel et par conception. Si vous avez besoin d'une" table "rapide et sale, utilisez une <pre>disposition ASCII." Je ne crois pas qu'une table ASCII serait plus lisible que la liste ci-dessus.
akaihola
eh bien c'est dommage. vous avez mon vote positif de toute façon ... peut-être référencer le tableau dans le lien dans votre réponse?
MichaelChirico
25
def local_to_utc(t):
    secs = time.mktime(t)
    return time.gmtime(secs)

def utc_to_local(t):
    secs = calendar.timegm(t)
    return time.localtime(secs)

Source: http://feihonghsu.blogspot.com/2008/02/converting-from-local-time-to-utc.html

Exemple d'utilisation de bd808 : Si votre source est un datetime.datetimeobjet t, appelez comme:

local_to_utc(t.timetuple())
Chuck Callebs
la source
5
Si votre source est un objet datetime.datetime t, appelez en tant que: local_to_utc (t.timetuple ())
bd808
2
.timetuple()appels tm_isdstà -1; il y a 50% de chances d' mktime()échouer pendant la transition DST.
jfs
1
La solution de Chuck perd des informations en millisecondes.
Luca
21

J'ai de la chance avec dateutil (qui est largement recommandé sur SO pour d'autres questions connexes):

from datetime import *
from dateutil import *
from dateutil.tz import *

# METHOD 1: Hardcode zones:
utc_zone = tz.gettz('UTC')
local_zone = tz.gettz('America/Chicago')
# METHOD 2: Auto-detect zones:
utc_zone = tz.tzutc()
local_zone = tz.tzlocal()

# Convert time string to datetime
local_time = datetime.strptime("2008-09-17 14:02:00", '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in local time zone since 
# datetime objects are 'naive' by default
local_time = local_time.replace(tzinfo=local_zone)
# Convert time to UTC
utc_time = local_time.astimezone(utc_zone)
# Generate UTC time string
utc_string = utc_time.strftime('%Y-%m-%d %H:%M:%S')

(Le code a été dérivé de cette réponse pour convertir la chaîne de datetime UTC en datetime local )

Yarin
la source
dateutilpeut échouer pour les dates passées si le fuseau horaire local avait alors un décalage utc différent (sans rapport avec les transitions DST) sur les systèmes où l'implémentation n'utilise pas de base de données de fuseau horaire historique (notamment Windows). pytz+ tzlocalpourrait être utilisé à la place.
jfs
@ JFSebastian- N'en avait pas entendu parler - où pouvons-nous obtenir plus d'informations?
Yarin
prendre une machine Windows, définir n'importe quel fuseau horaire qui avait un décalage utc différent dans le passé, par exemple, Europe / Moscou. Comparez les résultats avec pytz . De plus, vous pouvez tester ce bogue qui échoue même sur Ubuntu, bien que je ne sois pas sûr de l'utilisation correcte de l'API dans ce cas.
jfs
Quelle est la sortie? Veuillez publier la sortie.
not2qubit
18

Un autre exemple avec pytz, mais inclut localize (), qui m'a sauvé la journée.

import pytz, datetime
utc = pytz.utc
fmt = '%Y-%m-%d %H:%M:%S'
amsterdam = pytz.timezone('Europe/Amsterdam')

dt = datetime.datetime.strptime("2012-04-06 10:00:00", fmt)
am_dt = amsterdam.localize(dt)
print am_dt.astimezone(utc).strftime(fmt)
'2012-04-06 08:00:00'
Paulius Sladkevičius
la source
12

J'ai eu le plus de succès avec python-dateutil :

from dateutil import tz

def datetime_to_utc(date):
    """Returns date in UTC w/o tzinfo"""
    return date.astimezone(tz.gettz('UTC')).replace(tzinfo=None) if date.tzinfo else date
Shu Wu
la source
7
import time

import datetime

def Local2UTC(LocalTime):

    EpochSecond = time.mktime(LocalTime.timetuple())
    utcTime = datetime.datetime.utcfromtimestamp(EpochSecond)

    return utcTime

>>> LocalTime = datetime.datetime.now()

>>> UTCTime = Local2UTC(LocalTime)

>>> LocalTime.ctime()

'Thu Feb  3 22:33:46 2011'

>>> UTCTime.ctime()

'Fri Feb  4 05:33:46 2011'
Scipythonee
la source
mktime(dt.timetuple())peut échouer pendant la transition DST . Il y a LocalTimezonedans les documents (cela fonctionne pour la définition de fuseau horaire la plus récente mais peut échouer pour les dates passées (sans rapport avec l'heure d'été))
jfs
5

si vous préférez datetime.datetime:

dt = datetime.strptime("2008-09-17 14:04:00","%Y-%m-%d %H:%M:%S")
utc_struct_time = time.gmtime(time.mktime(dt.timetuple()))
utc_dt = datetime.fromtimestamp(time.mktime(utc_struct_time))
print dt.strftime("%Y-%m-%d %H:%M:%S")
user235042
la source
1
Bien sûr, mais je ne vois pas pourquoi vous préférez cela. Il nécessite une importation supplémentaire et 3 appels de fonction de plus que ma version ...
Tom
% Z et% z imprime toujours les espaces blancs.
Pavel Vlasov
2
c'est incorrect. Il échoue si le fuseau horaire local n'est pas UTC. mktime()attend l'heure locale comme entrée. fromtimestamp()renvoie l'heure locale, pas l'utc. Si vous le résolvez, voyez ces problèmes supplémentaires (comme dateutil, la solution stdlib uniquement peut échouer)
jfs
5

Facile

Je l'ai fait comme ça:

>>> utc_delta = datetime.utcnow()-datetime.now()
>>> utc_time = datetime(2008, 9, 17, 14, 2, 0) + utc_delta
>>> print(utc_time)
2008-09-17 19:01:59.999996

Mise en œuvre de fantaisie

Si vous voulez devenir chic, vous pouvez le transformer en un foncteur:

class to_utc():
    utc_delta = datetime.utcnow() - datetime.now()

    def __call__(cls, t):
        return t + cls.utc_delta

Résultat:

>>> utc_converter = to_utc()
>>> print(utc_converter(datetime(2008, 9, 17, 14, 2, 0)))
2008-09-17 19:01:59.999996
uclatommy
la source
5
cela ne fonctionne pas pour l'heure d'été - par exemple si c'est actuellement l'été et que la date que vous convertissez est en hiver. et la question était de convertir les dates stockées sous forme de chaînes ...
Tom
1
Pour info. Le plus gros problème avec cette méthode (en plus de l'heure d'été) est le peu de millisecondes pendant lequel le delta sera désactivé. Toutes mes invitations de calendrier s'affichent comme désactivées d'une minute.
Nostalg.io
4

Vous pouvez le faire avec:

>>> from time import strftime, gmtime, localtime
>>> strftime('%H:%M:%S', gmtime()) #UTC time
>>> strftime('%H:%M:%S', localtime()) # localtime
Cristian Salamea
la source
3

Que diriez-vous -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

si secondes est Nonealors il convertit l'heure locale en temps UTC sinon convertit le temps écoulé en UTC.

À M
la source
2

Pour se déplacer à l'heure d'été, etc.

Aucune des réponses ci-dessus ne m'a particulièrement aidé. Le code ci-dessous fonctionne pour GMT.

def get_utc_from_local(date_time, local_tz=None):
    assert date_time.__class__.__name__ == 'datetime'
    if local_tz is None:
        local_tz = pytz.timezone(settings.TIME_ZONE) # Django eg, "Europe/London"
    local_time = local_tz.normalize(local_tz.localize(date_time))
    return local_time.astimezone(pytz.utc)

import pytz
from datetime import datetime

summer_11_am = datetime(2011, 7, 1, 11)
get_utc_from_local(summer_11_am)
>>>datetime.datetime(2011, 7, 1, 10, 0, tzinfo=<UTC>)

winter_11_am = datetime(2011, 11, 11, 11)
get_utc_from_local(winter_11_am)
>>>datetime.datetime(2011, 11, 11, 11, 0, tzinfo=<UTC>)
Dantalion
la source
2

Utilisation de http://crsmithdev.com/arrow/

arrowObj = arrow.Arrow.strptime('2017-02-20 10:00:00', '%Y-%m-%d %H:%M:%S' , 'US/Eastern')

arrowObj.to('UTC') or arrowObj.to('local') 

Cette bibliothèque vous facilite la vie :)

Yash
la source
arrow is awesome: arrow.get (datetime.now (), 'local'). to ('utc'). naive
SteveJ
1

J'ai trouvé la meilleure réponse sur une autre question ici . Il utilise uniquement des bibliothèques intégrées python et ne vous oblige pas à entrer votre fuseau horaire local (une exigence dans mon cas)

import time
import calendar

local_time = time.strptime("2018-12-13T09:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
local_seconds = time.mktime(local_time)
utc_time = time.gmtime(local_seconds)

Je republie la réponse ici car cette question apparaît dans google au lieu de la question liée en fonction des mots clés de recherche.

franksands
la source
1

J'ai ce code dans l'un de mes projets:

from datetime import datetime
## datetime.timezone works in newer versions of python
try:
    from datetime import timezone
    utc_tz = timezone.utc
except:
    import pytz
    utc_tz = pytz.utc

def _to_utc_date_string(ts):
    # type (Union[date,datetime]]) -> str
    """coerce datetimes to UTC (assume localtime if nothing is given)"""
    if (isinstance(ts, datetime)):
        try:
            ## in python 3.6 and higher, ts.astimezone() will assume a
            ## naive timestamp is localtime (and so do we)
            ts = ts.astimezone(utc_tz)
        except:
            ## in python 2.7 and 3.5, ts.astimezone() will fail on
            ## naive timestamps, but we'd like to assume they are
            ## localtime
            import tzlocal
            ts = tzlocal.get_localzone().localize(ts).astimezone(utc_tz)
    return ts.strftime("%Y%m%dT%H%M%SZ")
tobixen
la source
0

En python3:

pip install python-dateutil

from dateutil.parser import tz

mydt.astimezone(tz.gettz('UTC')).replace(tzinfo=None) 
spedy
la source
cela ne semble pas fonctionner, il déclenche une exception ValueError: ValueError: astimezone () ne peut pas être appliqué à un datetime naïf
Stormsson
Cela devrait être: from dateutil import tz
Javier
-3

Que diriez-vous -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

si secondes est Nonealors il convertit l'heure locale en temps UTC sinon convertit le temps écoulé en UTC.

Mohammad Efazati
la source
1
Cela n'aide pas, la question était de convertir une chaîne d'heure locale donnée en une chaîne utc.
Tom