How to display all the months between given two dates? - python

I am trying to generate list of months between two dates.
For Example:
startDate = '2016-1-31'
endDate = '2017-3-26'
It should result as:
datetime.date(2016, 1, 31)
datetime.date(2016, 2, 28)
and so on....
I am trying like this
startDate = '2016-1-28'
endDate = '2017-3-26'
start = date(*map(int, startDate.split('-')))
end = date(*map(int, endDate.split('-')))
week = start
dateData = []
while week <= end:
dateData.append(week)
week = week + datetime.timedelta(weeks=4)
pprint(dateData)
This gives result as:
[datetime.date(2016, 1, 31),
datetime.date(2016, 2, 28),
datetime.date(2016, 3, 27),
datetime.date(2016, 4, 24),
datetime.date(2016, 5, 22),
datetime.date(2016, 6, 19),
datetime.date(2016, 7, 17),
datetime.date(2016, 8, 14),
datetime.date(2016, 9, 11),
datetime.date(2016, 10, 9),
datetime.date(2016, 11, 6),
datetime.date(2016, 12, 4),
datetime.date(2017, 1, 1),
datetime.date(2017, 1, 29),
datetime.date(2017, 2, 26),
datetime.date(2017, 3, 26)]
Here "2016, 12" & "2017, 1" is repeating twice. Can anybody help me solve this problem.

You could use the dateutil extension's relativedelta method like below -
from datetime import datetime
from dateutil.relativedelta import relativedelta
startDate = '2016-1-28'
endDate = '2017-3-26'
cur_date = start = datetime.strptime(startDate, '%Y-%m-%d').date()
end = datetime.strptime(endDate, '%Y-%m-%d').date()
while cur_date < end:
print(cur_date)
cur_date += relativedelta(months=1)
Following is the output
2016-01-28
2016-02-28
2016-03-28
2016-04-28
2016-05-28
2016-06-28
2016-07-28
2016-08-28
2016-09-28
2016-10-28
2016-11-28
2016-12-28
2017-01-28
2017-02-28

You can also use only pandas in one line:
import pandas as pd
pd.date_range('2018-01', '2020-05', freq='M')
The output will be:
DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',
'2018-05-31', '2018-06-30', '2018-07-31', '2018-08-31',
'2018-09-30', '2018-10-31', '2018-11-30', '2018-12-31',
'2019-01-31', '2019-02-28', '2019-03-31', '2019-04-30',
'2019-05-31', '2019-06-30', '2019-07-31', '2019-08-31',
'2019-09-30', '2019-10-31', '2019-11-30', '2019-12-31',
'2020-01-31', '2020-02-29', '2020-03-31', '2020-04-30'],
dtype='datetime64[ns]', freq='M')

I'm not privileged enough to comment yet, but your program is doing exactly as it is told. 4 weeks equals 28 days. The difference between 1st Jan and 29th Jan (2017) is 28 days; therefore you are getting the same month twice.
You might want to redefine what you are trying to solve. If however, you do want to solve just for the months of the years between the two dates, your code will need some expanding.
You need to create a loop to iterate over the years and months.
You will need a condition for the start year and end year to ensure you begin at the start month and finish at the end month.
Here is a working example, it includes the start and end dates in the list as well. I hope it helps:
import datetime
startDate = '2016-1-28'
endDate = '2017-3-26'
start = datetime.date(*map(int, startDate.split('-')))
end = datetime.date(*map(int, endDate.split('-')))
week = start
dateData = []
dateData.append(start)
rangeYear = (end.year - start.year)
for i in range(rangeYear + 1):
if i == 0:
for j in range(1,13-start.month):
date = datetime.date(start.year, start.month+j, 1)
dateData.append(date)
elif (i > 0) & (i < rangeYear):
for j in range(1,12):
date = datetime.date(start.year+i, j, 1)
dateData.append(date)
elif i == rangeYear:
for j in range(1,end.month):
date = datetime.date(start.year+i, j, 1)
dateData.append(date)
dateData.append(end)

