2011-12-19 5 views
34

Sto provando a generare un timestamp UTC RFC 3339 in Python. Finora sono stato in grado di fare quanto segue:Generare il timestamp di RFC 3339 in Python

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

Il mio problema è con l'impostazione dell'offset UTC.

Secondo il docs, il classmethod datetime.now([tz]), prende un argomento opzionale tz dove tz must be an instance of a class tzinfo subclass, e datetime.tzinfo è an abstract base class for time zone information objects.

Questo è dove ho stassi perdendo Come mai tzinfo è una classe astratta, e come faccio a implementarlo?


(NOTA: In PHP è semplice come timestamp = date(DATE_RFC3339);, motivo per cui non riesco a capire il motivo per cui l'approccio di Python è così contorto ...)

+0

Ho appena trovato questa domanda simile: [Tempo ISO (ISO 8601) in Python?] (Http: // StackOverflow.it/questions/2150739/iso-time-iso-8601-in-python) – Yarin

risposta

7

Further down nello stesso documento che si è collegato al, si spiega come implementare, dando alcuni esempi, compresa la piena codice per una classe UTC (che rappresenta UTC), una classe FixedOffset (che rappresenta un fuso orario con un offset fisso da UTC, a differenza di un fuso orario con DST e quant'altro) e pochi altri.

+0

@ ruakh- grazie, ho perso quegli esempi- La classe 'LocalTimezone()' ha fatto il trucco. – Yarin

+0

@Yarin: Prego! – ruakh

+0

@gene_wood: Spero non ti dispiaccia, ho ripristinato la tua modifica. Il problema è che ciò che hai implementato non corrisponde a ciò che l'OP voleva realmente. – ruakh

28

Timezones sono un dolore, che è probabilmente perché hanno scelto di non includerli nella libreria datetime.

prova pytz, ha la tzinfo vostro ricerca: http://pytz.sourceforge.net/

È necessario creare prima l'oggetto datetime, quindi applicare il fuso orario come come qui di seguito, e poi la tua .isoformat() uscita includerà l'offset UTC, se lo desideri :

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

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

Oppure, usa semplicemente UTC e lancia una "Z" (per il fuso orario Zulu) per contrassegnare il "fuso orario" come UTC.

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

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

+0

@ monkut- grazie- La classe pytz sembra un'altra implementazione che funzionerebbe, ma ho finito per usare l'esempio incluso nei documenti, per la risposta di ruakh . – Yarin

+0

@ monkut- +1 il tuo secondo esempio è una buona idea anche – Yarin

+0

non restituisce microsecondi per me: -/ –

0

Un'altra utile utilità che ho appena iniziato a lavorare: libreria dateutil per la gestione del fuso orario e l'analisi della data. Consigliato intorno a SO, incluso questo answer

14

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

Nelle versioni più vecchie di Python, se tutto ciò che serve è un oggetto di conoscenza datetime che rappresenta l'ora corrente in UTC, allora si potrebbe 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 

Si potrebbe anche usare tzlocal module per ottenere pytz fuso orario che rappresenta il fuso orario locale:

#!/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')) 

funziona sia su Python 2 e 3.

+0

Giù le mani, la migliore risposta per Python 3.3+ –

+0

Tecnicamente, ISO 8601 e RFC 3339 non sono al 100% compatibile ... esistono alcune differenze, come ad esempio che ISO 8601 consente sia un segno meno o un trattino per la parte offset UTC, mentre RFC 3339 _ onlyly consente un trattino. Ogni implementazione '.isoformat()' che ho visto finora (solo un paio) si sovrappone a RFC 3339, ma è bene rendersi consapevoli delle differenze – villapx

+1

@villapx: rfc 3339 è un profilo ISO 8601. Succede che 'datetime.isoformat()' è RFC 3339 per un datetime timezone-aware (è per questo che l'ho usato). – jfs

1

Il pacchetto pytz è disponibile per Python 2.xe 3.x. Implementa sottoclassi concrete di tzinfo, tra gli altri servizi, in modo da non dover.

Per aggiungere un offset UTC: import datetime importazione pytz

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

E ora questo:

print utc_dt.isoformat() 

sarebbe stampare:

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

non è necessario il modulo' pytz' se tutto ciò che si desidera è il fuso orario UTC. È semplice [definire utc tzinfo] (http://stackoverflow.com/a/25421145/4279) – jfs

+0

Grazie. Salverò la tua risposta per quando avrò bisogno di una soluzione stdlib. UTC era solo il più breve da dimostrare. OP non lo ha specificamente chiesto. 'pytz' conosce tutti i fusi orari e il loro fuso orario, che trovo utile. –

+0

Nota: ['get_localzone()' nella mia risposta] (http://stackoverflow.com/a/27987813/4279) restituisce il fuso orario che corrisponde al fuso orario locale. – jfs

5

ho lottato con il formato datetime RFC3339 molto, ma ho trovato una soluzione adatta per convertire date_stri ng < => datetime_object in entrambe le direzioni.

avete bisogno di due diversi moduli esterni, perché uno di loro è è in grado di fare la conversione in una sola direzione (purtroppo):

prima installare:

sudo pip install rfc3339 
sudo pip install iso8601 

quindi includere:

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

Per non aver bisogno di ricordare quale modulo è per quale direzione, ho scritto due semplici funzioni di supporto:

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

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

che all'interno del codice è possibile usare facilmente come questo:

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! Ora si può facilmente (haha ​​) usare le stringhe di data e stringhe di data in un formato utilizzabile.

0

È possibile utilizzare il modulo integrato datetime. Come @ruakh mentions, ci sono esempi nella pagina che mostrano come. Se si guarda nella sezione sulla tzinfo si vedere una lunga esempio che mostra molti casi d'uso differenti. Ecco il codice per l'uno che stai cercando, che è quello di generare un timestamp UTC RFC 3339.

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