date_range not accepting the variable I want to use? - python

When I input a value like '2015-08', my date_range works as intended. If I use the startdate variable, then it no longer works? I cannot figure out why this would be.
The error I get is "Cannot convert input to Timestamp"

Not for points. I'm a bit confused, isn't what you're doing just basically the following?
Code:
from datetime import datetime, timedelta
now = datetime.now()
print now.strftime("%Y-%m")
month_ago = now.replace(day=1) - timedelta(days = 1)
print month_ago.strftime("%Y-%m")
months_ago = month_ago.replace(day=1) - timedelta(days = 1)
print months_ago.strftime("%Y-%m")
Output:
2015-11
2015-10
2015-09
The above might not be the perfect answer, but you can substitute any datetime for now and it will give you basically the current and last two months. Adjust as needed, of course.
EDIT:
You can even take it a step further and just create a function that allows you to specify the numbers of months back or use a custom date.
from datetime import datetime, timedelta
def last_n_months(num_of_months, start_date=datetime.now(), include_curr=True):
f = "%Y-%m"
curr = start_date
if include_curr:
yield curr.strftime(f)
for num in range(num_of_months):
curr = curr.replace(day=1) - timedelta(days=1)
yield curr.strftime(f)
# This month and last 12 months.
print [m for m in last_n_months(12)]
# ['2015-11', '2015-10', '2015-09', '2015-08', '2015-07', '2015-06', '2015-05', '2015-04', '2015-03', '2015-02', '2015-01', '2014-12', '2014-11']
# Last 12 months only.
print [m for m in last_n_months(12, include_curr=False)]
# ['2015-10', '2015-09', '2015-08', '2015-07', '2015-06', '2015-05', '2015-04', '2015-03', '2015-02', '2015-01', '2014-12', '2014-11']
# Last 12 months from custom date, exclude custom date.
d = datetime(2012, 6, 1)
print [m for m in last_n_months(12, d, False)]
# ['2012-05', '2012-04', '2012-03', '2012-02', '2012-01', '2011-12', '2011-11', '2011-10', '2011-09', '2011-08', '2011-07', '2011-06']

Related

How to return all weekdays in a range of dates, sorted in ascending order

