I want to create a list of dates, starting with today, and going back an arbitrary number of days, say, in my example 100 days. Is there a better way to do it than this?
import datetime a = datetime.datetime.today() numdays = 100 dateList = [] for x in range (0, numdays): dateList.append(a - datetime.timedelta(days = x)) print dateList 023 Answers
Marginally better...
base = datetime.datetime.today() date_list = [base - datetime.timedelta(days=x) for x in range(numdays)] 3Pandas is great for time series in general, and has direct support for date ranges.
For example pd.date_range():
import pandas as pd from datetime import datetime datelist = pd.date_range(datetime.today(), periods=100).tolist() It also has lots of options to make life easier. For example if you only wanted weekdays, you would just swap in bdate_range.
In addition it fully supports pytz timezones and can smoothly span spring/autumn DST shifts.
EDIT by OP:
If you need actual python datetimes, as opposed to Pandas timestamps:
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") This uses the "end" parameter to match the original question, but if you want descending dates:
pd.date_range(datetime.today(), periods=100).to_pydatetime().tolist() 0Get range of dates between specified start and end date (Optimized for time & space complexity):
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") 5You can write a generator function that returns date objects starting from today:
import datetime def date_generator(): from_date = datetime.datetime.today() while True: yield from_date from_date = from_date - datetime.timedelta(days=1) This generator returns dates starting from today and going backwards one day at a time. Here is how to take the first 3 dates:
>>> 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)] The advantage of this approach over a loop or list comprehension is that you can go back as many times as you want.
Edit
A more compact version using a generator expression instead of a function:
date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count()) Usage:
>>> 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)] 1yeah, reinvent the wheel.... just search the forum and you'll get something like this:
from dateutil import rrule from datetime import datetime list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now())) 8You can also use the day ordinal to make it simpler:
def date_range(start_date, end_date): for ordinal in range(start_date.toordinal(), end_date.toordinal()): yield datetime.date.fromordinal(ordinal) Or as suggested in the comments you can create a list like this:
date_range = [ datetime.date.fromordinal(ordinal) for ordinal in range( start_date.toordinal(), end_date.toordinal(), ) ] 0From the title of this question I was expecting to find something like range(), that would let me specify two dates and create a list with all the dates in between. That way one does not need to calculate the number of days between those two dates, if one does not know it beforehand.
So with the risk of being slightly off-topic, this one-liner does the job:
import datetime start_date = datetime.date(2011, 01, 01) end_date = datetime.date(2014, 01, 01) dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))] All credits to this answer!
2Here's a slightly different answer building off of S.Lott's answer that gives a list of dates between two dates start and end. In the example below, from the start of 2017 to today.
start = datetime.datetime(2017,1,1) end = datetime.datetime.today() daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)] If there are two dates and you need the range try
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))) A bit of a late answer I know, but I just had the same problem and decided that Python's internal range function was a bit lacking in this respect so I've overridden it in a util module of mine.
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)) 2Based on answers I wrote for myself this:
import datetime; print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)] Output:
['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07'] The difference is that I get the 'date' object, not the 'datetime.datetime' one.
Here is gist I created, from my own code, this might help. (I know the question is too old, but others can use it)
(same thing below)
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 Here's a one liner for bash scripts to get a list of weekdays, this is python 3. Easily modified for whatever, the int at the end is the number of days in the past you want.
python -c "import sys,datetime; print('\n'.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 Here is a variant to provide a start (or rather, end) date
python -c "import sys,datetime; print('\n'.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 Here is a variant for arbitrary start and end dates. not that this isn't terribly efficient, but is good for putting in a for loop in a bash script:
python -c "import sys,datetime; print('\n'.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 1Matplotlib related
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) 0I know this has been answered, but I'll put down my answer for historical purposes, and since I think it is straight forward.
import numpy as np import datetime as dt listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))] Sure it won't win anything like code-golf, but I think it is elegant.
2A generic method that allows to create date ranges on parameterised window size(day, minute, hour, seconds):
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_ Tests:
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("\nInterval: %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() Test output:
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')] Another example that counts forwards or backwards, starting from Sandeep's answer.
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) gives
[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)] and
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) gives
[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)] Note that the start date is included in the return, so if you want four total dates, use timedelta(days=3)
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) 1A monthly date range generator with datetime and dateutil. Simple and easy to understand:
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) 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() 1from 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 From above answers i created this example for date generator
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) I thought I'd throw in my two cents with a simple (and not complete) implementation of a date range:
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)) )