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

po5*_*o5i 1 django timezone datetime

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

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

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

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

Aam*_*nan 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>
Run Code Online (Sandbox Code Playgroud)

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

url(r'^update_timezone/$',
    'MySite.views.update_timezone',
    name='update_timezone'),
Run Code Online (Sandbox Code Playgroud)

添加此视图:

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')
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

created = add_user_offset(obj.created, request.session.get('user_timezone_offset'))
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是您不需要要求用户指定他们的时区.我们正在自动做所有事情.