from datetime import datetime
from datetime import timedelta
#this is the start day
day = input()
#this is number of days input
num=int(input())
#this is the start date of the shipment
temp = input()
#this is the date format the string into a day using the strptime object
start_day = datetime.strptime(day, '%A')
#this line will format the string input into a date
format1 = datetime.strptime(temp, '%d-%m-%Y')
#this line will add number input onto the date
arrival = format1 + timedelta(days=num)
for i in range(num):
a = arrival - timedelta(days=i)
if a.weekday() <5 :
print(a.strftime('%d-%m-%Y'))
The above code gives me three weekday dates but I am expecting four.
This is my output:
05-03-2019
04-03-2019
01-03-2019
but I need this:
01-03-2019
04-03-2019
05-03-2019
06-03-2019
All dates starting with the oldest first e.g. ascending order.
Here is the assignment I have:
Radan Logistics is a mid sized Shipping Company known for its Customer oriented delivery services. The Company Management intended to place an information kiosk in their Head Office which would help their Customers to fetch all the desired information with regards to their shipment. One such vital information that Customers would prefer to know is the details of the working days of the Company which would help them track their shipments.
Help the Management write a program for the kiosk, that when given the start day, number of days 'n' and the start date, will output the dates of the 'n' business days (excluding Saturday and Sunday).
Input Format:
The first line of input is a String, the start day.
The second line of the input is the number of days.
Third line is a string that correponds to the start date of the shipment.
Output Format:
Output is list of dates of n working days separated by new line.
Sample Input 1:
Monday
7
03-12-2007
Sample Output 1:
04-12-2007
05-12-2007
06-12-2007
07-12-2007
10-12-2007
11-12-2007
Sample Input 2:
Thursday
10
25-02-2012
Sample Output 2:
26-02-2012
29-02-2012
01-03-2012
02-03-2012
03-03-2012
04-03-2012
07-03-2012
08-03-2012
09-03-2012
The issue seems to be that you're looping through an ascending range of numbers, but that number is subtracted to get the result. For example 10-1=9, 10-2=8, 10-3=7, etc. You can instead loop through range(num) in descending order. Also, range() by default goes from index zero up to and not including num. To have num included, you may want range(num + 1)
for i in reversed(range(num + 1)):
a = arrival - timedelta(days=i)
if a.weekday() <5 :
print(a.strftime('%d-%m-%Y'))
To show 5 days you have to make a.weekday() <=5 not num+1
and add reversed to range to reverse the showing of data
for i in reversed(range(num)):
a = arrival - timedelta(days=i)
if a.weekday() <=5 :
print(a.strftime('%d-%m-%Y'))
import datetime
start = '01-03-2019'
num_days = 7
date_list = [datetime.datetime.strptime(start, "%d-%m-%Y") + datetime.timedelta(days=x) for x in range(num_days)]
list_of_weekdays = [day.strftime('%d-%m-%Y') for day in date_list if day.isoweekday() in range(1, 6)]
[print(day) for day in list_of_weekdays[::-1]]
Print range of dates in descending order, i.e. from newest to oldest.
from datetime import datetime, timedelta
def range_of_dates_from_interval(start, end, date_format='%d-%m-%Y'):
start_date = datetime.strptime(start, date_format).date()
end_date = datetime.strptime(end, date_format).date()
d = timedelta(days=1)
date = end_date
while date != start_date:
print(date.strftime(date_format))
date -= d
print(date.strftime(date_format))
def range_of_dates_with_step(start, amount_days, date_format='%d-%m-%Y'):
start_date = datetime.strptime(start, date_format).date()
d = timedelta(days=1)
for i in range(amount_days-1, -1, -1):
print((start_date + d*i).strftime(date_format))
date_format = '%d-%m-%Y'
# test first function
start = '29-03-2019'
end = '02-04-2019'
range_of_dates_from_interval(start, end, date_format=date_format)
#02-04-2019
#01-04-2019
#31-03-2019
#30-03-2019
#29-03-2019
# test second function
start = '29-03-2019'
amount_days = 5
range_of_dates_with_step(start, amount_days, date_format=date_format)
#02-04-2019
#01-04-2019
#31-03-2019
#30-03-2019
#29-03-2019
EDIT: answer of the assignment
import datetime
# not needed but useful for display information
def weekdays_iso(day_num_format=True) -> dict:
out = {}
d0 = datetime.date.fromordinal(1) # day zero
d, a_day = d0, datetime.timedelta(days=1)
for i in range(7):
if day_num_format:
out[d.strftime("%A")] = i+1
else:
out[i+1] = d.strftime("%A")
d += a_day
return out
# main function
def get_business_days(num_b_days, start, date_format='%d-%m-%Y') -> list:
b_days = []
start_date = datetime.datetime.strptime(start, date_format).date()
b_day, a_day = start_date, datetime.timedelta(days=1)
while num_b_days > 1:
b_day += a_day
if b_day.isoweekday() not in {6, 7}:
b_days.append(b_day)
num_b_days -= 1
return b_days
WEEKDAYS_ISO = weekdays_iso(day_num_format=False)
date_format = '%d-%m-%Y'
Test 1
start = "03-12-2007"
n_b_days = 7
# result
b_days = get_business_days(n_b_days, start, date_format=date_format)
# check
for d in b_days:
print(d.strftime(date_format), WEEKDAYS_ISO[d.isoweekday()])
Output 1:
04-12-2007 Tuesday
05-12-2007 Wednesday
06-12-2007 Thursday
07-12-2007 Friday
10-12-2007 Monday
11-12-2007 Tuesday
Test 2
start = "25-02-2012"
n_b_days = 10
# result
b_days = get_business_days(n_b_days, start, date_format=date_format)
# check
for d in b_days:
print(d.strftime(date_format), WEEKDAYS_ISO[d.isoweekday()])
Output 2:
27-02-2012 Monday
28-02-2012 Tuesday
29-02-2012 Wednesday
01-03-2012 Thursday
02-03-2012 Friday
05-03-2012 Monday
06-03-2012 Tuesday
07-03-2012 Wednesday
08-03-2012 Thursday

