如何以天为单位注释日期时间的差异

Posted

技术标签:

【中文标题】如何以天为单位注释日期时间的差异【英文标题】:How to annotate a difference of datetime in days 【发布时间】:2016-11-23 11:01:43 【问题描述】:

我有一个 Booking 模型,它具有 startend 日期时间字段。我想知道预订涵盖多少天。我可以在 Python 中做到这一点,但我需要这个值来做进一步的注释。

这是我尝试过的:

In [1]: Booking.objects.annotate(days=F('end')-F('start'))[0].days
Out[1]: datetime.timedelta(16, 50400)

这里有几个问题:

我想要一个整数(或我可以在计算中使用的其他数字类型)作为输出,而不是 timedelta。设置 output_field 在这里没有任何意义。 我的总和基于日期时间。像这样的减法,如果不删除时间可能会导致整个天数都没有。

在 Python 中,我会使用 (end.date() - start.date()).days + 1。我怎样才能在数据库中做到这一点,最好是通过 ORM(例如数据库函数),但是 RawSQL 就足以解决这个问题?

【问题讨论】:

相关:***.com/q/8432926 【参考方案1】:

我编写了几个数据库函数来转换和截断日期,以解决 PostgreSQL 下的这两个问题。我使用的DATE_PARTDATE_TRUNC 内部函数是特定于数据库的☹

from django.db.models import Func

class DiffDays(Func):
    function = 'DATE_PART'
    template = "%(function)s('day', %(expressions)s)"

class CastDate(Func):
    function = 'date_trunc'
    template = "%(function)s('day', %(expressions)s)"

那么我可以:

In [25]: Booking.objects.annotate(days=DiffDays(CastDate(F('end'))-CastDate(F('start'))) + 1)[0].days
Out[25]: 18.0

【讨论】:

【参考方案2】:

这个问题还有另一个简单的解决方案。您可以使用:

from django.db.models import F
from django.db.models.functions import ExtractDay

然后:

Booking.objects.annotate(days=(ExtractDay(F('end')-F('start'))+1))[0].days

【讨论】:

这仅适用于月份和年份具有相同值的情况。否则会失败【参考方案3】:

如果您使用的是 MYSQL 数据库,您可以使用 Custom DB Function 作为,

from django.db.models.functions import Func


class TimeStampDiff(Func):
    class PrettyStringFormatting(dict):
        def __missing__(self, key):
            return '%(' + key + ')s'

    def __init__(self, *expressions, **extra):
        unit = extra.pop('unit', 'day')
        self.template = self.template % self.PrettyStringFormatting("unit": unit)
        super().__init__(*expressions, **extra)

    function = 'TIMESTAMPDIFF'
    template = "%(function)s(%(unit)s, %(expressions)s)"

用法

from django.db.models import F, IntegerField

booking_queryset = Booking.objects.annotate(
    days=TimeStampDiff(F('start'), F('end'), output_field=IntegerField()))
if booking_queryset.exist():
    print(booking_queryset[0].__dict__)

【讨论】:

以上是关于如何以天为单位注释日期时间的差异的主要内容,如果未能解决你的问题,请参考以下文章

以天为单位的日期时间差异的高性能计算

以天为单位计算用户的年龄java [重复]

使用PHP的日期差(以天为单位)

两个日期之间的天数差异[重复]

postgresql中的日期差异

计算 Hive 数组中连续日期之间的差异