Skip to content

Commit

Permalink
Added comments explaining round_time
Browse files Browse the repository at this point in the history
  • Loading branch information
markusschmaus authored and mistercrunch committed Sep 11, 2015
1 parent 8b2bf95 commit 94dde28
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions airflow/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,23 +522,55 @@ def as_tuple(obj):


def round_time(dt, delta, start_date=datetime.min):
"""
Returns the datetime of the form start_date + i * delta
which is closest to dt for any non-negative integer i.
"""
# Ignore the microseconds of dt
dt -= timedelta(microseconds = dt.microsecond)

# We are looking for a datetime in the form start_date + i * delta
# which is as close as possible to dt. Since delta could be a relative
# delta we don't know it's exact length in seconds so we cannot rely on
# division to find i. Instead we employ a binary search algorithm, first
# finding an upper and lower limit and then disecting the interval until
# we have found the closest match.

# We first search an upper limit for i for which start_date + upper * delta
# exceeds dt.
upper = 1
while start_date + upper*delta < dt:
# To speed up finding an upper limit we grow this exponentially by a
# factor of 2
upper *= 2

# Since upper is the first value for which start_date + upper * delta
# exceeds dt, upper // 2 is below dt and therefore forms a lower limited
# for the i we are looking for
lower = upper // 2

# We now continue to intersect the interval between
# start_date + lower * delta and start_date + upper * delta
# until we find the closest value
while True:
# If start_date + (lower + 1)*delta exceeds dt, then either lower or
# lower+1 has to be the solution we are searching for
if start_date + (lower + 1)*delta > dt:
# Check if start_date + (lower + 1)*delta or
# start_date + lower*delta is closer to dt and return the solution
if (start_date + (lower + 1)*delta) - dt < dt - (start_date + lower*delta):
return start_date + (lower + 1)*delta
else:
return start_date + lower*delta

# We intersect the interval and either replace the lower or upper
# limit with the candidate
candidate = lower + (upper - lower) // 2
if start_date + candidate*delta > dt:
upper = candidate
else:
lower = candidate

# in the special case when start_date > dt the search for upper will
# immediately stop for upper == 1 which results in lower = upper // 2 = 0
# and this function returns start_date.

0 comments on commit 94dde28

Please sign in to comment.