Printing working dates between two dates but excluding every weekends

I am trying to print the working days between two dates, but excluding the latter one and the weekends, holding in there. I've tried the following code:
from datetime import timedelta, date, datetime
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
if date1.isoweekday == excluded:
continue
else:
yield date1 + timedelta(n)
start_dt = datetime.now()
end_dt = datetime(2022, 4, 28)
for dt in print_working_dates(start_dt, end_dt):
print(dt.strftime("%Y-%m-%d"))
which prints every day before the last one, but it holds all weekends. Could anyone please anyone could give a piece of advice to define better this function? To my mind, the excluded object should be better detailed, but I cannot know how.
Firstly, you can check if a value is in an iterable (such as a tuple or list) using the in keyword. isoweekday is a function, so you need to call it with isoweekday(). Finally, you need to work out the new date, then check it's weekday, otherwise it just checks if the start date is a weekend for every date.
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
new = date1 + timedelta(n)
if new.isoweekday() not in excluded:
yield new
I've negated the if statement with not to make it a bit more compact.
First off, you are not checking the correct time to be a weekday or not you have to check if (date1 + timedelta(n)) is a weekday, not date1
And secondly you have to you have to check if isoweekday's return value is in the excluded
Here's my solution to your code:
from datetime import timedelta, datetime
def print_working_dates(date1, date2):
excluded = (6,7)
for n in range(int((date2 - date1).days)+1):
if (date1 + timedelta(n)).isoweekday() in excluded:
continue
else:
yield date1 + timedelta(n)
start_dt = datetime.now()
end_dt = datetime(2022, 4, 28)
for dt in print_working_dates(start_dt, end_dt):
print(dt.strftime("%Y-%m-%d"))

How to correctly generate list of UTC timestamps, by hour, between two datetimes Python?

