如何使TimeField有时区感知?

时间:2013-11-05 00:47:17

标签: django

有时您需要从用户那里收集时间而不收集相关日期。例如,如果用户正在配置每天同时运行的重复事件。 Django的TimeField虽然没有使用时区。但是,在这种特殊情况下(并且可能在您自己记录时间的任何时候),时区是一个重要因素。那么,你如何存储时区感知时间?

2 个答案:

答案 0 :(得分:4)

答案是你没有。要知道时区的时间,它必须有一个与之相关的日期。想想夏令时...我的解决方案是在模型上使用DateTimeField并覆盖表格,如下所示:

# 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()

答案 1 :(得分:0)

这是未经测试和不完整的:

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)

这将使用Postgres的time with time zone数据类型。如果你传给一个格式为'HH:MM:SS.mmmmmm + HH:MM'的字符串,并且使用auto_now会尝试保存一个天真的时间(不确定是否会引发错误),它会破坏。

修改

在通用后端代码中,如果您尝试使用UTC以外的时区插入时间,则会引发异常。

编辑2

我添加了一个更新的get_db_prep_value,将带有时区的提供的time转换为字符串,但只有在提供的时区输出utc偏移量时才会生效(这可能是不明确的日期)。< / p>

似乎time with time zone有点误导......据我所知,它实际上存储了一个UTC偏移而不是时区的时间。因此,很难获取返回的值,添加日历日期,并在夏令时方面找回适当的时间。