在 Python 中创建日期范围
- 2025-01-03 14:22:00
- admin 原创
- 235
问题描述:
我想创建一个日期列表,从今天开始,回溯任意天数,例如,在我的示例中为 100 天。有没有比这更好的方法?
import datetime
a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
dateList.append(a - datetime.timedelta(days = x))
print dateList
解决方案 1:
稍微好一点...
base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(numdays)]
解决方案 2:
Pandas
非常适合一般的时间序列,并且直接支持日期范围。
例如pd.date_range()
:
import pandas as pd
from datetime import datetime
datelist = pd.date_range(datetime.today(), periods=100).tolist()
它还提供许多选项,让生活更轻松。例如,如果您只想查看工作日,只需换成 即可bdate_range
。
参见日期范围文档
此外,它完全支持 pytz 时区,并可以平滑跨越春季/秋季夏令时转变。
OP 编辑:
如果您需要实际的 Python 日期时间,而不是 Pandas 时间戳:
import pandas as pd
from datetime import datetime
pd.date_range(end = datetime.today(), periods = 100).to_pydatetime().tolist()
#OR
pd.date_range(start="2018-09-09",end="2020-02-02")
这使用“end”参数来匹配原始问题,但如果您想要降序日期:
pd.date_range(datetime.today(), periods=100).to_pydatetime().tolist()
解决方案 3:
获取指定开始日期和结束日期之间的日期范围(针对时间和空间复杂度进行了优化):
import datetime
start = datetime.datetime.strptime("21-06-2014", "%d-%m-%Y")
end = datetime.datetime.strptime("07-07-2014", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
for date in date_generated:
print date.strftime("%d-%m-%Y")
解决方案 4:
您可以编写一个生成器函数,返回从今天开始的日期对象:
import datetime
def date_generator():
from_date = datetime.datetime.today()
while True:
yield from_date
from_date = from_date - datetime.timedelta(days=1)
此生成器返回从今天开始并逐日向前追溯的日期。以下是如何获取前 3 个日期:
>>> import itertools
>>> dates = itertools.islice(date_generator(), 3)
>>> list(dates)
[datetime.datetime(2009, 6, 14, 19, 12, 21, 703890), datetime.datetime(2009, 6, 13, 19, 12, 21, 703890), datetime.datetime(2009, 6, 12, 19, 12, 21, 703890)]
与循环或列表推导相比,这种方法的优势在于您可以根据需要多次返回。
编辑
使用生成器表达式而不是函数的更紧凑版本:
date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count())
用法:
>>> dates = itertools.islice(date_generator, 3)
>>> list(dates)
[datetime.datetime(2009, 6, 15, 1, 32, 37, 286765), datetime.datetime(2009, 6, 14, 1, 32, 37, 286836), datetime.datetime(2009, 6, 13, 1, 32, 37, 286859)]
解决方案 5:
如果使用外部依赖项可以,请检查https://pypi.org/project/python-dateutil及其rrule
模块: https: //dateutil.readthedocs.io/en/stable/rrule.html。
from dateutil import rrule
from datetime import datetime
list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))
解决方案 6:
您还可以使用日期序数来使其更简单:
def date_range(start_date, end_date):
for ordinal in range(start_date.toordinal(), end_date.toordinal()):
yield datetime.date.fromordinal(ordinal)
或者按照评论中的建议,您可以创建如下列表:
date_range = [
datetime.date.fromordinal(ordinal)
for ordinal in range(
start_date.toordinal(),
end_date.toordinal(),
)
]
解决方案 7:
从这个问题的标题来看,我期望找到类似 的内容range()
,这样我就可以指定两个日期并创建一个包含这两个日期之间所有日期的列表。这样,如果事先不知道这两个日期之间的天数,就不需要计算这两个日期之间的天数。
因此,尽管可能有点偏离主题,但下面这句话还是起到了作用:
import datetime
start_date = datetime.date(2011, 1, 1)
end_date = datetime.date(2014, 1, 1)
dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]
所有功劳都归功于这个答案!
解决方案 8:
这是基于 S.Lott 的答案的略微不同的答案,它给出了两个日期start
和之间的日期列表end
。在下面的例子中,从 2017 年初到今天。
start = datetime.datetime(2017,1,1)
end = datetime.datetime.today()
daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
解决方案 9:
如果有两个日期并且您需要范围,请尝试
from dateutil import rrule, parser
date1 = '1995-01-01'
date2 = '1995-02-28'
datesx = list(rrule.rrule(rrule.DAILY, dtstart=parser.parse(date1), until=parser.parse(date2)))
解决方案 10:
根据我为自己写下的答案:
import datetime;
print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)]
输出:
['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07']
区别在于我得到的是“ date
”对象,而不是“ datetime.datetime
”对象。
解决方案 11:
我知道回答得有点晚了,但是我遇到了同样的问题并且认为 Python 的内部范围函数在这方面有点欠缺,所以我在我的实用程序模块中覆盖了它。
from __builtin__ import range as _range
from datetime import datetime, timedelta
def range(*args):
if len(args) != 3:
return _range(*args)
start, stop, step = args
if start < stop:
cmp = lambda a, b: a < b
inc = lambda a: a + step
else:
cmp = lambda a, b: a > b
inc = lambda a: a - step
output = [start]
while cmp(start, stop):
start = inc(start)
output.append(start)
return output
print range(datetime(2011, 5, 1), datetime(2011, 10, 1), timedelta(days=30))
解决方案 12:
这是我根据自己的代码创建的要点,这可能会有所帮助。(我知道这个问题太老了,但其他人可以使用它)
https://gist.github.com/2287345
(下同)
import datetime
from time import mktime
def convert_date_to_datetime(date_object):
date_tuple = date_object.timetuple()
date_timestamp = mktime(date_tuple)
return datetime.datetime.fromtimestamp(date_timestamp)
def date_range(how_many=7):
for x in range(0, how_many):
some_date = datetime.datetime.today() - datetime.timedelta(days=x)
some_datetime = convert_date_to_datetime(some_date.date())
yield some_datetime
def pick_two_dates(how_many=7):
a = b = convert_date_to_datetime(datetime.datetime.now().date())
for each_date in date_range(how_many):
b = a
a = each_date
if a == b:
continue
yield b, a
解决方案 13:
允许根据参数化窗口大小(天、分、时、秒)创建日期范围的通用方法:
from datetime import datetime, timedelta
def create_date_ranges(start, end, **interval):
start_ = start
while start_ < end:
end_ = start_ + timedelta(**interval)
yield (start_, min(end_, end))
start_ = end_
测试:
def main():
tests = [
('2021-11-15:00:00:00', '2021-11-17:13:00:00', {'days': 1}),
('2021-11-15:00:00:00', '2021-11-16:13:00:00', {'hours': 12}),
('2021-11-15:00:00:00', '2021-11-15:01:45:00', {'minutes': 30}),
('2021-11-15:00:00:00', '2021-11-15:00:01:12', {'seconds': 30})
]
for t in tests:
print("
Interval: %s, range(%s to %s)" % (t[2], t[0], t[1]))
start = datetime.strptime(t[0], '%Y-%m-%d:%H:%M:%S')
end = datetime.strptime(t[1], '%Y-%m-%d:%H:%M:%S')
ranges = list(create_date_ranges(start, end, **t[2]))
x = list(map(
lambda x: (x[0].strftime('%Y-%m-%d:%H:%M:%S'), x[1].strftime('%Y-%m-%d:%H:%M:%S')),
ranges
))
print(x)
main()
测试输出:
Interval: {'days': 1}, range(2021-11-15:00:00:00 to 2021-11-17:13:00:00)
[('2021-11-15:00:00:00', '2021-11-16:00:00:00'), ('2021-11-16:00:00:00', '2021-11-17:00:00:00'), ('2021-11-17:00:00:00', '2021-11-17:13:00:00')]
Interval: {'hours': 12}, range(2021-11-15:00:00:00 to 2021-11-16:13:00:00)
[('2021-11-15:00:00:00', '2021-11-15:12:00:00'), ('2021-11-15:12:00:00', '2021-11-16:00:00:00'), ('2021-11-16:00:00:00', '2021-11-16:12:00:00'), ('2021-11-16:12:00:00', '2021-11-16:13:00:00')]
Interval: {'minutes': 30}, range(2021-11-15:00:00:00 to 2021-11-15:01:45:00)
[('2021-11-15:00:00:00', '2021-11-15:00:30:00'), ('2021-11-15:00:30:00', '2021-11-15:01:00:00'), ('2021-11-15:01:00:00', '2021-11-15:01:30:00'), ('2021-11-15:01:30:00', '2021-11-15:01:45:00')]
Interval: {'seconds': 30}, range(2021-11-15:00:00:00 to 2021-11-15:00:01:12)
[('2021-11-15:00:00:00', '2021-11-15:00:00:30'), ('2021-11-15:00:00:30', '2021-11-15:00:01:00'), ('2021-11-15:00:01:00', '2021-11-15:00:01:12')]
解决方案 14:
这是用于获取工作日列表的 bash 脚本的一行代码,这是 python 3。可以轻松修改,末尾的 int 是您想要的过去天数。
python -c "import sys,datetime; print('
'.join([(datetime.datetime.today() - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int(sys.argv[1])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 10
这是一个提供开始(或者结束)日期的变体
python -c "import sys,datetime; print('
'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d \") for x in range(0,int(sys.argv[2])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/30 10
这是一个任意开始和结束日期的变体。这并不是说它效率不高,但适合在 bash 脚本中加入 for 循环:
python -c "import sys,datetime; print('
'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") + datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int((datetime.datetime.strptime(sys.argv[2], \"%Y/%m/%d\") - datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\")).days)) if (datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\") + datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/15 2015/12/30
解决方案 15:
我知道这个问题已经得到解答了,但是为了历史目的,我会把我的答案写下来,因为我认为它很简单。
import numpy as np
import datetime as dt
listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))]
当然,它不会像代码高尔夫那样赢得任何比赛,但我认为它很优雅。
解决方案 16:
from datetime import datetime , timedelta, timezone
start_date = '2022_01_25'
end_date = '2022_01_30'
start = datetime.strptime(start_date, "%Y_%m_%d")
print(type(start))
end = datetime.strptime(end_date, "%Y_%m_%d")
##pDate = str(pDate).replace('-', '_')
number_of_days = (end - start).days
print("number_of_days: ", number_of_days)
##
date_list = []
for day in range(number_of_days):
a_date = (start + timedelta(days = day)).astimezone(timezone.utc)
a_date = a_date.strftime('%Y-%m-%d')
date_list.append(a_date)
print(date_list)
解决方案 17:
Matplotlib相关
from matplotlib.dates import drange
import datetime
base = datetime.date.today()
end = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
l = drange(base, end, delta)
解决方案 18:
另一个正向或反向计数的例子,从 Sandeep 的回答开始。
from datetime import date, datetime, timedelta
from typing import Sequence
def range_of_dates(start_of_range: date, end_of_range: date) -> Sequence[date]:
if start_of_range <= end_of_range:
return [
start_of_range + timedelta(days=x)
for x in range(0, (end_of_range - start_of_range).days + 1)
]
return [
start_of_range - timedelta(days=x)
for x in range(0, (start_of_range - end_of_range).days + 1)
]
start_of_range = datetime.today().date()
end_of_range = start_of_range + timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)
给出
[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)]
和
start_of_range = datetime.today().date()
end_of_range = start_of_range - timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)
给出
[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)]
请注意,开始日期包含在返回值中,因此如果您想要总共四个日期,请使用timedelta(days=3)
解决方案 19:
datetime
带有和 的每月日期范围生成器dateutil
。简单易懂:
import datetime as dt
from dateutil.relativedelta import relativedelta
def month_range(start_date, n_months):
for m in range(n_months):
yield start_date + relativedelta(months=+m)
解决方案 20:
我专门为此目的pypi
编写并维护了一个包。dateroll
它使用我们所说的“日期计划字符串”。
dateroll
可以通过以下方式实现:
pip install dateroll
>>> from dateroll import ddh # date duration helper
>>> ddh("t-100d,t,1d").list
[Date(2024,1,6), Date(2024,1,7), Date(2024,1,8),...]
该函数ddh
采用一个包含 3 个部分的特殊字符串:开始日期、停止日期和增量日期。
该类dateroll.Date
继承自 datetime.Date,因此您可以正常使用它们,或者它们具有属性.date
并.datetime
可以转换为 python 标准 datetime.date 和 datetime.datetime
文档中更复杂的示例:
https://dateroll.disent.com/docs/Quickstart
解决方案 21:
import datetime
def date_generator():
cur = base = datetime.date.today()
end = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
while(end>base):
base = base+delta
print base
date_generator()
解决方案 22:
from datetime import datetime, timedelta
from dateutil import parser
def getDateRange(begin, end):
""" """
beginDate = parser.parse(begin)
endDate = parser.parse(end)
delta = endDate-beginDate
numdays = delta.days + 1
dayList = [datetime.strftime(beginDate + timedelta(days=x), '%Y%m%d') for x in range(0, numdays)]
return dayList
解决方案 23:
根据以上答案,我为日期生成器创建了这个示例
import datetime
date = datetime.datetime.now()
time = date.time()
def date_generator(date, delta):
counter =0
date = date - datetime.timedelta(days=delta)
while counter <= delta:
yield date
date = date + datetime.timedelta(days=1)
counter +=1
for date in date_generator(date, 30):
if date.date() != datetime.datetime.now().date():
start_date = datetime.datetime.combine(date, datetime.time())
end_date = datetime.datetime.combine(date, datetime.time.max)
else:
start_date = datetime.datetime.combine(date, datetime.time())
end_date = datetime.datetime.combine(date, time)
print('start_date---->',start_date,'end_date---->',end_date)
解决方案 24:
我想用一个简单的(但不完整的)日期范围实现来表达我的看法:
from datetime import date, timedelta, datetime
class DateRange:
def __init__(self, start, end, step=timedelta(1)):
self.start = start
self.end = end
self.step = step
def __iter__(self):
start = self.start
step = self.step
end = self.end
n = int((end - start) / step)
d = start
for _ in range(n):
yield d
d += step
def __contains__(self, value):
return (
(self.start <= value < self.end) and
((value - self.start) % self.step == timedelta(0))
)