2013-11-05 13 views
6

Vi sono occasioni in cui è necessario raccogliere un tempo da un utente senza raccogliere una data associata. Ad esempio, se l'utente sta configurando un evento ricorrente che viene eseguito tutti i giorni alla stessa ora. Django's TimeField però non suona con i fusi orari. Tuttavia, in questo caso particolare (e probabilmente ogni volta che registri un orario da solo), il fuso orario è un fattore importante. Quindi, come si memorizza un orario sensibile al fuso orario?Come rendere TimeField sensibile al fuso orario?

risposta

4

La risposta è che non lo fai. Per un certo periodo di tempo, è necessario avere una data associata. Pensate di ora legale ... La mia soluzione per questo è stato quello di utilizzare un DateTimeField sul modello e di ignorare la forma in questo modo:

# Model 
class MyModel(models.Model): 
    time_of_day = models.DateTimeField() 

# Form Fields 
from django.forms.util import from_current_timezone 
from django.forms.util import to_current_timezone 
from django.utils import timezone 

class TzAwareTimeField(forms.fields.TimeField): 
    def prepare_value(self, value): 
     if isinstance(value, datetime.datetime): 
      value = to_current_timezone(value).time() 
     return super(TzAwareTimeField, self).prepare_value(value) 

    def clean(self, value): 
     value = super(TzAwareTimeField, self).to_python(value) 
     dt = to_current_timezone(timezone.now()) 
     return dt.replace(
      hour=value.hour, minute=value.minute, 
      second=value.second, microsecond=value.microsecond) 


# Forms 
class MyForm(forms.ModelForm): 
    time_of_day = TzAwareTimeField() 
+3

L'istruzione di apertura (e il comportamento di Django) non è coerente con il modo in cui Python gestisce gli oggetti 'tempo'. Un oggetto 'time' di Python può avere un campo' tzinfo', che consente un oggetto 'time' di conoscenza del fuso orario senza alcuna data associata, che è utile in alcune circostanze, come quando la data viene memorizzata altrove. Ho appena trovato questo problema con 'open_time' e' close_time' 'TimeField su un modello' Day' in Django. Quei tempi dovrebbero idealmente essere consapevoli del fuso orario, ma non può essere perché Django non lo supporta. – jbg

+0

Questo è vecchio, ma comunque utile, quindi voglio sottolineare che penso che sia necessario avvolgere il valore restituito del metodo 'clean' in' from_current_timezone'. –

0

Questo non è testato e incompleto:

class TimeFieldWithZone(TimeField): 
    def db_type(self, connection): 
     if (connection.settings_dict['ENGINE'] == 
      'django.db.backends.postgresql_psycopg2'): 
      return 'time with time zone' 
     raise Exception('Unsupported database type') 

    def get_db_prep_value(self, value, *args, **kwargs): 
     try: 
      return super(TimeFieldWithZone, self).get_db_prep_value(
       value, *args, **kwargs) 
     except ValueError: 
      return six.text_type(value) 

Questo userà Tipo di dati Postgres time with time zone. Si romperà se passerai una stringa nel formato 'HH: MM: SS.mmmmmm + HH: MM' e usando auto_now cercherai di salvare un tempo ingenuo (non sono sicuro se questo genera un errore).

modificare

Nel codice backend generica viene generata un'eccezione se si tenta l'inserimento di un tempo con un fuso orario diverso da UTC.

modifica 2

ho aggiunto un aggiornato get_db_prep_value per convertire un fornito time con fuso orario in una stringa, ma funziona solo se il fuso orario previsto emette un offset UTC (che può essere ambiguo senza data).

Sembra time with time zone è un po 'fuorviante ... Per quanto posso dire, in realtà memorizza un tempo con un offset UTC e NON un fuso orario. Quindi sarebbe difficile prendere il valore restituito, aggiungere una data di calendario e recuperare l'ora esatta in relazione all'ora legale.