2011-12-19 18 views
34

Estoy tratando de generar un RFC 3339 UTC marca de tiempo en Python. Hasta ahora he podido hacer lo siguiente:Generar RFC 3339 marca de tiempo en Python

>>> d = datetime.datetime.now() 
>>> print d.isoformat('T') 
2011-12-18T20:46:00.392227 

Mi problema es con la configuración del desplazamiento UTC.

De acuerdo con la docs, la classmethod datetime.now([tz]), toma un argumento opcional tz donde tz must be an instance of a class tzinfo subclass, y es datetime.tzinfoan abstract base class for time zone information objects.

Esto es donde consigo perdido- ¿Cómo es que tzinfo es una clase abstracta, y cómo se supone que voy a ¿Impleméntalo?


(NOTA: En PHP es tan simple como timestamp = date(DATE_RFC3339);, que es por lo que no puedo entender por qué el enfoque de Python es tan complicada ...)

+0

Acabo de encontrar esta pregunta similar: [ISO Time (ISO 8601) en Python?] (Http: // stackoverflow.com/questions/2150739/iso-time-iso-8601-in-python) – Yarin

Respuesta

7

Further down en el mismo documento que se ha vinculado a, se explica cómo ponerlo en práctica, dando algunos ejemplos, incluido el pleno código para una clase UTC (que representa UTC), una clase FixedOffset (que representa una zona horaria con un desplazamiento fijo de UTC, en oposición a una zona horaria con horario de verano y otras cosas), y algunos otros.

+0

@ ruakh- gracias, me perdí esos ejemplos- La clase 'LocalTimezone()' hizo el truco. – Yarin

+0

@Yarin: ¡De nada! – ruakh

+0

@gene_wood: espero que no te importe, he revertido tu edición. El problema es que lo que implementó no coincide con lo que el OP realmente quería. – ruakh

28

zonas horarias son un dolor, que es probablemente por qué eligieron no incluirlos en la biblioteca de fecha y hora.

intento pytz, tiene la tzinfo su buscando: http://pytz.sourceforge.net/

Es necesario crear primero el objeto datetime, a continuación, aplicar la zona horaria, como la siguiente, y después de su salida de .isoformat() incluirá el desplazamiento UTC según se desee :

d = datetime.datetime.utcnow() 
d_with_timezone = d.replace(tzinfo=pytz.UTC) 
d_with_timezone.isoformat() 

'2017-04-13T14: 34: 23.111142 + 00: 00'

O, simplemente use UTC, y lance una "Z" (para Zulu zona horaria) al final para marcar la "zona horaria" como UTC.

d = datetime.datetime.utcnow() # <-- get time in UTC 
print d.isoformat("T") + "Z" 

'2017-04-13T14: 34: 23.111142Z'

+0

@ monkut- gracias- La clase pytz parece otra implementación que funcionaría, pero terminé usando el ejemplo incluido en los documentos, la respuesta de ruakh . – Yarin

+0

@ monkut- +1 su segundo ejemplo es una buena idea también – Yarin

+0

no devuelve microsegundos para mí: -/ –

0

Otra utilidad útil con la que comencé a trabajar: la biblioteca dateutil para el manejo de la zona horaria y el análisis de la fecha. Recomendado alrededor de SO, incluido este answer

14

En Python 3.3+:

>>> from datetime import datetime, timezone         
>>> local_time = datetime.now(timezone.utc).astimezone() 
>>> local_time.isoformat() 
'2015-01-16T16:52:58.547366+01:00' 

En las versiones más antiguas de Python, si todo lo que necesita es un objeto de fecha y hora conscientes que representa la hora actual en GMT entonces se podría define a simple tzinfo subclass as shown in the docs to represent UTC timezone:

from datetime import datetime 

utc_now = datetime.now(utc) 
print(utc_now.isoformat('T')) 
# -> 2015-05-19T20:32:12.610841+00:00 

También se puede usar para obtener tzlocal modulepytz zona horaria que representa su zona horaria local:

#!/usr/bin/env python 
from datetime import datetime 
from tzlocal import get_localzone # $ pip install tzlocal 

now = datetime.now(get_localzone()) 
print(now.isoformat('T')) 

funciona tanto en Python 2 y 3.

+0

Sin dudas, mejor respuesta para Python 3.3+ –

+0

Técnicamente, ISO 8601 y RFC 3339 no son 100% compatible ... existen algunas diferencias, como que ISO 8601 permite un signo menos o un guion para la parte de desplazamiento UTC, mientras que RFC 3339 _only_ permite un guion. Cada implementación '.isoformat()' que he visto hasta ahora (solo un par) se solapa con RFC 3339, pero es bueno conocer las diferencias – villapx

+1

@villapx: rfc 3339 es un perfil de ISO 8601. Sucede ese 'datetime.isoformat()' es RFC 3339 para un datetime con reconocimiento de zona horaria (es por eso que lo he usado). – jfs

1

El paquete pytz está disponible para Python 2.X y 3.X. Implementa subclases concretas de tzinfo, entre otros servicios, por lo que no es necesario.

Para añadir un desplazamiento UTC: fecha y hora de importación pytz importación

dt = datetime.datetime(2011, 12, 18, 20, 46, 00, 392227) 
utc_dt = pytz.UTC.localize(dt) 

Y ahora esto:

print utc_dt.isoformat() 

imprimiría:

2011-12-18T20:46:00.392227+00:00 
+0

no necesita el módulo 'pytz' si todo lo que quiere es la zona horaria UTC. Es simple de [definir utc tzinfo] (http://stackoverflow.com/a/25421145/4279) – jfs

+0

Gracias. Guardaré tu respuesta cuando necesite una solución stdlib. UTC fue el más corto para demostrar. OP no lo pidió específicamente. 'pytz' conoce todas las zonas horarias y su horario de verano, que me parece útil. –

+0

Nota: ['get_localzone()' en mi respuesta] (http://stackoverflow.com/a/27987813/4279) devuelve puts zona horaria que corresponde a la zona horaria local. – jfs

5

tuve problemas con el formato de fecha y hora RFC3339 mucho, pero encontré una solución adecuada para convertir date_stri ng < => datetime_object en ambas direcciones.

Se necesitan dos módulos externos diferentes, debido a que uno de ellos es sólo es capaz de hacer la conversión en una dirección (por desgracia):

primera instalación:

sudo pip install rfc3339 
sudo pip install iso8601 

a continuación incluyen:

import datetime  # for general datetime object handling 
import rfc3339  # for date object -> date string 
import iso8601  # for date string -> date object 

Para no tener que recordar qué módulo es para qué dirección, escribí dos funciones simples de ayuda:

def get_date_object(date_string): 
    return iso8601.parse_date(date_string) 

def get_date_string(date_object): 
    return rfc3339.rfc3339(date_object) 

el cual dentro de su código que puede utilizar fácilmente como esto:

input_string = '1989-01-01T00:18:07-05:00' 
test_date = get_date_object(input_string) 
# >>> datetime.datetime(1989, 1, 1, 0, 18, 7, tzinfo=<FixedOffset '-05:00' datetime.timedelta(-1, 68400)>) 

test_string = get_date_string(test_date) 
# >>> '1989-01-01T00:18:07-05:00' 

test_string is input_string # >>> True 

Heureka! Ahora puede fácilmente (haha ​​) usar sus cadenas de fechas y fechas en un formato utilizable.

0

Puede utilizar el módulo integrado datetime. Como @ruakh mentions, hay ejemplos en la página que muestran cómo. Si nos fijamos en la sección en tzinfo verá vea un ejemplo largo que muestra muchos casos de uso diferentes. Aquí está el código para el que está buscando , que es generar una marca de hora RFC 3339 UTC.

from datetime import tzinfo, timedelta, datetime 
import time as _time 

ZERO = timedelta(0) 
STDOFFSET = timedelta(seconds=-_time.timezone) 
if _time.daylight: 
    DSTOFFSET = timedelta(seconds=-_time.altzone) 
else: 
    DSTOFFSET = STDOFFSET 

DSTDIFF = DSTOFFSET - STDOFFSET 


class LocalTimezone(tzinfo): 

    def utcoffset(self, dt): 
     if self._isdst(dt): 
      return DSTOFFSET 
     else: 
      return STDOFFSET 

    def dst(self, dt): 
     if self._isdst(dt): 
      return DSTDIFF 
     else: 
      return ZERO 

    def tzname(self, dt): 
     return _time.tzname[self._isdst(dt)] 

    def _isdst(self, dt): 
     tt = (dt.year, dt.month, dt.day, 
       dt.hour, dt.minute, dt.second, 
       dt.weekday(), 0, 0) 
     stamp = _time.mktime(tt) 
     tt = _time.localtime(stamp) 
     return tt.tm_isdst > 0 

Local = LocalTimezone() 

d = datetime.now(Local) 
print d.isoformat('T') 

# which returns 
# 2014-04-28T15:44:45.758506-07:00 
Cuestiones relacionadas