def test_npoints(): ts = traces.TimeSeries() ts[0] = 4 ts[1] = 2 ts[2] = 1 ts[5] = 2 ts[8] = 4 nose.tools.eq_(ts.n_points(), 5) nose.tools.eq_( ts.n_points(start=0, end=8, include_start=False, include_end=False), 3) nose.tools.eq_( ts.n_points(start=0, end=8, include_start=False, include_end=True), 4) nose.tools.eq_( ts.n_points(start=0, end=8, include_start=True, include_end=False), 4) nose.tools.eq_( ts.n_points(start=0, end=8, include_start=True, include_end=True), 5) nose.tools.eq_( ts.n_points(start=1, end=8, include_start=False, include_end=False), 2) nose.tools.eq_( ts.n_points(start=1, end=8, include_start=False, include_end=True), 3) nose.tools.eq_( ts.n_points(start=1, end=8, include_start=True, include_end=False), 3) nose.tools.eq_( ts.n_points(start=1, end=8, include_start=True, include_end=True), 4) ts = traces.TimeSeries() nose.tools.eq_(ts.n_points(), 0) nose.tools.eq_(ts.n_points(include_start=False), 0) nose.tools.eq_(ts.n_points(include_end=False), 0)
def test_traces(self): ts = traces.TimeSeries(default=0) ts[datetime(2042, 2, 1, 6, 0, 0)] = 10 ts[datetime(2042, 2, 1, 7, 45, 56)] = 10 print(ts) f = ts[datetime(2042, 2, 1, 6, 0, 0)] f2 = ts[datetime(2042, 2, 1, 6, 10, 0)] print(f, f2) # del ts[ts.first_key()] print(ts) ts2 = traces.TimeSeries(default=0) ts2[datetime(2042, 2, 1, 5, 0, 0)] = 5 ts2[datetime(2042, 2, 1, 6, 45, 0)] = 5 ts2[datetime(2042, 2, 1, 7, 40, 0)] = 2 ts2[datetime(2042, 2, 1, 8, 0, 0)] = 10 # h = traces.Histogram().median() count = ts * ts2 # d = count.plot(figure_width=6,interpolate=) count.compact() count.plot() l = list(count.iterintervals(n=1)) # count = traces.TimeSeries.merge([ts, ts2], operation=sum) # hist = count.distribution() # a, b= hist.items() # plt.hist(hist.items()) # plt.show() self.assertEqual(count[datetime(2042, 2, 1, 7, 50)], 20) self.assertEqual(count[datetime(2042, 2, 1, 8)], 100)
def test_mean_interpolate(): ts = traces.TimeSeries() ts[0] = 0 ts[1] = 0 ts[3] = 20 nose.tools.assert_almost_equal( ts.mean(0, 2, interpolate='linear'), 2.5, ) assert ts.mean(0, 2, interpolate='linear') == 2.5 mask = traces.TimeSeries(default=False) mask[0] = True mask[0.5] = False mask[1] = True mask[3] = False nose.tools.assert_almost_equal( ts.mean(0, 2, mask=mask, interpolate='linear'), 10/3.0, ) nose.tools.assert_almost_equal( ts.mean(0, 3, mask=mask, interpolate='linear'), 8.0, )
def test_encode_refuted_rec_sync(): from magnum.examples.feasible_example2 import feasible_example as g from magnum.solvers import smt from magnum.solvers import milp from stl.boolean_eval import pointwise_sat dt = g.model.dt refuted = {'u': traces.TimeSeries([(0, 0.5)])} phi = encode_refuted_rec(refuted, 0.1, g.times, dt=dt) g = bind(g).specs.learned.set(phi) res = smt.encode_and_run(g) assert pointwise_sat(phi, dt=dt)(res.solution) res = milp.encode_and_run(g) assert pointwise_sat(phi, dt=dt)(res.solution) refuted = {'u': traces.TimeSeries([(0, 1), (0.4, 1), (1, 0)])} phi = encode_refuted_rec(refuted, 0.1, g.times, dt=dt) g = bind(g).specs.learned.set(phi) res = smt.encode_and_run(g) assert pointwise_sat(phi, dt=dt)(res.solution) res = milp.encode_and_run(g) assert pointwise_sat(phi, dt=dt)(res.solution)
def test_bin(): # make some random dates start = datetime.datetime(2018, 12, 13, 7, 43, 15) end = datetime.datetime(2019, 2, 3, 8, 45, 10) # make a timeseries span = end-start ts = traces.TimeSeries() ts[start-span/2] = 2 ts[start] = 12 ts[start+span/3] = 5 ts[end - span/4] = 14 ts[end+span] = None # nose.tools.assert_raises(KeyError, ts.bin, 'days') # make a mask mask = traces.TimeSeries(default=False) mask[start] = True mask[end] = False mask[start + 3*span/10] = False mask[start + 5*span/10] = True binned = ts.bin('weeks', mask=mask) first = binned.peekitem(0) last = binned.peekitem() assert len(binned) == 7 assert first[0] == datetime.datetime(2018, 12, 10, 0, 0) assert last[0] == datetime.datetime(2019, 1, 21, 0, 0) assert int(last[1][5]) == 30581
def test_traces_am(self): ts = traces.TimeSeries(default=0) ts2 = traces.TimeSeries(default=0) ts.set_interval(start=datetime(year=2000, month=1, day=1, hour=4), end=datetime(year=2000, month=1, day=1, hour=5), value=5) ts.set_interval(start=datetime(year=2000, month=1, day=1, hour=5), end=datetime(year=2000, month=1, day=1, hour=6), value=10) ts.set_interval(start=datetime(year=2000, month=1, day=1, hour=6), end=datetime(year=2000, month=1, day=1, hour=7), value=3) ts2.set_interval(start=datetime(year=2000, month=1, day=1, hour=3, minute=30), end=datetime(year=2000, month=1, day=1, hour=4, minute=30), value=8) ts2.set_interval(start=datetime(year=2000, month=1, day=1, hour=4, minute=30), end=datetime(year=2000, month=1, day=1, hour=5, minute=30), value=5) ts2.set_interval(start=datetime(year=2000, month=1, day=1, hour=5, minute=30), end=datetime(year=2000, month=1, day=1, hour=6, minute=30), value=3) ts2.set_interval(start=datetime(year=2000, month=1, day=1, hour=6, minute=30), end=datetime(year=2000, month=1, day=1, hour=7, minute=30), value=5) # ts.plot() # ts2.plot() ts3 = ts * ts2 # ts3.plot() # plt.show() self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=3, minute=50)], 0) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=4, minute=10)], 40) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=4, minute=40)], 25) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=5, minute=10)], 50) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=5, minute=40)], 30) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=6, minute=10)], 9) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=6, minute=40)], 15) self.assertEqual(ts3[datetime(year=2000, month=1, day=1, hour=7, minute=10)], 0)
def test_missing(): """example code for dealing with missing datapoints""" router_a = traces.TimeSeries([(-10, 0), (-7, 1), (-5, None), (0, 3), (1, 3), (5, None)]) assert router_a[-6] == 1 assert router_a[-15] is None assert not router_a[15] router_b = traces.TimeSeries([(-8, 0), (-5, 0), (-2, 1), (5, 3)], default=0) assert router_b[7] == 3 # a separate signal tells us that the router went down at -10, -1 and 10 # we have no extra data about when it came online (other than the readings) for timestamp in [-10, -1, 10]: if timestamp < router_b.first_key(): router_b.default = None for start, end, value in router_b.iterperiods(): if timestamp >= start and timestamp < end: router_b[timestamp] = None if timestamp >= router_b.last_key(): router_b[timestamp] = None assert router_b[-15] is None assert router_b[-6] == 0 assert router_b[0] is None assert router_b[7] == 3 router_list = [router_a, router_b] # the default here should be the element returned by `count_merge([])` clients = traces.TimeSeries.merge(router_list, operation=traces.operations.strict_sum) assert clients[-15] is None assert clients[-6] == 1 assert clients[-0.5] is None assert clients[3] is None assert clients[15] is None system_uptime = clients.exists() assert system_uptime[-15] is False assert system_uptime[-6] is True assert system_uptime[-1] is False clients = traces.TimeSeries.merge(router_list, operation=traces.operations.ignorant_sum) assert clients[-15] == 0 assert clients[-6] == 1 assert clients[-0.5] == 0 assert clients[3] == 3 assert clients[15] == 0 system_uptime = clients.exists() assert system_uptime[-15] is True assert system_uptime[-5] is True assert system_uptime[-1] is True
def test_reference(): cart = traces.TimeSeries() cart[1.2] = {'broccoli'} cart[1.7] = {'broccoli', 'apple'} cart[2.2] = {'apple'} cart[3.5] = {'apple', 'beets'} assert cart[2] == {'broccoli', 'apple'} assert cart[-1] is None cart = traces.TimeSeries(default=set()) assert cart[-1] == set([])
def test_deltas(self): filter = Filters.DepthFilter(3) reader = TimeLimitedReader('resources/orderbook/_orderbooks.csv.gz', skip_time='530 sec', limit_time='10 sec') bids = [] asks = [] for item, _ in reader: if item.symbol == 'XBTUSD': res = filter.process(item) if res is not None and res[-2] != -1: v = np.sum(res[-1][1,:]) if res[-2] % 2 == 0 and v < 0: bids.append((res[0], -v)) elif v > 0: asks.append((res[0], v)) # tf, symbol, side? __delta-values bid_ts, bid_deltas = zip(*bids) ask_ts, ask_deltas = zip(*asks) bid_deltas = np.array(bid_deltas) ask_deltas = np.array(ask_deltas) bid_deltas[1:] -= bid_deltas[:-1] ask_deltas[1:] -= ask_deltas[:-1] # bids = zip(bid_ts, np.log(bid_deltas)) # asks = zip(ask_ts, np.log(ask_deltas)) # bids = zip(bid_ts[1:], np.clip(bid_deltas[1:], -1000., 1000.)) # asks = zip(ask_ts[1:], np.clip(ask_deltas[1:], -1000., 1000.)) bids = zip(bid_ts[1:], bid_deltas[1:]) asks = zip(ask_ts[1:], ask_deltas[1:]) print(f'bid deltas (neg) {len(bid_ts)}, ask deltas (pos) = {len(ask_ts)}') t1 = time.time() ts_bid = traces.TimeSeries(bids, default=0) ts_ask = traces.TimeSeries(asks, default=0) ts = ts_ask * ts_bid t2 = time.time() - t1 print(f'Time to compute timeseries {t2}') ts.plot() plt.show() t1 = time.time() sq1 = np.sqrt(np.sum(np.square(ask_deltas[1:]))) sq2 = np.sqrt(np.sum(np.square(bid_deltas[1:]))) values = sum(list(ts._d.values())) hy = values / sq1 / sq2 t2 = time.time() - t1 print(f'Time to compute Hoyashi-Yoshido cor {t2}') print(hy)
def test_find_refuted_radius(): from magnum.examples.rock_paper_scissors import rps as g play = {'u': traces.TimeSeries([(0, 1)])} counter = {'w': traces.TimeSeries([(0, 20 / 60)])} r = find_refuted_radius(g, play, counter, tol=1e-6) assert approx(10 / 60, abs=1e-5) == r play = {'u': traces.TimeSeries([(0, 0)])} counter = {'w': traces.TimeSeries([(0, 20 / 60)])} r = find_refuted_radius(g, play, counter, tol=1e-6) assert approx(10 / 60, abs=1e-5) == r play = {'u': traces.TimeSeries([(0, 20 / 60)])} counter = {'w': traces.TimeSeries([(0, 40 / 60)])} r = find_refuted_radius(g, play, counter, tol=1e-6) assert approx(10 / 60, abs=1e-5) == r play = {'u': traces.TimeSeries([(0, 40 / 60)])} counter = {'w': traces.TimeSeries([(0, 0)])} r = find_refuted_radius(g, play, counter, tol=1e-6) assert approx(10 / 60, abs=1e-5) == r
def test_sample(): time_list = [ datetime.datetime(2016, 1, 1, 1, 1, 2), datetime.datetime(2016, 1, 1, 1, 1, 3), datetime.datetime(2016, 1, 1, 1, 1, 8), datetime.datetime(2016, 1, 1, 1, 1, 10) ] ts = _make_ts(int, time_list, [1, 2, 3, 0]) def curr_time(i): return datetime.datetime(2016, 1, 1, 1, 1, i) # Check first arguments assert dict(ts.sample(1, time_list[0], time_list[-1])) == { curr_time(i): ts[curr_time(i)] for i in range(2, 11) } assert dict(ts.sample(2, time_list[0], time_list[-1])) == { curr_time(i): ts[curr_time(i)] for i in range(2, 11, 2) } nose.tools.assert_raises(ValueError, ts.sample, -1, time_list[0], time_list[-1]) nose.tools.assert_raises(ValueError, ts.sample, 20, time_list[0], time_list[-1]) # Check second and third arguments nose.tools.assert_raises(ValueError, ts.sample, 1, time_list[3], time_list[0]) assert dict(ts.sample(1, curr_time(5), curr_time(10))) == { curr_time(i): ts[curr_time(i)] for i in range(5, 11) } assert dict(ts.sample(1, curr_time(2), curr_time(5))) == { curr_time(i): ts[curr_time(i)] for i in range(2, 6) } assert dict(ts.sample(1, curr_time(0), curr_time(13))) == { curr_time(i): ts[curr_time(i)] for i in range(0, 14) } # Check using int ts = traces.TimeSeries([[1, 2], [2, 3], [6, 1], [8, 4]]) assert dict(ts.sample(1, 1, 8)) == {i: ts[i] for i in range(1, 9)} assert dict(ts.sample( 0.5, 1, 8)) == {1 + i / 2.: ts[1 + i / 2.] for i in range(0, 15)} nose.tools.assert_raises(ValueError, ts.sample, 0.5, -traces.inf, 8) nose.tools.assert_raises(ValueError, ts.sample, 0.5, 1, traces.inf) # Test pandas compatibility pd_ts = pd.Series(dict(ts.sample(1, 1, 8))) assert all(pd_ts.index[i - 1] == i for i in range(1, 9)) assert all(pd_ts.values[i - 1] == ts[i] for i in range(1, 9))
def _eval(x): y = f(x) out = traces.TimeSeries(((t - dt, v) for t, v in y)) out = out.slice(y.domain.start(), y.domain.end()) out.compact() return out
def test_histogram_stats_with_nones(): histogram = traces.Histogram() nose.tools.eq_(histogram.mean(), None) nose.tools.eq_(histogram.variance(), None) nose.tools.eq_(histogram.standard_deviation(), None) nose.tools.eq_(histogram.min(), None) nose.tools.eq_(histogram.max(), None) nose.tools.eq_(histogram.median(), None) histogram = traces.Histogram.from_dict({None: 1}, key=hash) nose.tools.eq_(histogram.mean(), None) nose.tools.eq_(histogram.variance(), None) nose.tools.eq_(histogram.standard_deviation(), None) nose.tools.eq_(histogram.min(), None) nose.tools.eq_(histogram.max(), None) nose.tools.eq_(histogram.median(), None) ts = traces.TimeSeries() ts[0] = None ts[1] = 5 ts[2] = 6 ts[3] = None ts[9] = 7 ts[10] = None histogram = ts.distribution(start=0, end=10) nose.tools.eq_(histogram.mean(), 6)
def _eval(x): y1, y2 = f1(x), f2(x) y = y1.operation(y2, lambda a, b: (a, b)) out = traces.TimeSeries(apply_until(y), domain=y1.domain) out.compact() return out
def test_encode_refuted_rec(): refuted = { 'u1': traces.TimeSeries([(0, 0), (1, 1)]), 'u2': traces.TimeSeries([(0, 0.5)]) } phi = encode_refuted_rec(refuted, 0.2, [0]) psi1 = stl.parse('(u1 < -0.2) | (u1 > 0.2)') psi2 = stl.parse('(u2 < 0.3) | (u2 > 0.7)') assert phi == psi1 | psi2 psi3 = stl.parse('X(u1 < 0.8)') psi4 = stl.parse('(X(u2 < 0.3)) | (X(u2 > 0.7))') phi = encode_refuted_rec(refuted, 0.2, [1]) assert phi == psi3 | psi4 phi = encode_refuted_rec(refuted, 0.2, [0, 1]) assert set(phi.args) == set((psi1 | psi2 | psi3 | psi4).args)
def test_compact(): # since this is random, do it a bunch of times for n_trial in range(100): # make two time series, one compact and one not test_ts = traces.TimeSeries() compact_ts = traces.TimeSeries() for t in range(100): value = random.randint(0, 2) test_ts.set(t, value) compact_ts.set(t, value, compact=True) # make test_ts compact test_ts.compact() # items should be exactly the same assert test_ts.items() == compact_ts.items()
def _eval(x): y = f(x) if len(y) <= 1: return y out = traces.TimeSeries(process_intervals(y)).slice( y.domain.start(), y.domain.end()) out.compact() return out
def extract_ts(name, model, g, store): dt = g.model.dt # TODO: hack to have to eval this # TODO: support extracting H=0 timeseries ts = traces.TimeSeries( ((dt * t, eval(str(model[store[name, t]]))) for t in g.times if (name, t) in store and store[name, t] in model), domain=(0, g.scope + dt)) ts.compact() return ts
def get_stats_from_ss(ss): df = pd.concat([ pd.DataFrame(dict(t=ss.start, dx=1)), pd.DataFrame(dict(t=ss.stop, dx=-1)) ]) w = df.sort_values('t')['dx'].cumsum().pipe( lambda s: set_index(s, df.t - df.t.iloc[0])).sort_index() x = traces.TimeSeries(data=w) s = pd.Series(*reversed(list(zip(*x.sample(0.1))))) return x.mean(), (s == 0).mean()
def test_plot(): ts = traces.TimeSeries() ts[0] = 0 ts[1] = 2 ts[3] = 1 ts[5] = 0 figure, axes = ts.plot() return figure
def extract_ts(name, model, g, store): dt = g.model.dt model = {k: v.primal for k, v in model.variables.items()} ts = traces.TimeSeries( ((dt * t, model[store[name, t][0].name]) for t in g.times if not isinstance(store[name, t][0], (float, int)) and store[name, t][0].name in model), domain=(0, g.scaled_scope + dt)) ts.compact() return ts
def test_smt_radius_oracle(): from magnum.examples.rock_paper_scissors import rps as g play = {'u': traces.TimeSeries([(0, 1)])} counter = {'w': traces.TimeSeries([(0, 20 / 60)])} oracle = smt_radius_oracle(g=g, play=play, counter=counter) assert not oracle(r=9 / 60) assert oracle(r=20 / 60) assert oracle(r=1) play = {'u': traces.TimeSeries([(0, 0)])} counter = {'w': traces.TimeSeries([(0, 20 / 60)])} oracle = smt_radius_oracle(g=g, play=play, counter=counter) assert not oracle(r=5 / 60) assert not oracle(r=9 / 60) assert oracle(r=11 / 60) assert oracle(r=1)
def test_invalid_call(): ts = traces.TimeSeries() ts[0] = 0 ts[1] = 1 ts.plot(interpolate='previous') ts.plot(interpolate='linear') with pytest.raises(ValueError): ts.plot(interpolate='yomama')
def test_radd(): ts1 = traces.TimeSeries(default=0) ts1[0] = 1 ts1[2] = 0 ts1[3] = 1 ts1[4] = 0 ts2 = traces.TimeSeries(default=0) ts2[-1] = 1 ts2[2] = 0 ts2[3] = 1 ts2[4] = 0 ts3 = ts1 + ts2 nose.tools.eq_(list(ts3.items()), [(-1, 1), (0, 2), (2, 0), (3, 2), (4, 0)]) nose.tools.assert_raises(TypeError, ts3.__radd__, 1)
def slice(self, series, start, end, default=0): """Technically TimeSeries has a method for this, but it wasn't working and it was easier to write something of my own than to try to fix that. """ result = traces.TimeSeries(default=default) for t0, t1, value in series.iterperiods(start, end): result[t0] = value result[t1] = series[t1] return result
def get_trace(df, date): end_date = date + pd.Timedelta(days=1) single_date_df = df[(df['Date'] >= date) & (df['Date'] < end_date)] per_car_timeseries = [] for x in single_date_df[["Date", "duration"]].values: ts = traces.TimeSeries(default=0) ticket_start = x[0] ticket_end = get_ticket_end(ticket_start, x[1]) ts[ticket_start], ts[ticket_end] = 1, 0 per_car_timeseries.append(ts) ret = traces.TimeSeries.merge(per_car_timeseries, operation=sum, compact=True) return ret
def test_counter_examples(): from magnum.examples.feasible_example2 import feasible_example as g res = milp.encode_and_run(g) assert res.feasible ces = [{'w': traces.TimeSeries([(0, 0)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible ces = [{'w': traces.TimeSeries([(0, 1)])}] res = milp.encode_and_run(g, counter_examples=ces) assert not res.feasible ces = [{ 'w': traces.TimeSeries([(0, 1)]) }, { 'w': traces.TimeSeries([(0, 0)]) }] res = milp.encode_and_run(g, counter_examples=ces) assert not res.feasible
def stack(self, duration, start_times, operation): ts_list = [] for start in start_times: end = start + duration ts = traces.TimeSeries() for t0, dur, value in self.iterperiods(start, end): offset = t0 - start if isinstance(offset, datetime.timedelta): offset = offset.total_seconds() ts.set(offset, value, compact=True) ts_list.append(ts) return traces.TimeSeries.merge(ts_list, operation=operation)
def test_rps_counter_examples(): from magnum.examples.rock_paper_scissors import rps as g from stl.boolean_eval import pointwise_sat # Respond to Paper ces = [{'w': traces.TimeSeries([(0, 20 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 phi = stl.parse('X((x >= 10) & (x <= 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) # Respond to Scissors and Paper ces.append({'w': traces.TimeSeries([(0, 40 / 60)])}) res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 phi = stl.parse('X((x >= 30) & (x <= 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) ces.append({'w': traces.TimeSeries([(0, 0)])}) res = milp.encode_and_run(g, counter_examples=ces) assert not res.feasible assert pytest.approx(res.cost) == 0 phi = stl.parse('X((x = 10) | (x = 30) | (x = 50))') assert pointwise_sat(phi, dt=g.model.dt)(res.solution) g = g.invert() res = milp.encode_and_run(g) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [{'u': traces.TimeSeries([(0, 20 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [{'u': traces.TimeSeries([(0, 40 / 60)])}] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible assert pytest.approx(res.cost) == 10 ces = [({'u': traces.TimeSeries([(0, 0)])})] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible ces = [({'u': traces.TimeSeries([(0, 1)])})] res = milp.encode_and_run(g, counter_examples=ces) assert res.feasible
def get_time(self, triad): credentials = self.get_credentials() http = credentials.authorize(httplib2.Http()) service = discovery.build('calendar', 'v3', http=http) now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time # Got freebusy code from https://gist.github.com/cwurld/9b4e10dbeecab28345a3 body = { "timeMin": now, "timeMax": (datetime.datetime.utcnow() + self.time_window).isoformat() + 'Z', "timeZone": 'US/Central', "items": [{"id": email} for email in triad] } eventsResult = service.freebusy().query(body=body).execute() cal_dict = eventsResult[u'calendars'] busy_times_list = [] for cal_name in cal_dict: busy_times = traces.TimeSeries(default=0) # default is free (0), for busy_window in cal_dict[cal_name]['busy']: # manually add busy times busy_times[busy_window['start']] = 1 busy_times[busy_window['end']] = 0 busy_times_list.append(busy_times) # combine all of the calendars to find when everyone is free try: combined_free_times = traces.TimeSeries.merge(busy_times_list, operation=sum) except ValueError: print('One of the time series is empty. One of the emails is most likely wrong.') return all_start_times = self.interim_periods(combined_free_times) all_intervals = self.entire_interval_free(all_start_times).to_bool(invert=True) eligible_times = [i[0] for i in all_intervals.items() if i[1] is True \ and self.within_timebox(i[0])\ and not self.is_weekend(i[0])] if not eligible_times: print('There are no available times for that group in that time range.') return else: event_time = eligible_times[0] # for now, take first time that works. we can refine print(event_time) return event_time