+class TimeMock:
+ delta = {}
+ delta_init = 0
+ true_time = time.time
+ true_sleep = time.sleep
+ time_patch = None
+ datetime_patch = None
+
+ @classmethod
+ def travel(cls, start_date):
+ cls.delta = {}
+ cls.delta_init = (datetime.datetime.now() - start_date).total_seconds()
+
+ @classmethod
+ def start(cls):
+ cls.delta = {}
+ cls.delta_init = 0
+
+ class fake_datetime(datetime.datetime):
+ @classmethod
+ def now(cls, tz=None):
+ if tz is None:
+ return cls.fromtimestamp(time.time())
+ else:
+ return tz.fromutc(cls.utcfromtimestamp(time.time()).replace(tzinfo=tz))
+
+ cls.time_patch = mock.patch.multiple(time, time=cls.fake_time, sleep=cls.fake_sleep)
+ cls.datetime_patch = mock.patch.multiple(datetime, datetime=fake_datetime)
+ cls.time_patch.start()
+ cls.datetime_patch.start()
+
+ @classmethod
+ def stop(cls):
+ cls.delta = {}
+ cls.delta_init = 0
+
+ @classmethod
+ def fake_time(cls):
+ cls.delta.setdefault(threading.current_thread(), cls.delta_init)
+ return cls.true_time() - cls.delta[threading.current_thread()]
+
+ @classmethod
+ def fake_sleep(cls, duration):
+ cls.delta.setdefault(threading.current_thread(), cls.delta_init)
+ cls.delta[threading.current_thread()] -= float(duration)
+ cls.true_sleep(min(float(duration), 0.1))
+
+TimeMock.start()