Related

Iterating over date range in python and setting the start and end date

I know this question is a repeated one. But what I am trying to do is, I want to iterate through a date range and for each iteration i need to set the fromDate and toDate.
for ex:
If I give the date range as startDate = '2022-10-31'
and endDate = '2022-11-04'
and for each iteration fromDate = '2022-10-31' and toDate = '2022-11-01'
next iteration fromDate = '2022-11-01' and endDate = '2022-11-02' and so on.
I did some research and got to know how to iterate through dateRange.
sample code:
import datetime
start_date = datetime.date(2022, 10, 31)
end_date = datetime.date(2022, 11, 04)
dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]
This just prints the incremented dates in the date Range. Am new to Python language. Any help is appreciated.
Thank you.
You can change the code slightly to,
import datetime
start_date = datetime.date(2022, 10, 31)
end_date = datetime.date(2022, 11, 4)
dates_2011_2013 = [ (start_date + datetime.timedelta(n), start_date + datetime.timedelta(n+1)) for n in range(int ((end_date - start_date).days))]
[(datetime.date(2022, 10, 31), datetime.date(2022, 11, 1)),
(datetime.date(2022, 11, 1), datetime.date(2022, 11, 2)),
(datetime.date(2022, 11, 2), datetime.date(2022, 11, 3)),
(datetime.date(2022, 11, 3), datetime.date(2022, 11, 4))]
First item of the tuple is start date and the second item is end date.
I want to iterate through a date range
another option is using while:
while start_date < end_date:
print(start_date, start_date + datetime.timedelta(1))
start_date += datetime.timedelta(1)
'''
2022-10-31 2022-11-01
2022-11-01 2022-11-02
2022-11-02 2022-11-03
2022-11-03 2022-11-04

Exclude specific dates from date range - Python

I tried to exclude specific dates from a range of date and not getting valid output and below is the code. Could you please help to fix it.
from datetime import timedelta, date
sdate = date(2020, 7, 1)
edate = date(2020, 7, 7)
delta = edate - sdate
toRemoveDate = [date(2020, 7, 6), date(2020, 7, 2)]
for i in range(delta.days + 1):
day = sdate + timedelta(days=i)
print(day)
for j in range(len(toRemoveDate)):
if day != toRemoveDate[j]:
print(day)
Thanks,
Anand
try this,
from datetime import timedelta, date
sdate = date(2020, 7, 1)
edate = date(2020, 7, 7)
delta = edate - sdate
toRemoveDate = [date(2020, 7, 6), date(2020, 7, 2)]
for i in range(delta.days + 1):
day = sdate + timedelta(days=i)
if day not in toRemoveDate: # <-- check if day not in list
print(day)
Try .drop()
from datetime import timedelta, date
import pandas as pd
sdate = date(2020, 7, 1)
edate = date(2020, 7, 7)
range = pd.date_range(start=str(sdate), end=str(edate))
toRemoveDate = [date(2020, 7, 6), date(2020, 7, 2)]
days = range.drop(toRemoveDate)
print(days)

Pandas specifying custom holidays

I'm trying to specify business days in a foreign country, but I can't get the pandas function pd.bdate_range() to recognize holidays. My code is as follows:
import pandas as pd
import datetime
weekmask = "Mon Tue Wed Thu Fri"
holidays = [datetime.datetime(2017, 1, 9), datetime.datetime(2017, 3, 20),
datetime.datetime(2017, 4, 13)]
BdaysCol2017 = pd.bdate_range(start = pd.datetime(2017, 1, 1),
end = pd.datetime(2017, 12, 31),
weekmask = weekmask,
holidays = holidays)
But I get the following error on the holidays parameter:
ValueError: a custom frequency string is required when holidays or weekmask are passed, got frequency B
Why is this? How can I specify custom holidays? Is there a better way to do this?
Thank you
as the docs specify about weekmask and holidays:
only used when custom frequency strings are passed
so you need:
BdaysCol2017 = pd.bdate_range(start = pd.datetime(2017, 1, 1),
end = pd.datetime(2017, 12, 31),
freq='C',
weekmask = weekmask,
holidays=holidays)
I would do that:
import pandas as pd
from datetime import datetime
weekmask = 'Sun Mon Tue Wed Thu'
exclude = [pd.datetime(2017, 3, 20),
pd.datetime(2017, 4, 13),
pd.datetime(2017, 5, 3)]
pd.bdate_range('2017/1/1','2017/12/31',
freq='C',
weekmask = weekmask,
holidays=exclude)

I have an ISO 8601 week number (ex: 201801) corresponding to week 1 of 2018. What is the best way in pyth

I have an ISO 8601 week number, say 201801 - corresponding to week 1 of year 2018.
How do I extract the dates within the week using python?
I would get the sunday of that week, and then give 7 days starting from that. Depending on what you want to happen in week 52, you might want to remove the break
from datetime import datetime, timedelta
def days_from_weekstr(weekstr):
sunday = datetime.strptime(weekstr + "-0", "%Y%W-%w")
year = sunday.year
for i in range(7):
day = sunday + timedelta(1) * i
if day.year != year:
break
yield day.date()
Usage:
>>> list(days_from_weekstr("201801"))
[datetime.date(2018, 1, 7), datetime.date(2018, 1, 8), datetime.date(2018, 1, 9), datetime.date(2018, 1, 10), datetime.date(2018, 1, 11), datetime.date(2018, 1, 12), datetime.date(2018, 1, 13)]

Calculate the end of the previous quarter

I'm looking for an elegant and pythonic way to get the date of the end of the previous quarter.
Something like this:
def previous_quarter(reference_date):
...
>>> previous_quarter(datetime.date(2013, 5, 31))
datetime.date(2013, 3, 31)
>>> previous_quarter(datetime.date(2013, 2, 1))
datetime.date(2012, 12, 31)
>>> previous_quarter(datetime.date(2013, 3, 31))
datetime.date(2012, 12, 31)
>>> previous_quarter(datetime.date(2013, 11, 1))
datetime.date(2013, 9, 30)
Edit: Have I tried anything?
Yes, this seems to work:
def previous_quarter(ref_date):
current_date = ref_date - timedelta(days=1)
while current_date.month % 3:
current_date -= timedelta(days=1)
return current_date
But it seems unnecessarily iterative.
You can do it the "hard way" by just looking at the month you receive:
def previous_quarter(ref):
if ref.month < 4:
return datetime.date(ref.year - 1, 12, 31)
elif ref.month < 7:
return datetime.date(ref.year, 3, 31)
elif ref.month < 10:
return datetime.date(ref.year, 6, 30)
return datetime.date(ref.year, 9, 30)
Using dateutil:
import datetime as DT
import dateutil.rrule as rrule
def previous_quarter(date):
date = DT.datetime(date.year, date.month, date.day)
rr = rrule.rrule(
rrule.DAILY,
bymonth=(3,6,9,12), # the month must be one of these
bymonthday=-1, # the day has to be the last of the month
dtstart = date-DT.timedelta(days=100))
result = rr.before(date, inc=False) # inc=False ensures result < date
return result.date()
print(previous_quarter(DT.date(2013, 5, 31)))
# 2013-03-31
print(previous_quarter(DT.date(2013, 2, 1)))
# 2012-12-31
print(previous_quarter(DT.date(2013, 3, 31)))
# 2012-12-31
print(previous_quarter(DT.date(2013, 11, 1)))
# 2013-09-30
Exploit the data pattern involved and turn the problem into a table-lookup - your classic space-time tradeff:
from datetime import date
PQTBL = (((12,31,-1),)*3 + ((3,31,0),)*3 + ((6,30,0),)*3 + ((9,30,0),)*3)
def previous_quarter(ref):
entry = PQTBL[ref.month-1]
return date(ref.year+entry[2], entry[0], entry[1])
Find the first day and month of the quarter, then use relativedelta to subtract a day.
from dateutil.relativedelta import relativedelta
def previous_quarter(ref):
first_month_of_quarter = ((ref.month - 1) // 3) * 3 + 1
return ref.replace(month=first_month_of_quarter, day=1) - relativedelta(days=1)
It's almost certain you would be happier using pandas (a python library), it has many functions for "business time" data.
http://pandas.pydata.org/pandas-docs/dev/timeseries.html
Reworked Justin Ethier's code for a "next quarter" version. Also added timezone via pytz and strftime formatting. #justin-ethier
import pytz
from datetime import datetime, timedelta
import datetime as dt
def nextQuarter():
ref = datetime.now(pytz.timezone('America/New_York'))
if ref.month < 4:
next = dt.datetime(ref.year, 3, 31, 23, 59, 59).strftime('%m-%d-%Y %H:%M:%S')
elif ref.month < 7:
next = dt.datetime(ref.year, 6, 30, 23, 59, 59).strftime('%m-%d-%Y %H:%M:%S')
elif ref.month < 10:
next = dt.datetime(ref.year, 9, 30, 23, 59, 59).strftime('%m-%d-%Y %H:%M:%S')
else:
next = dt.datetime(ref.year + 1, 12, 31, 23, 59, 59).strftime('%m-%d-%Y %H:%M:%S')
return next
next = nextQuarter()
import datetime
def previous_quarter(ref):
quarter = (ref.month - 1) // 3
prev_quarter = (quarter - 1) % 4
return datetime.datetime(ref.year if quarter>0 else ref.year-1, prev_quarter*3+1, 1)
Solution using only python's datetime library -
import datetime
def get_quarter_end(dt):
'''
given a datetime object, find the end of the quarter
'''
quarter_of_month = int((dt.month-1)/3 + 1)
#======================================================
# find the first day of the next quarter
#======================================================
# if in last quarter then go to the next year
year = dt.year + 1 if quarter_of_month==4 else dt.year
# if in last quarter then month is january (or 1)
month = 1 if quarter_of_month==4 else (quarter_of_month*3) + 1
first_of_next_quarter = datetime.datetime(year = year,
month = month,
day = 1
)
# last day of quarter for dt will be minus 1 day of first of next quarter
quarter_end_dt = first_of_next_quarter - datetime.timedelta(days=1)
return quarter_end_dt
if __name__=='__main__':
dt = datetime.datetime.strptime('2016-07-15', '%Y-%m-%d')
target_dt = get_quarter_end(dt)
and if you want to retreive the last fours quarter you can do this
if ref.month < 4:
list1 = [datetime.date(ref.year - 1, 12, 31),
datetime.date(ref.year - 1, 9, 30),
datetime.date(ref.year - 1, 6, 30),
datetime.date(ref.year - 1, 3, 31)]
list1 = [i.strftime('%Y%m%d') for i in list1]
return list1
elif ref.month < 7:
return [datetime.date(ref.year, 3, 31),
datetime.date(ref.year - 1, 12, 31),
datetime.date(ref.year - 1, 9, 30),
datetime.date(ref.year - 1, 6, 30)]
elif ref.month < 10:
return [datetime.date(ref.year, 6, 30),
datetime.date(ref.year, 3, 31),
datetime.date(ref.year - 1, 12, 31),
datetime.date(ref.year - 1, 9, 30)]
return [datetime.date(ref.year, 9, 30),
datetime.date(ref.year, 6, 30),
datetime.date(ref.year, 3, 30),
datetime.date(ref.year - 1, 12, 31)]

Categories

Resources