I'm new to Python. After a couple days researching and trying things out, I've landed on a decent solution for creating a list of timestamps, for each hour, between two dates.
Example:
import datetime
from datetime import datetime, timedelta
timestamp_format = '%Y-%m-%dT%H:%M:%S%z'
earliest_ts_str = '2020-10-01T15:00:00Z'
earliest_ts_obj = datetime.strptime(earliest_ts_str, timestamp_format)
latest_ts_str = '2020-10-02T00:00:00Z'
latest_ts_obj = datetime.strptime(latest_ts_str, timestamp_format)
num_days = latest_ts_obj - earliest_ts_obj
num_hours = int(round(num_days.total_seconds() / 3600,0))
ts_raw = []
for ts in range(num_hours):
ts_raw.append(latest_ts_obj - timedelta(hours = ts + 1))
dates_formatted = [d.strftime('%Y-%m-%dT%H:%M:%SZ') for d in ts_raw]
# Need timestamps in ascending order
dates_formatted.reverse()
dates_formatted
Which results in:
['2020-10-01T00:00:00Z',
'2020-10-01T01:00:00Z',
'2020-10-01T02:00:00Z',
'2020-10-01T03:00:00Z',
'2020-10-01T04:00:00Z',
'2020-10-01T05:00:00Z',
'2020-10-01T06:00:00Z',
'2020-10-01T07:00:00Z',
'2020-10-01T08:00:00Z',
'2020-10-01T09:00:00Z',
'2020-10-01T10:00:00Z',
'2020-10-01T11:00:00Z',
'2020-10-01T12:00:00Z',
'2020-10-01T13:00:00Z',
'2020-10-01T14:00:00Z',
'2020-10-01T15:00:00Z',
'2020-10-01T16:00:00Z',
'2020-10-01T17:00:00Z',
'2020-10-01T18:00:00Z',
'2020-10-01T19:00:00Z',
'2020-10-01T20:00:00Z',
'2020-10-01T21:00:00Z',
'2020-10-01T22:00:00Z',
'2020-10-01T23:00:00Z']
Problem:
If I change earliest_ts_str to include minutes, say earliest_ts_str = '2020-10-01T19:45:00Z', the resulting list does not increment the minute intervals accordingly.
Results:
['2020-10-01T20:00:00Z',
'2020-10-01T21:00:00Z',
'2020-10-01T22:00:00Z',
'2020-10-01T23:00:00Z']
I need it to be:
['2020-10-01T20:45:00Z',
'2020-10-01T21:45:00Z',
'2020-10-01T22:45:00Z',
'2020-10-01T23:45:00Z']
Feels like the problem is in the num_days and num_hours calculation, but I can't see how to fix it.
Ideas?
if you don't mind to use a 3rd party package, have a look at pandas.date_range:
import pandas as pd
earliest, latest = '2020-10-01T15:45:00Z', '2020-10-02T00:00:00Z'
dti = pd.date_range(earliest, latest, freq='H') # just specify hourly frequency...
l = dti.strftime('%Y-%m-%dT%H:%M:%SZ').to_list()
print(l)
# ['2020-10-01T15:45:00Z', '2020-10-01T16:45:00Z', '2020-10-01T17:45:00Z', '2020-10-01T18:45:00Z', '2020-10-01T19:45:00Z', '2020-10-01T20:45:00Z', '2020-10-01T21:45:00Z', '2020-10-01T22:45:00Z', '2020-10-01T23:45:00Z']
import datetime
from datetime import datetime, timedelta
timestamp_format = '%Y-%m-%dT%H:%M:%S%z'
earliest_ts_str = '2020-10-01T00:00:00Z'
ts_obj = datetime.strptime(earliest_ts_str, timestamp_format)
latest_ts_str = '2020-10-02T00:00:00Z'
latest_ts_obj = datetime.strptime(latest_ts_str, timestamp_format)
ts_raw = []
while ts_obj <= latest_ts_obj:
ts_raw.append(ts_obj)
ts_obj += timedelta(hours=1)
dates_formatted = [d.strftime('%Y-%m-%dT%H:%M:%SZ') for d in ts_raw]
print(dates_formatted)
EDIT:
Here is example with Maya
import maya
earliest_ts_str = '2020-10-01T00:00:00Z'
latest_ts_str = '2020-10-02T00:00:00Z'
start = maya.MayaDT.from_iso8601(earliest_ts_str)
end = maya.MayaDT.from_iso8601(latest_ts_str)
# end is not included, so we add 1 second
my_range = maya.intervals(start=start, end=end.add(seconds=1), interval=60*60)
dates_formatted = [d.iso8601() for d in my_range]
print(dates_formatted)
Both output
['2020-10-01T00:00:00Z',
'2020-10-01T01:00:00Z',
... some left out ...
'2020-10-01T23:00:00Z',
'2020-10-02T00:00:00Z']
Just change
num_hours = num_days.days*24 + num_days.seconds//3600
The problem is that num_days only takes integer values, so if it is not a multiple of 24h you will get the floor value (i.e for your example you will get 0). So in order to compute the hours you need to use both, days and seconds.
Also, you can create the list directly in the right order, I am not sure if you are doing it like this for some reason.
ts_raw.append(earliest_ts_obj + timedelta(hours = ts + 1))

Python Pandas: Loop through dates and add them as new rows to the dataframe?

