如何按天/周/时/月粒度获取两日期间的日期?解决pandas date_range问题
我明白你用pandas的date_range时遇到的周粒度问题——默认的freq='W'确实是返回每周的起始(通常是周日或周一,取决于你的系统设置),但我们可以通过调整参数或者简单的后期处理来拿到每周结束日期,同时我也把天、小时、月这些粒度的实现一并整理给你,方便直接复用。
1. 按天粒度拆分
这是最直接的场景,用freq='D'就能返回起始到结束之间的每一天(包含两端日期):
import pandas as pd start_date = '2024-01-01' end_date = '2024-01-10' daily_dates = pd.date_range(start=start_date, end=end_date, freq='D') print(daily_dates)
输出会是从2024-01-01到2024-01-10的所有日期。
2. 按小时粒度拆分
用freq='H'可以生成每小时的时间戳,注意如果你的结束日期是不含时间的字符串(如'2024-01-10'),默认会被解析为当天00:00,所以date_range的小时粒度会到前一天的23:00;如果需要包含结束当天的小时,可以把结束日期改为'2024-01-10 23:59':
hourly_dates = pd.date_range(start=start_date, end=end_date, freq='H') print(hourly_dates)
3. 按月粒度拆分
根据需求选择月初或月末的频率参数:
freq='MS':返回每个月的第一天(月初)freq='M':返回每个月的最后一天(月末)
示例代码:
# 按月初拆分 monthly_start_dates = pd.date_range(start=start_date, end=end_date, freq='MS') # 按月末拆分 monthly_end_dates = pd.date_range(start=start_date, end=end_date, freq='M') print("月初日期:", monthly_start_dates) print("月末日期:", monthly_end_dates)
比如如果你的日期跨了2023年12月到2024年2月,MS会返回2024-01-01、2024-02-01,M会返回2023-12-31、2024-01-31。
4. 按周粒度拆分(重点解决你的问题)
默认的freq='W'(等价于W-SUN)返回的是每周日的日期(作为周起始),如果你想要每周的结束日期,有两种实用方法:
方法一:直接指定周结束的频率字符串
pandas支持用W-XXX的格式指定每周的结束日,比如:
W-SAT:每周六作为周结束W-FRI:每周五作为周结束W-MON:每周一作为周结束(适合周一为一周最后一天的场景)
示例代码:
# 以每周六作为周结束日期 weekly_end_dates = pd.date_range(start=start_date, end=end_date, freq='W-SAT') print(weekly_end_dates)
比如start_date='2024-01-01'(周一)、end_date='2024-01-20'(周六),这段代码会返回2024-01-06、2024-01-13、2024-01-20,刚好是每周的结束日。
方法二:对默认周起始日期做偏移
如果已经生成了周起始日期,想要转成结束日期,直接给每个日期加6天即可,记得过滤掉超过结束日期的结果:
# 先获取默认的周起始日期(每周日) weekly_start_dates = pd.date_range(start=start_date, end=end_date, freq='W') # 加6天得到周结束日期(每周六) weekly_end_dates = weekly_start_dates + pd.Timedelta(days=6) # 过滤掉超过end_date的日期 weekly_end_dates = weekly_end_dates[weekly_end_dates <= end_date] print(weekly_end_dates)
如果需要同时拿到每周的起始和结束日期对,可以把它们打包成元组:
weekly_pairs = list(zip(weekly_start_dates, weekly_end_dates)) print("每周起始-结束对:", weekly_pairs)
完整整合示例
这里把所有粒度的逻辑封装成一个函数,方便你直接调用:
import pandas as pd def get_date_ranges(start_date, end_date): date_ranges = { 'daily': pd.date_range(start=start_date, end=end_date, freq='D'), 'hourly': pd.date_range(start=start_date, end=end_date, freq='H'), 'monthly_start': pd.date_range(start=start_date, end=end_date, freq='MS'), 'monthly_end': pd.date_range(start=start_date, end=end_date, freq='M'), 'weekly_end_sat': pd.date_range(start=start_date, end=end_date, freq='W-SAT') } # 补充周起始转结束的逻辑 weekly_start = pd.date_range(start=start_date, end=end_date, freq='W') weekly_end_from_start = weekly_start + pd.Timedelta(days=6) weekly_end_from_start = weekly_end_from_start[weekly_end_from_start <= end_date] date_ranges['weekly_end_from_start'] = weekly_end_from_start return date_ranges # 测试调用 start = '2024-01-01' end = '2024-01-20' all_ranges = get_date_ranges(start, end) for granularity, dates in all_ranges.items(): print(f"\n{granularity} 结果:") print(dates)
内容的提问来源于stack exchange,提问作者Anish

