Python如何判断Datetime是否处于YAML加载的时间间隔字典列表内
时间区间判断最优实现方案
针对你需要高效判断指定UTC时间是否落在任意给定时间区间的需求,最优方案是预处理时合并有序区间+查询时二分查找,仅需一次O(nlogn)的预处理开销,后续每次查询时间复杂度低至O(logk)(k为合并后区间数量),远优于逐一遍历的O(n)效率,同时逻辑清晰易维护。
完整实现代码
import yaml import bisect from datetime import datetime # 1. 加载YAML配置 with open(r'test.yml', encoding='utf-8') as file: config = yaml.load(file, Loader=yaml.FullLoader) # 2. 预处理区间:提取、排序、合并 raw_intervals = [] for item in config['ignore_state_change']: start = item['start_time_utc'] end = item['end_time_utc'] # 过滤无效区间(开始时间晚于结束时间) if start <= end: raw_intervals.append((start, end)) # 按区间起始时间排序 raw_intervals.sort() # 合并重叠/相邻区间,减少后续查询冗余 merged_intervals = [] for curr_start, curr_end in raw_intervals: if not merged_intervals: merged_intervals.append((curr_start, curr_end)) continue last_start, last_end = merged_intervals[-1] # 当前区间与最后一个已合并区间重叠/首尾相接则合并 if curr_start <= last_end: merged_intervals[-1] = (last_start, max(last_end, curr_end)) else: merged_intervals.append((curr_start, curr_end)) # 单独提取所有区间的起始时间,用于二分查找 start_time_list = [interval[0] for interval in merged_intervals] # 3. 区间判断函数 def is_in_ignore_range(event_time_utc: datetime) -> bool: # 查找第一个大于目标时间的区间起始位置 idx = bisect.bisect_right(start_time_list, event_time_utc) # 目标时间早于所有区间起始时间 if idx == 0: return False # 校验目标时间是否落在对应区间的结束时间之前 _, target_end = merged_intervals[idx-1] # 此处为左闭右闭区间判断,如需左闭右开可将<=改为< return event_time_utc <= target_end
使用示例
# 测试时间1:落在第一个区间内 test1 = datetime(2021, 8, 4, 23, 30, 0, tzinfo=datetime.timezone.utc) print(is_in_ignore_range(test1)) # 输出:True # 测试时间2:落在两个区间的间隙中 test2 = datetime(2021, 8, 5, 0, 30, 0, tzinfo=datetime.timezone.utc) print(is_in_ignore_range(test2)) # 输出:False # 测试时间3:落在第二个区间内 test3 = datetime(2021, 8, 5, 1, 40, 0, tzinfo=datetime.timezone.utc) print(is_in_ignore_range(test3)) # 输出:True
注意事项
- 需保证入参
event_time_utc是带UTC时区信息的datetime对象,和YAML加载出的时间对象时区一致,否则会抛出时区比较异常。 - 如果你的区间数量极少(少于10个)且查询次数很低,逐一遍历的开销也可以接受,但本方案扩展性更强,区间数量增长时不会出现性能衰减。
- 预处理步骤仅需执行一次,不需要每次查询都重复加载YAML、合并区间。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

