def zero_fill(start, end, data_sets, spacing=DAY_IN_MILLIS): """Given one or more histogram dicts, zero fill them in a range. The format of the dictionaries should be {milliseconds: numeric value}. It is important that the time points in the dictionary are equally spaced. If they are not, extra points will be added. This method works with milliseconds because that is the format elasticsearch and Javascript use. :arg start: Datetime to start zero filling. :arg end: Datetime to stop zero filling at. :arg data_sets: A list of dictionaries to zero fill. :arg spacing: Number of milliseconds between data points. """ start_millis = epoch_milliseconds(start) # Date ranges are inclusive on both ends. end_millis = epoch_milliseconds(end) + spacing # `timestamp` is a loop counter that iterates over the timestamps # from start to end. It can't just be `timestamp = start`, because # then the zeros being adding to the data might not be aligned # with the data already in the graph, since we aren't counting by # 24 hours, and the data could have a timezone offset. # # This block picks a time up to `spacing` time after `start` so # that it lines up with the data. If there is no data, then we use # `stamp = start`, because there is nothing to align with. # start <= timestamp < start + spacing days = [d for d in data_sets if d.keys()] if days: source = days[0] timestamp = source.keys()[0] d = floor((timestamp - start_millis) / spacing) timestamp -= d * spacing else: # If there no data, it doesn't matter how it aligns. timestamp = start_millis # Iterate in the range `start` to `end`, starting from # `timestamp`, increasing by `spacing` each time. This ensures # there is a data point for each day. while timestamp < end_millis: for d in data_sets: if timestamp not in d: d[timestamp] = 0 timestamp += spacing
def _zero_fill(start, end, data_sets, spacing=DAY_IN_MILLIS): """Given one or more histogram dicts, zero fill them in a range. The format of the dictionaries should be {milliseconds: numeric value}. It is important that the time points in the dictionary are equally spaced. If they are not, extra points will be added. This method works with milliseconds because that is the format elasticsearch and Javascript use. :arg start: Datetime to start zero filling. :arg end: Datetime to stop zero filling at. :arg data_sets: A list of dictionaries to zero fill. :arg spacing: Number of milliseconds between data points. """ start_millis = epoch_milliseconds(start) # Date ranges are inclusive on both ends. end_millis = epoch_milliseconds(end) + spacing # `timestamp` is a loop counter that iterates over the timestamps # from start to end. It can't just be `timestamp = start`, because # then the zeros being adding to the data might not be aligned # with the data already in the graph, since we aren't counting by # 24 hours, and the data could have a timezone offset. # # This block picks a time up to `spacing` time after `start` so # that it lines up with the data. If there is no data, then we use # `stamp = start`, because there is nothing to align with. # start <= timestamp < start + spacing days = [d for d in data_sets if d.keys()] if days: source = days[0] timestamp = source.keys()[0] d = floor((timestamp - start_millis) / spacing) timestamp -= d * spacing else: # If there no data, it doesn't matter how it aligns. timestamp = start_millis # Iterate in the range `start` to `end`, starting from # `timestamp`, increasing by `spacing` each time. This ensures # there is a data point for each day. while timestamp < end_millis: for d in data_sets: if timestamp not in d: d[timestamp] = 0 timestamp += spacing
def test_zerofill(self): start = datetime(2012, 1, 1) end = datetime(2012, 1, 7) data1 = {epoch_milliseconds(datetime(2012, 1, 3)): 1, epoch_milliseconds(datetime(2012, 1, 5)): 1} data2 = { epoch_milliseconds(datetime(2012, 1, 2)): 1, epoch_milliseconds(datetime(2012, 1, 5)): 1, epoch_milliseconds(datetime(2012, 1, 10)): 1, } _zero_fill(start, end, [data1, data2]) for day in range(1, 8): millis = epoch_milliseconds(datetime(2012, 1, day)) assert millis in data1, "Day %s was not zero filled." % day assert millis in data2, "Day %s was not zero filled." % day
def test_zerofill(self): start = datetime(2012, 1, 1) end = datetime(2012, 1, 7) data1 = { epoch_milliseconds(datetime(2012, 1, 3)): 1, epoch_milliseconds(datetime(2012, 1, 5)): 1, } data2 = { epoch_milliseconds(datetime(2012, 1, 2)): 1, epoch_milliseconds(datetime(2012, 1, 5)): 1, epoch_milliseconds(datetime(2012, 1, 10)): 1, } zero_fill(start, end, [data1, data2]) for day in range(1, 7): millis = epoch_milliseconds(datetime(2012, 1, day)) assert millis in data1, "Day %s was not zero filled." % day assert millis in data2, "Day %s was not zero filled." % day