Repository: TabbycatDebate/tabbycat

Issue:
NonExistentTimeError and AmbiguousTimeError on daylight time changes with checkin filter window
I believe this error occurs when:
- There is a change into or out of daylight saving time
- A user loads a view that displays check-in statuses
- The current time is such that the beginning of the check-in window would be during the daylight saving time transition.

For example, if the check-in window is 12 hours, then loading any page that seeks check-in information (check-ins, results entry, private URL landing) at 2:15 p.m. would cause this error, because 2:15 a.m. is either ambiguous (if daylight saving just finished) or non-existent (if it just started).

https://sentry.io/organizations/tabbycat-ig/issues/975799227/?project=185382&referrer=github_plugin

```
NonExistentTimeError: 2019-04-07 02:51:30.519504
(24 additional frame(s) were not displayed)
...
  File "utils/views.py", line 127, in get_tables
    return [self.get_table()]
  File "availability/views.py", line 167, in get_table
    self.annotate_checkins(queryset, self.tournament)
  File "availability/views.py", line 232, in annotate_checkins
    return get_checkins(queryset, t, 'checkin_window_people')
  File "checkins/utils.py", line 124, in get_checkins
    events = get_unexpired_checkins(t, window_preference_type).values(
  File "checkins/utils.py", line 61, in get_unexpired_checkins
    time__gte=time_window).select_related('identifier').order_by('time')

NonExistentTimeError: 2019-04-07 02:51:30.519504
```

Relates to feature originally implemented from #513.


Discussion:
Sentry issue: [BACKEND-1DS](https://sentry.io/organizations/tabbycat-ig/issues/975293501/?project=185382&referrer=github_plugin)
Sentry issue: [BACKEND-1DR](https://sentry.io/organizations/tabbycat-ig/issues/975289131/?project=185382&referrer=github_plugin)

Resolving patch:
diff --git a/tabbycat/checkins/utils.py b/tabbycat/checkins/utils.py
--- a/tabbycat/checkins/utils.py
+++ b/tabbycat/checkins/utils.py
@@ -4,7 +4,9 @@
 import string
 
 from django.db import IntegrityError
+from django.db.models import Q
 from django.core.exceptions import ObjectDoesNotExist
+from django.utils import timezone
 from django.utils.translation import gettext as _
 
 from .models import DebateIdentifier, Event, PersonIdentifier, VenueIdentifier
@@ -51,15 +53,13 @@ def delete_identifiers(queryset):
 
 
 def get_unexpired_checkins(tournament, window_preference_type):
-    if not window_preference_type:
-        time_window = datetime.datetime.fromtimestamp(0)  # Unix start
-    else:
+    filters = Q(tournament=tournament)
+    if window_preference_type:
         start = datetime.timedelta(hours=tournament.pref(window_preference_type))
-        time_window = datetime.datetime.now() - start
+        time_window = timezone.now() - start
+        filters &= Q(time_gte=time_window)
 
-    events = Event.objects.filter(tournament=tournament,
-        time__gte=time_window).select_related('identifier').order_by('time')
-    return events
+    return Event.objects.filter(filters).select_related('identifier').order_by('time')
 
 
 def create_identifiers(model_to_make, items_to_check):


Test patch: