def test_vixie_cronstring_schedule(): start_time = create_pendulum_time(year=2022, month=2, day=21, hour=1, minute=30, second=1, tz="US/Pacific") time_iter = schedule_execution_time_iterator(start_time.timestamp(), "@hourly", "US/Pacific") for _i in range(6): # 2:00, 3:00, 4:00, 5:00, 6:00, 7:00 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2022, month=2, day=21, hour=7, tz="US/Pacific").timestamp()) time_iter = schedule_execution_time_iterator(start_time.timestamp(), "@daily", "US/Pacific") for _i in range(6): # 2/22, 2/23, 2/24, 2/25, 2/26, 2/27 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2022, month=2, day=27, tz="US/Pacific").timestamp()) time_iter = schedule_execution_time_iterator(start_time.timestamp(), "@weekly", "US/Pacific") for _i in range(6): # 2/27, 3/6, 3/13, 3/20, 3/27, 4/3 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2022, month=4, day=3, tz="US/Pacific").timestamp()) time_iter = schedule_execution_time_iterator(start_time.timestamp(), "@monthly", "US/Pacific") for _i in range(6): # 3/1, 4/1, 5/1, 6/1, 7/1, 8/1 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2022, month=8, day=1, tz="US/Pacific").timestamp()) time_iter = schedule_execution_time_iterator(start_time.timestamp(), "@yearly", "US/Pacific") for _i in range(6): # 1/1/2023, 1/1/2024, 1/1/2025, 1/1/2026, 1/1/2027, 1/1/2028 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2028, month=1, day=1, tz="US/Pacific").timestamp())
def get_schedule_range_partitions(): tz = timezone if timezone else pendulum.now().timezone.name _start = (start.in_tz(tz) if isinstance(start, pendulum.Pendulum) else pendulum.instance(start, tz=tz)) if not end: _end = pendulum.now(tz) elif isinstance(end, pendulum.Pendulum): _end = end.in_tz(tz) else: _end = pendulum.instance(end, tz=tz) end_timestamp = _end.timestamp() partitions = [] for next_time in schedule_execution_time_iterator( _start.timestamp(), cron_schedule, tz): partition_time = execution_time_to_partition_fn(next_time) if partition_time.timestamp() > end_timestamp: break if partition_time.timestamp() < _start.timestamp(): continue partitions.append( Partition(value=partition_time, name=partition_time.strftime(fmt))) return partitions[:-1]
def time_window_for_partition_key(self, partition_key: str) -> TimeWindow: start = self.start_time_for_partition_key(partition_key) iterator = schedule_execution_time_iterator( start_timestamp=start.timestamp(), cron_schedule=get_cron_schedule(schedule_type=self.schedule_type), execution_timezone=self.timezone, ) next(iterator) return TimeWindow(start, next(iterator))
def test_invalid_cron_string(): start_time = create_pendulum_time(year=2022, month=2, day=21, hour=1, minute=30, second=1, tz="US/Pacific") with pytest.raises(CheckError): next( schedule_execution_time_iterator(start_time.timestamp(), "* * * * * *", "US/Pacific"))
def get_partitions( self, current_time: Optional[datetime] = None ) -> List[Partition[TimeWindow]]: current_timestamp = (pendulum.instance(current_time, tz=self.timezone) if current_time else pendulum.now( self.timezone)).timestamp() time_of_day = time(self.hour_offset, self.minute_offset) start_timestamp = pendulum.instance(self.start, tz=self.timezone).timestamp() iterator = schedule_execution_time_iterator( start_timestamp=start_timestamp, cron_schedule=get_cron_schedule( schedule_type=self.schedule_type, time_of_day=time_of_day, execution_day=self.day_offset, ), execution_timezone=self.timezone, ) partitions: List[Partition[TimeWindow]] = [] prev_time = next(iterator) while prev_time.timestamp() < start_timestamp: prev_time = next(iterator) end_offset = self.end_offset partitions_past_current_time = 0 while True: next_time = next(iterator) if (next_time.timestamp() <= current_timestamp or partitions_past_current_time < end_offset): partitions.append( Partition( value=TimeWindow(prev_time, next_time), name=prev_time.strftime(self.fmt), )) if next_time.timestamp() > current_timestamp: partitions_past_current_time += 1 else: break prev_time = next_time if end_offset < 0: partitions = partitions[:end_offset] return partitions
def time_window_for_partition_key(self, partition_key: str) -> TimeWindow: start = self.start_time_for_partition_key(partition_key) time_of_day = time(self.hour_offset, self.minute_offset) iterator = schedule_execution_time_iterator( start_timestamp=start.timestamp(), cron_schedule=get_cron_schedule( schedule_type=self.schedule_type, time_of_day=time_of_day, execution_day=self.day_offset, ), execution_timezone=self.timezone, ) return TimeWindow(next(iterator), next(iterator))
def test_cron_schedule_advances_past_dst(): # In Australia/Sydney, DST is at 2AM on 10/3/21. Verify that we don't # get stuck on the DST boundary. start_time = create_pendulum_time(year=2021, month=10, day=3, hour=1, minute=30, second=1, tz="Australia/Sydney") time_iter = schedule_execution_time_iterator(start_time.timestamp(), "*/15 * * * *", "Australia/Sydney") for _i in range(6): # 1:45, 3:00, 3:15, 3:30, 3:45, 4:00 next_time = next(time_iter) assert (next_time.timestamp() == create_pendulum_time( year=2021, month=10, day=3, hour=4, tz="Australia/Sydney").timestamp())
def get_schedule_range_partitions(current_time=None): check.opt_inst_param(current_time, "current_time", datetime.datetime) tz = timezone if timezone else "UTC" _start = ( to_timezone(start, tz) if isinstance(start, PendulumDateTime) else pendulum.instance(start, tz=tz) ) if end: _end = end elif current_time: _end = current_time else: _end = pendulum.now(tz) # coerce to the definition timezone if isinstance(_end, PendulumDateTime): _end = to_timezone(_end, tz) else: _end = pendulum.instance(_end, tz=tz) end_timestamp = _end.timestamp() partitions = [] for next_time in schedule_execution_time_iterator(_start.timestamp(), cron_schedule, tz): partition_time = execution_time_to_partition_fn(next_time) if partition_time.timestamp() > end_timestamp: break if partition_time.timestamp() < _start.timestamp(): continue partitions.append(Partition(value=partition_time, name=partition_time.strftime(fmt))) return partitions if inclusive else partitions[:-1]
def execution_time_iterator(self, start_timestamp): return schedule_execution_time_iterator(start_timestamp, self.cron_schedule, self.execution_timezone)