1111from __future__ import absolute_import , unicode_literals
1212
1313from datetime import datetime
14+ from pytz import AmbiguousTimeError
1415
1516from django .db import models
1617from django .db .models import Q
@@ -47,7 +48,7 @@ def latest_children(self):
4748
4849
4950# ------------------------------------------------------------------------
50- def granular_now (n = None ):
51+ def granular_now (n = None , default_tz = None ):
5152 """
5253 A datetime.now look-alike that returns times rounded to a five minute
5354 boundary. This helps the backend database to optimize/reuse/cache its
@@ -57,12 +58,27 @@ def granular_now(n=None):
5758 """
5859 if n is None :
5960 n = timezone .now ()
60- # WARNING/TODO: make_aware can raise a pytz NonExistentTimeError or
61- # AmbiguousTimeError if the resultant time is invalid in n.tzinfo
62- # -- see https://github.com/feincms/feincms/commit/5d0363df
63- return timezone .make_aware (
64- datetime (n .year , n .month , n .day , n .hour , (n .minute // 5 ) * 5 ),
65- n .tzinfo )
61+ if default_tz is None :
62+ default_tz = n .tzinfo
63+
64+ # Django 1.9:
65+ # The correct way to resolve the AmbiguousTimeError every dst
66+ # transition is... the is_dst parameter appeared with 1.9
67+ # make_aware(some_datetime, get_current_timezone(), is_dst=True)
68+
69+ rounded_minute = (n .minute // 5 ) * 5
70+ d = datetime (n .year , n .month , n .day , n .hour , rounded_minute )
71+ try :
72+ retval = timezone .make_aware (d , default_tz )
73+ except AmbiguousTimeError :
74+ try :
75+ retval = timezone .make_aware (d , default_tz , is_dst = False )
76+ except TypeError : # Pre-Django 1.9
77+ retval = timezone .make_aware (
78+ datetime (n .year , n .month , n .day , n .hour + 1 , rounded_minute ),
79+ default_tz )
80+
81+ return retval
6682
6783
6884# ------------------------------------------------------------------------
0 commit comments