Improve time-related stuff
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Add created_at to all models Add modified_at to Session Get rid of custom now() function Make sure aware datetime is used everywhere
This commit is contained in:
parent
3f037b4c7c
commit
c44d8bf427
|
@ -1,12 +1,5 @@
|
|||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def now() -> datetime:
|
||||
return datetime.now(ZoneInfo(settings.TIME_ZONE))
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
def _safe_timedelta(duration: timedelta | int | None):
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# Generated by Django 4.1.5 on 2023-11-15 13:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("games", "0030_alter_purchase_name"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="device",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="edition",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="game",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="platform",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="purchase",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="session",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,52 @@
|
|||
# Generated by Django 4.1.5 on 2023-11-15 18:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("games", "0031_device_created_at_edition_created_at_game_created_at_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="session",
|
||||
options={"get_latest_by": "timestamp_start"},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="session",
|
||||
name="modified_at",
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="device",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="edition",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="game",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="platform",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="purchase",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="session",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
]
|
|
@ -1,10 +1,9 @@
|
|||
from common.time import format_duration
|
||||
from datetime import datetime, timedelta
|
||||
from django.conf import settings
|
||||
from datetime import timedelta
|
||||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.db.models import F, Manager, Sum
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
class Game(models.Model):
|
||||
|
@ -12,6 +11,7 @@ class Game(models.Model):
|
|||
sort_name = models.CharField(max_length=255, null=True, blank=True, default=None)
|
||||
year_released = models.IntegerField(null=True, blank=True, default=None)
|
||||
wikidata = models.CharField(max_length=50, null=True, blank=True, default=None)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -42,6 +42,7 @@ class Edition(models.Model):
|
|||
)
|
||||
year_released = models.IntegerField(null=True, blank=True, default=None)
|
||||
wikidata = models.CharField(max_length=50, null=True, blank=True, default=None)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.sort_name
|
||||
|
@ -128,6 +129,7 @@ class Purchase(models.Model):
|
|||
blank=True,
|
||||
related_name="related_purchases",
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
additional_info = [
|
||||
|
@ -156,6 +158,7 @@ class Purchase(models.Model):
|
|||
class Platform(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
group = models.CharField(max_length=255, null=True, blank=True, default=None)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -173,6 +176,9 @@ class SessionQuerySet(models.QuerySet):
|
|||
|
||||
|
||||
class Session(models.Model):
|
||||
class Meta:
|
||||
get_latest_by = "timestamp_start"
|
||||
|
||||
purchase = models.ForeignKey("Purchase", on_delete=models.CASCADE)
|
||||
timestamp_start = models.DateTimeField()
|
||||
timestamp_end = models.DateTimeField(blank=True, null=True)
|
||||
|
@ -186,6 +192,8 @@ class Session(models.Model):
|
|||
default=None,
|
||||
)
|
||||
note = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
modified_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = SessionQuerySet.as_manager()
|
||||
|
||||
|
@ -194,10 +202,10 @@ class Session(models.Model):
|
|||
return f"{str(self.purchase)} {str(self.timestamp_start.date())} ({self.duration_formatted()}{mark})"
|
||||
|
||||
def finish_now(self):
|
||||
self.timestamp_end = datetime.now(ZoneInfo(settings.TIME_ZONE))
|
||||
self.timestamp_end = timezone.now()
|
||||
|
||||
def start_now():
|
||||
self.timestamp_start = datetime.now(ZoneInfo(settings.TIME_ZONE))
|
||||
self.timestamp_start = timezone.now()
|
||||
|
||||
def duration_seconds(self) -> timedelta:
|
||||
manual = timedelta(0)
|
||||
|
@ -250,6 +258,7 @@ class Device(models.Model):
|
|||
]
|
||||
name = models.CharField(max_length=255)
|
||||
type = models.CharField(max_length=3, choices=DEVICE_TYPES, default=UNKNOWN)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.get_type_display()})"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from common.time import format_duration, now as now_with_tz
|
||||
from common.time import format_duration
|
||||
from common.utils import safe_division
|
||||
from datetime import datetime, timedelta
|
||||
from django.conf import settings
|
||||
|
@ -7,6 +7,7 @@ from django.db.models.functions import TruncDate
|
|||
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from typing import Callable, Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
@ -32,19 +33,15 @@ def model_counts(request):
|
|||
|
||||
|
||||
def stats_dropdown_year_range(request):
|
||||
result = {
|
||||
"stats_dropdown_year_range": range(
|
||||
datetime.now(ZoneInfo(settings.TIME_ZONE)).year, 1999, -1
|
||||
)
|
||||
}
|
||||
result = {"stats_dropdown_year_range": range(timezone.now().year, 1999, -1)}
|
||||
return result
|
||||
|
||||
|
||||
def add_session(request, purchase_id=None):
|
||||
context = {}
|
||||
initial = {"timestamp_start": now_with_tz()}
|
||||
initial = {"timestamp_start": timezone.now()}
|
||||
|
||||
last = Session.objects.all().last()
|
||||
last = Session.objects.last()
|
||||
if last != None:
|
||||
initial["purchase"] = last.purchase
|
||||
|
||||
|
@ -155,13 +152,11 @@ def view_game(request, game_id=None):
|
|||
.order_by("year_released")
|
||||
)
|
||||
|
||||
sessions = Session.objects.filter(purchase__edition__game=game).order_by(
|
||||
"timestamp_start"
|
||||
)
|
||||
sessions = Session.objects.filter(purchase__edition__game=game)
|
||||
session_count = sessions.count()
|
||||
|
||||
playrange_start = sessions.first().timestamp_start.strftime("%b %Y")
|
||||
playrange_end = sessions.last().timestamp_start.strftime("%b %Y")
|
||||
playrange_start = sessions.earliest().timestamp_start.strftime("%b %Y")
|
||||
playrange_end = sessions.latest().timestamp_start.strftime("%b %Y")
|
||||
|
||||
playrange = (
|
||||
playrange_start
|
||||
|
@ -225,15 +220,11 @@ def related_purchase_by_edition(request):
|
|||
|
||||
@use_custom_redirect
|
||||
def start_game_session(request, game_id: int):
|
||||
last_session = (
|
||||
Session.objects.filter(purchase__edition__game_id=game_id)
|
||||
.order_by("-timestamp_start")
|
||||
.first()
|
||||
)
|
||||
last_session = Session.objects.filter(purchase__edition__game_id=game_id).latest()
|
||||
session = SessionForm(
|
||||
{
|
||||
"purchase": last_session.purchase.id,
|
||||
"timestamp_start": now_with_tz(),
|
||||
"timestamp_start": timezone.now(),
|
||||
"device": last_session.device,
|
||||
}
|
||||
)
|
||||
|
@ -246,7 +237,7 @@ def start_session_same_as_last(request, last_session_id: int):
|
|||
session = SessionForm(
|
||||
{
|
||||
"purchase": last_session.purchase.id,
|
||||
"timestamp_start": now_with_tz(),
|
||||
"timestamp_start": timezone.now(),
|
||||
"device": last_session.device,
|
||||
}
|
||||
)
|
||||
|
@ -296,19 +287,18 @@ def list_sessions(
|
|||
context["title"] = "This year"
|
||||
else:
|
||||
# by default, sort from newest to oldest
|
||||
dataset = Session.objects.all().order_by("-timestamp_start")
|
||||
dataset = Session.objects.order_by("-timestamp_start")
|
||||
|
||||
for session in dataset:
|
||||
if session.timestamp_end == None and session.duration_manual == timedelta(
|
||||
seconds=0
|
||||
):
|
||||
session.timestamp_end = datetime.now(ZoneInfo(settings.TIME_ZONE))
|
||||
session.timestamp_end = timezone.now()
|
||||
session.unfinished = True
|
||||
|
||||
context["total_duration"] = dataset.total_duration_formatted()
|
||||
context["dataset"] = dataset
|
||||
# cannot use dataset[0] here because that might be only partial QuerySet
|
||||
context["last"] = Session.objects.all().order_by("timestamp_start").last()
|
||||
context["last"] = Session.objects.latest()
|
||||
|
||||
return render(request, "list_sessions.html", context)
|
||||
|
||||
|
@ -318,7 +308,7 @@ def stats(request, year: int = 0):
|
|||
if selected_year:
|
||||
return HttpResponseRedirect(reverse("stats_by_year", args=[selected_year]))
|
||||
if year == 0:
|
||||
year = now_with_tz().year
|
||||
year = timezone.now().year
|
||||
this_year_sessions = Session.objects.filter(timestamp_start__year=year)
|
||||
selected_currency = "CZK"
|
||||
unique_days = (
|
||||
|
@ -451,7 +441,7 @@ def stats(request, year: int = 0):
|
|||
|
||||
def add_purchase(request, edition_id=None):
|
||||
context = {}
|
||||
initial = {"date_purchased": now_with_tz()}
|
||||
initial = {"date_purchased": timezone.now()}
|
||||
|
||||
if request.method == "POST":
|
||||
form = PurchaseForm(request.POST or None, initial=initial)
|
||||
|
|
Loading…
Reference in New Issue