Python datetime时间范围判断与限时区域车辆停车时长计算技术问询
解决Python中Datetime时间范围判断与受限区域停车时长计算问题
嘿,我来帮你搞定这两个核心问题——其实用你已经在使用的pandas加上Python自带的datetime模块就完全能解决,不需要额外安装工具库,下面一步步拆解方案:
一、判断Datetime是否处于指定时间范围内
不管是单个时间对象,还是pandas DataFrame里的批量时间列,都有简洁的处理方式:
1. 单个Datetime对象的判断
直接用比较运算符就行,注意要保证所有时间的时区一致(如果有时区的话):
from datetime import datetime target_dt = datetime(2024, 5, 20, 14, 30) start_range = datetime(2024, 5, 20, 8, 0) end_range = datetime(2024, 5, 20, 18, 0) # 判断是否在范围内 is_in_range = start_range <= target_dt <= end_range print(is_in_range) # 输出True
2. Pandas DataFrame批量判断
先确保你的时间列已经转成pandas的datetime类型(如果还没转的话),然后用布尔索引或者between()方法:
import pandas as pd # 示例数据 df = pd.DataFrame({ 'park_start': ['2024-05-20 07:30', '2024-05-20 15:00', '2024-05-20 19:00'], 'park_end': ['2024-05-20 09:00', '2024-05-20 17:00', '2024-05-20 21:00'] }) # 转成datetime类型 df['park_start'] = pd.to_datetime(df['park_start']) df['park_end'] = pd.to_datetime(df['park_end']) # 定义限制时间范围 restriction_start = pd.to_datetime('2024-05-20 08:00') restriction_end = pd.to_datetime('2024-05-20 18:00') # 批量判断停车开始时间是否在限制范围内 df['start_in_restriction'] = df['park_start'].between(restriction_start, restriction_end) # 或者用布尔表达式更灵活 df['end_in_restriction'] = (df['park_end'] >= restriction_start) & (df['park_end'] <= restriction_end)
二、计算受限区域内的停车时长
这部分是核心场景,我们需要计算停车时间段和区域强制限制时间段的重叠时长。假设你有两个CSV:
- 一个是车辆停车记录(包含车辆ID、停车区域ID、停车开始/结束时间)
- 另一个是区域限制规则(包含区域ID、限制开始/结束时间,可能是单日或周期性规则)
1. 基础场景:单日限制规则的重叠计算
先把两个DataFrame按区域ID关联,然后用矢量化方法计算重叠时长(比apply()效率高很多):
import pandas as pd from datetime import timedelta # 模拟停车记录CSV数据 park_records = pd.DataFrame({ 'car_id': ['A1', 'A2', 'A3'], 'zone_id': ['Z01', 'Z01', 'Z02'], 'park_start': pd.to_datetime(['2024-05-20 07:30', '2024-05-20 16:00', '2024-05-20 10:00']), 'park_end': pd.to_datetime(['2024-05-20 09:00', '2024-05-20 19:00', '2024-05-20 12:00']) }) # 模拟区域限制规则CSV数据 zone_restrictions = pd.DataFrame({ 'zone_id': ['Z01', 'Z02'], 'restrict_start': pd.to_datetime(['2024-05-20 08:00', '2024-05-20 09:00']), 'restrict_end': pd.to_datetime(['2024-05-20 18:00', '2024-05-20 17:00']) }) # 关联两个DataFrame merged_df = pd.merge(park_records, zone_restrictions, on='zone_id', how='left') # 计算重叠时间段的起止时间 merged_df['overlap_start'] = merged_df[['park_start', 'restrict_start']].max(axis=1) merged_df['overlap_end'] = merged_df[['park_end', 'restrict_end']].min(axis=1) # 计算重叠时长,没有重叠的情况设为0 merged_df['restricted_park_duration'] = merged_df['overlap_end'] - merged_df['overlap_start'] merged_df['restricted_park_duration'] = merged_df['restricted_park_duration'].where( merged_df['overlap_start'] < merged_df['overlap_end'], timedelta(0) ) # 可以转成小时数更直观 merged_df['restricted_hours'] = merged_df['restricted_park_duration'].dt.total_seconds() / 3600
2. 进阶场景:周期性限制规则(如每周固定时段)
如果限制是每周重复的(比如周一到周五的8:00-18:00),需要把停车时间段拆分成单日片段,再逐个和当日的限制时间计算重叠:
def split_park_period(row): # 把停车时间段拆分成每天的时间段 dates = pd.date_range(row['park_start'].date(), row['park_end'].date(), freq='D') periods = [] for date in dates: day_start = datetime.combine(date, datetime.min.time()) day_end = datetime.combine(date, datetime.max.time()) period_start = max(row['park_start'], day_start) period_end = min(row['park_end'], day_end) periods.append({'car_id': row['car_id'], 'zone_id': row['zone_id'], 'period_start': period_start, 'period_end': period_end}) return pd.DataFrame(periods) # 拆分所有停车记录为单日片段 split_df = park_records.apply(split_park_period, axis=1).explode().reset_index(drop=True) # 这里假设区域限制是每周一到周五8:00-18:00,先判断日期是否在工作日 split_df['is_weekday'] = split_df['period_start'].dt.weekday < 5 # 设置当日的限制时间 split_df['restrict_start'] = split_df['period_start'].dt.floor('D') + pd.Timedelta(hours=8) split_df['restrict_end'] = split_df['period_start'].dt.floor('D') + pd.Timedelta(hours=18) # 只计算工作日的重叠时长 split_df['overlap_start'] = split_df[['period_start', 'restrict_start']].max(axis=1) split_df['overlap_end'] = split_df[['period_end', 'restrict_end']].min(axis=1) split_df['daily_restricted'] = split_df['overlap_end'] - split_df['overlap_start'] split_df['daily_restricted'] = split_df['daily_restricted'].where( (split_df['is_weekday']) & (split_df['overlap_start'] < split_df['overlap_end']), timedelta(0) ) # 按车辆ID汇总总受限时长 total_restricted = split_df.groupby('car_id')['daily_restricted'].sum()
几点实用建议
- 先统一时间格式:确保所有时间列都用
pd.to_datetime()转换,检查时区(如果涉及跨时区),用dt.tz_localize()或dt.tz_convert()统一时区。 - 优先矢量化操作:避免用
apply()处理大数据量,矢量化方法的效率会高几十倍。 - 处理缺失值:关联后如果有缺失的限制规则,要考虑默认逻辑(比如无限制则时长为0)。
内容的提问来源于stack exchange,提问作者Michael McKeever
相关产品推荐
相关产品推荐

