Django/DRF中正确的日期时间/时区处理

a64a0gku  于 2023-05-01  发布在  Go
关注(0)|答案(3)|浏览(115)

我试图为我的Web应用程序做一个适当的日期处理设置。我有一个看起来像这样的模型

class Entity(models.Model):
    name = models.CharField(max_length=255)
    date = models.DateTimeField()

用户可以向我的DRF端点/api/v1/entity/发送请求以获取此类实体的列表。现在有一个要求,即用户应该能够在一天内请求所有Entity对象,这是由date参数确定的。日期以UTC存储在数据库中,而此应用的用户不在UTC时区。
用户可以创建一个日期为2018-06-19T01:00:00+02:00的实体,在数据库中存储为2018-06-18T23:00:00Z。现在,如果我尝试列出用户为2018-06-19创建的所有实体,则不会返回任何内容,但通过2018-06-18进行过滤会返回一个条目。
这是我使用的代码设置:http://127.0.0.1:8000/api/v1/entity/?date=2018-06-18

def get_queryset(self):
    user = self.request.user
    entities = Entity.objects.filter(owner=user)
    date = self.request.query_params.get('date')
    if date:
        entities = entities.filter(date__date=date)
    return entities

因此,在这种情况下,适当的日期范围将是2018-06-18T23:00:00Z-2018-06-19T23:00:00Z。在用户的时区中获取一天(或一个日期范围)的所有实体的正确方法是什么?

p8h8hvxi

p8h8hvxi1#

如果我理解正确,你必须将本地**DateTime转换为等效的UTC**时间并查询到DB。所以我在下面定义了一个简单的时间转换函数

import pytz
from datetime import datetime
def convert_to_UTC(local_tz,dt_1,dt_2):
    """
    local_tz : any possible timezone which supports pytz lib (https://stackoverflow.com/questions/13866926/is-there-a-list-of-pytz-timezones)
    dt_1 and dt_2 : local datetime in string in this format ->> '%Y-%m-%dT%H:%M:%S'

    return a list as ->> [utc_equivalent_of_dt_1_in_string,utc_equivalent_of_dt_2_in_string]
    """
    format='%Y-%m-%dT%H:%M:%S'
    pytz_local_tz = pytz.timezone(local_time_zone)
    dt_obj_from_date_time = datetime.strptime(dt_1,format)
    dt_obj_to_date_time = datetime.strptime(dt_2,format)
    return [pytz_local_tz.localize(dt_obj_from_date_time).astimezone(tz=pytz.utc).strftime(format),
            pytz_local_tz.localize(dt_obj_to_date_time).astimezone(tz=pytz.utc).strftime(format)]

要使用此函数,请按如下所示更改get_queryset()方法,

def get_queryset(self):
    user = self.request.user
    entities = Entity.objects.filter(owner=user)
    date_from = self.request.query_params.get('date_from')
    date_to = self.request.query_params.get('date_to')

    if date_from and date_to:
        entities = entities.filter(date__range=convert_to_UTC('Asia/Kolkata', date_from, date_to))
    return entities

因此,URL将像/api/v1/entity/?date_from=2018-06-18T23:00:00&date_to=2018-06-19T23:00:00

nx7onnlm

nx7onnlm2#

# simplified functions

def localize(usertimzone, date, type):
    """
    type = 'date', 'time', 'datetime'
    """
    from dateutil import parser
    date = parser.parse(date)
    if not date.tzinfo:
        # "if the POST request like `2018-06-19T01:00:00`"
        usertimzone = pytz.timezone(usertimzone)
        date = usertimzone.localize(date)

    # "if the POST request like `2018-06-19T01:00:00+02:00`" then just do this
    utc_date = date.astimezone(pytz.utc)
    return utc_date
#usages example
    def post(self, request, *args, **kwargs):
        alert_date = request.data.get('alert_date')
        if alert_date:
            request.data['alert_date'] = localize(request.user.timezone, alert_date, 'datetime')
vd8tlhqk

vd8tlhqk3#

让我们这样想:任何带有时区信息的timestamp都是绝对的值,因为它可以被转换为任何其他时区,而没有时区的timestamp是相对的,并且仅在整个系统的单个时区的上下文中是可靠的。
根据以上想法,你应该
1.从客户端(应用程序)Angular 确定所需的期间界限startend,不仅日期)。例如,如果应用程序在时区+03:00运行,并且我们想要2023-04-01的实体,那么边界将是:

{
    "start": "2023-04-01T00:00:00.000000+03:00",
    "end": "2023-04-01T23:59:59.999999+03:00"
}

1.将其转换为UTC(* 不是必需的,但:这可以在后台完成,甚至你可以按原样将日期时间值推送到ORM/数据库,它们只需要包含时区信息 *)并将其用作查询参数

{
    "start": "2023-03-31T21:00:00.000000Z",
    "end": "2023-04-01T20:59:59.999999Z"
}

相关问题