如何处理来自不同时区的日期时间

时间:2013-07-15 04:12:45

标签: django datetime timezone

我有一个django应用程序,它在数据库(postgres)中存储UTC的日期时间,它在全球范围内都有用户。

但是在应用程序逻辑中,我根据当地时间范围进行了一些验证,即用户在瓜亚基尔,有些事情在星期天发生;我有问题要执行它并进行一些调试我发现在UTC是星期一凌晨2点,但用户(美国/瓜亚基尔)UTC-5仍然在周日21:00。所以它对用户来说是失败的,因为DAY已经改变了。

我正在考虑将用户时区存储在用户表中,但我不知道如何设置它以及如何防止以前的情况。

作为一个附带问题,如何将存储在数据库中的UTC日期时间转换为用户(例如)电子邮件通知的时区。 (我不会给他发送一封日期时间和时区的电子邮件,让他在脑海里做数学计算。)

3 个答案:

答案 0 :(得分:6)

这很好,你将所有内容存储在UTC中。现在您不需要将用户时区存储在数据库中,您可以在登录页面上执行此操作,您可以计算UTC的用户偏移量并存储在会话vi ajax中。以下是您可以在登录页面模板中包含的简单脚本:

<script>
    $(document).ready(function(){
        var visitortime = new Date();
        var visitortimezone = - visitortime.getTimezoneOffset()/60;

        $.ajax({
            type: "POST",
            url: "{% url 'update_timezone' %}",
            data: {'time_zone': visitortimezone, 'csrfmiddlewaretoken': '{{csrf_token}}'},
            dataType: "text"
        });
    });
</script>

在您的根urls.py中添加此网址:

url(r'^update_timezone/$',
    'MySite.views.update_timezone',
    name='update_timezone'),

添加此视图:

def update_timezone(request):
    time_zone = request.POST.get('time_zone', 0)
    if time_zone:
        request.session['user_timezone_offset'] = float(time_zone)*60*60
    return HttpResponse(
        simplejson.dumps({}), mimetype='application/javascript')

现在,您在会话中拥有用户时区偏移量。现在是计算的部分。您需要这两个简单的辅助函数:

from datetime import timedelta

def add_user_offset(dt, offset):
    if offset:
        dt = dt + timedelta(seconds=offset)
    return dt


def subtract_user_offset(dt, offset):
    if offset:
        dt = dt - timedelta(seconds=offset)
    return dt

好的,如果您想根据他/她的时区显示用户时间,您可以这样做:

created = add_user_offset(obj.created, request.session.get('user_timezone_offset'))

如果您有来自表单的日期时间或日期,并且您想验证它,例如所选日期不应小于您当前的日期:

from django.utils import timezone

d = request.POST['date']
d_normalize = subtract_user_offset(d, request.session.get('user_timezone_offset'))
if d_normalize < timezone.now():
    raise Exception, 'Date must be in future'

此方法的好处是您无需要求用户指定其时区。我们自动完成所有工作。

答案 1 :(得分:1)

django中的全局策略是在持久层中使用UTC,并在与最终用户交互时使用本地时间(您可以查看here。 因此,在您的用例中,我将在数据库中保留UTC时间并使用当前时区来处理您需要的计算。

时区选择功能为here 。使用get_current_timezone()可以获得tzinfo对象。

当前时区是用于呈现网页的时区。它可能不是您想要的那个,例如用户是否想要使用UTC-1时区但是当前正在看UTC + 1的网页。在这种情况下,最好以Aamir所解释的类似方法保持会话中的时区或保持它。

模型中持久化的方法仅仅是使用CharField并使用pytz包放置时区字符串。

答案 2 :(得分:-1)

默认django是美国/芝加哥时区。您需要将用户时区存储在数据库中以及用户登录时从DB获取时区并通过代码更改配置的最佳方式。

import datetime
from django.utils.timezone import utc
now = datetime.datetime.utcnow().replace(tzinfo=utc)

https://docs.djangoproject.com/en/dev/ref/settings/#time-zone