I have a basic dataframe that is read into pandas, with a few rows of existing data that don't matter much.
df = pd.read_csv('myfile.csv')
df['Date'] = pd.to_datetime(df['Date'])
I need to be able to come up with a method that will allow me to loop through between two dates and add these as new rows. These dates are on a cycle, 21 days out of 28 day cycle. So if the start date was 4/1/13 and my end date was 6/1/19, I want to be able to add a row for each date, 21 days on and off for a week.
Desired output:
A, Date
x, 4/1/13
x, 4/2/13
x, 4/3/13
x, 4/4/13
x, 4/5/13
... cont'd
x, 4/21/13
y, 4/29/13
y, 4/30/13
... cont'd
You can see that between x and y there was a new cycle.
I think I am supposed to use Datetime for this but please correct me if I am wrong. I am not sure where to start.
EDIT
I started with this:
import datetime
# The size of each step in days
day_delta = datetime.timedelta(days=1)
start_date = datetime.date(2013, 4, 1)
end_date = start_date + 21*day_delta
for i in range((end_date - start_date).days):
print(start_date + i*day_delta)
And got this:
2013-04-01
2013-04-02
2013-04-03
2013-04-04
2013-04-05
2013-04-06
2013-04-07
2013-04-08
2013-04-09
2013-04-10
2013-04-11
2013-04-12
2013-04-13
2013-04-14
2013-04-15
2013-04-16
2013-04-17
2013-04-18
2013-04-19
2013-04-20
2013-04-21
But I am not sure how to implement the cycle in here.
TYIA!
Interesting question, I spent almost half an hour on this.
Yes, you will need the datetime module for this.
base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(100)]
I made a list of dates as you did. This is a list of datetime.timedelta objects. I recommend you convert all your dates into this format to make calculations easier. We set a base date (the first day) to compare with the rest later on in a loop.
date_list_filtered = []
for each in enumerate(date_list):
date_list_filtered.append(each[1].strftime('%d/%m/%y'))
strftime() changes the datetime.datetime object into a readable date, my own preference is using the dd/mm/yy format. You can look up different formats online.
df = pd.DataFrame({'Raw':date_list,'Date':date_list_filtered})
Here I made a loop to count the difference in days between each date in the loop and the base date, changing the base date every time it hits -21.
Edit: Oops I did 21 days instead of 28, but I'm sure you can tweak it
base = df['Raw'][0]
unique_list = []
no21 = 0
for date in df['Raw'].values:
try:
res = (date-base).days
except:
res = (date-base).astype('timedelta64[D]')/np.timedelta64(1, 'D')
if res==-21.0:
base = date
#print(res)
unique_list.append(string.ascii_letters[no21])
no21+=1
else:
unique_list.append(string.ascii_letters[no21])
I used the string library to get the unique letters I wanted.
Lastly, put it in the data frame.
df['Unique'] = unique_list
Thanks for asking this question, it was really fun.
You can floor divide the difference in days from the start date by 28 to get the number of cycles.
date_start = datetime.datetime(2013, 4, 1)
date1 = datetime.datetime(2013, 5, 26)
And to check the difference
diff_days = (date1-date_start).days
diff_days
55
cycle = (date1-date_start).days//28
cycle
1
Then you can sum over the dates within the same cycle.

python get day if its in a dates range

I'm trying to check if first date of the month and the last date of the month lies in a range of dates (the range is 7 days window starting from current date) . below is an example for what I'm trying to achieve:
import datetime, calendar
today = datetime.date.today()
date_list = [today + datetime.timedelta(days=x) for x in range(0, 7)]
lastDayOfMonth = today.replace(day=calendar.monthrange(today.year,today.month)[-1])
if 1 in [ date_list[i].day for i in range(0, len(date_list))]:
print "we have first day of month in range"
elif lastDayOfMonth in [ date_list[i].day for i in range(0, len(date_list))]:
print " we have last date of month in the range"
I'm wondering if there is a cleaner way for doing that? I also want to print the exact date if I find it in the list but I don't know how without expanding the for loop in the if statement and save print date_list[i] if it matches my condition. so instead of printing the message when I find the first day in the range I should print the actual date. same for last date.
Thanks in advance!
The only thing I can come up with, without having to make use of iteration is:
import datetime, calendar
today = datetime.date.today()
week_from_today = today + datetime.timedelta(days=6)
last_day_of_month = today.replace(day=calendar.monthrange(today.year,today.month)[-1])
if today.month != week_from_today.month:
print datetime.date(week_from_today.year, week_from_today.month, 1)
elif today <= last_day_of_month <= week_from_today:
print last_day_of_month
since today it's 2016-06-02 it's hard to test the code.
Try changing the variable today to another day. I used the dates 2016-05-25 and 2016-05-26 to test the code.
to set a custom date: today = datetime.date(yyyy, m, d)

Categories

Resources