1

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

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

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

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

4

3 回答 3

6

That is good you are storing everything in UTC. Now you don't need to store the user timezone in database what you can do is that on login page you can calculate the user offset from UTC and store in session vi ajax. Here is the simple script you can include in your login page template:

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

Add this url in your root urls.py:

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

Add this view:

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

Now you have user timezone offset in session. Now comes the part for calculation. You need these two simple helper functions:

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

Ok if you want to show the user time according to the his/her timezone you would do:

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

If you have datetime or date coming from the form and you want to validate it e.g. the date chosen should not be less than current date you would do:

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'

The benefit of this approach is that you don't need to ask users to specify their timezones. We are doing everything automatically on our side.

于 2013-07-15T07:24:25.637 回答
1

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

时区选择功能在这里 。使用 get_current_timezone() 您可以获得 tzinfo 对象。

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

模型中的持久性方法仅使用 CharField 并放置您可以使用 pytz 包获得的时区字符串。

于 2013-07-15T09:30:18.820 回答
-1

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

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

于 2013-07-15T04:41:54.537 回答