from datetime import datetime
import pytz
from django.db import models
from django.db.models.functions import Cast
class PhaseQueryset(models.QuerySet):
def with_duration(self,):
base_date = datetime(2000, 1, 3, 0, tzinfo=pytz.utc)
# When I use base_date to do the end_total_time math in 3.0.3 together
# with ended_at annotated, it creates a wrong query
qs = self.annotate(
ended_at=models.Case(
models.When(
models.Q(type='TYPEONE'),
then=models.functions.Now()
),
default=models.F('started_at'),
output_field=models.DateTimeField(),
),
base_date=models.functions.Cast(
models.Value(base_date),
output_field=models.DateTimeField()
),
end_total_time=models.ExpressionWrapper(
models.F('ended_at') - models.F('base_date'),
output_field=models.fields.BigIntegerField()
)
)
return qs
# Create your models here.
class Phase(models.Model):
objects = PhaseQueryset().as_manager()
started_at = models.DateTimeField()
type = models.CharField(max_length=40)
from datetime import datetime, timedelta
import pytz
from django.test import TestCase
from daterror.models import Phase
# Create your tests here.
class TestDateProblem(TestCase):
def setUp(self,):
past = datetime.now(tz=pytz.UTC) - timedelta(days=30)
Phase.objects.create(started_at=past, type='TYPEONE')
past = datetime.now(tz=pytz.UTC) - timedelta(days=33)
Phase.objects.create(started_at=past, type='TYPETWO')
past = datetime.now(tz=pytz.UTC) - timedelta(days=34)
Phase.objects.create(started_at=past, type='TYPETHREE')
def test_timedifference_not_none(self,):
phases = Phase.objects.all().with_duration()
print(phases[0].end_total_time)
print(phases[1].end_total_time)
print(phases[2].end_total_time)
self.assertNotEqual(None, phases[0].end_total_time)
self.assertNotEqual(None, phases[1].end_total_time)
self.assertNotEqual(None, phases[2].end_total_time)