Iteratively changing dates in URLs - python

I'm having trouble building a logic/algorithm that creates a date, adds it to the URL and then when I create another URL, it will contain the next date.
It should iterate through every day of every month of every year (that's why I thought of the nested for loops).
Note that I only have one variable for date because I want the start and end dates to be the same.
# Setting range of years, months and days to be iterated through in the URL later
YYYY = []
years = range(2016, 2021)
for yyyy in years:
YYYY.append(yyyy)
MM = []
months = range(1, 13)
for mm in months:
MM.append(mm)
DD = []
days = range (1, 32)
for dd in days:
DD.append(dd)
# Create iterating logic with i, j and k t define which year, month and day will be added to the URL
for i in YYYY:
for j in MM:
for k in DD:
True
# start_date and e_date are the same, so we just define 'date'
date = str(YYYY[i]) + '-' + str(MM[j]) + '-' + str(DD[k])
print(date)
# Create URL with the date variable so it can be iterated through
URL = ('https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=' +
date + '&dt[dr][ed]=' + date + '&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US')

You could use datetime and timedelta objects to make a generator to produce the URLs to iterate over:
from datetime import datetime, timedelta
def get_url():
date = datetime(2016,1,1)
while date < datetime(2020,12,31):
yield 'https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=' + \
date.strftime('%Y-%m-%d') + '&dt[dr][ed]=' + date.strftime('%Y-%m-%d') + '&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US'
date += timedelta(days=1)
i = 0
for url in get_url():
i += 1
if i < 3 or i > 10:
print(url)
if i > 12:
break
Output:
https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=2016-01-01&dt[dr][ed]=2016-01-01&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US
https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=2016-01-02&dt[dr][ed]=2016-01-02&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US
https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=2016-01-11&dt[dr][ed]=2016-01-11&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US
https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=2016-01-12&dt[dr][ed]=2016-01-12&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US
https://movement.uber.com/explore/atlanta/travel-times/query?si=1074&ti=&ag=taz&dt[tpb]=ALL_DAY&dt[wd;]=1,2,3,4,5,6,7&dt[dr][sd]=2016-01-13&dt[dr][ed]=2016-01-13&dt[dr][ed]=2016-01-19&cd=&sa;=&sdn=&lang=en-US

Related

Weekend date sequentially numbered from 1 to n

I need your help to sequentially number my weekend days from 1 to n.
Here's my code:
start_date = datetime.strptime(getStart_date, '%Y-%m-%d')
end_date = datetime.strptime(getEnd_date, '%Y-%m-%d')
weekend_date = []
WE_numberedDays = []
for i in range(delta + 1):
day = start_date + timedelta(days=i)
if day.weekday() >= 5:
weekend_date.append(day)
for items in weekend_date:
WE_numberedDays.append(itmes + 1)
print(WE_numberedDays)
It print me out [2-2-2-2-2-2-2-] instead I would like [1-2-3-4-6-7-8]. Thank you for your help, hope your having a beautiful day in this rough time.
You can use range
WE_numberedDays = list(range(1,len(weekend_date))
And now you have the array from 1 to n

Better way of incrementing a date month?

I have a date as an int like so for example: 201805 I'd like to have a way where I can give the start date and it'll return back the next date, in this example: 201806. Currently, I have this solution:
def incrementDate(startdate):
try:
newdate = dt.datetime.strptime(str(startdate + 1), "%Y%m")
return str(newdate.year) + newdate.strftime('%m')
except:
newdate = dt.datetime.strptime(str(startdate), "%Y%m")
return int(str(newdate.year + 1) + "01")
Is this a good way of going about this or is there a simple better way?
How about something using relativedelta:
Your first step will be to install the package dateutil:
pip install dateutil
Then you will be able to use it:
import datetime
from dateutil.relativedelta import relativedelta
print(datetime.datetime.strptime(str(201805), "%Y%m") + relativedelta(months=1))
Or a string:
print((datetime.datetime.strptime(str(201805), "%Y%m") + relativedelta(months=1)).strftime("%Y%m"))
Note: relativedelta comes from a separate package called 'dateutil' (here for the details). It includes notably a nice way to add month / days / year .. without creating a custom function.
You can use datetime.timedelta:
from datetime import datetime, timedelta
def incrementDate(startdate):
cur_date = datetime.strptime(str(startdate), '%Y%m')
next_date = cur_date + timedelta(days=32)
return datetime.strftime(next_date, '%Y%m')
print(incrementDate(201806)) # 201807
print(incrementDate(201812)) # 201901
Just for fun, if your input is really an integer that represents a 4 digit year folowed by a 2 digit month, then you can increment the month without any string or datetime conversions.
d = 201812
y, m = d // 100, d % 100
if m == 12:
y += 1
m = 1
else:
m +=1
d = y * 100 + m
print(d)
# 201806
The replace() method fron the datetime objects allows you to update a parameter from the datetime object:
import datetime
today = datetime.datetime.now()
current_month = today.month
year = today.year
# Check for december
if current_month < 12:
next_month = current_month + 1
else:
next_month = 1
year += 1
today= today.replace(month = next_month, year = year )
Reference
To put in in your function:
import datetime
def increment_date(startdate):
date = datetime.strptime(str(startdate), '%Y%m')
current_month = date .month
year = date .year
# Check for december
if current_month < 12:
next_month = current_month + 1
else:
next_month = 1
year += 1
return date .replace(month = next_month, year = year )

Python Remove From List of Times Based on Business Hours

I have a tuple list of times in 15 min intervals for 24h range. Now I need to remove times outside of business hours.
My times:
times = []
for i in range(0, 24 * 4):
times.append((datetime.combine(date.today(), time()) + timedelta(minutes=15) * i).time())
Business Hours:
time_open = '08:00:00'
time_close = '17:00:00'
How do I remove times from the list outside of the business hours?
Here's a quick and dirty solution if i understood what you want. You can just check if the time is between the hours the business is open / closed before appending to the list.
from datetime import datetime as d, timedelta, time
import datetime as o_d
time_open = '08:00:00'
time_close = '17:00:00'
times = []
for i in range(0, 24 * 4):
date = (d.combine(o_d.date.today(), time()) + timedelta(minutes=15) * i).time()
date_str = date.strftime("%H:%M:%S")
if time_open <= date_str <= time_close:
times.append(date_str)
#times.append(date)
print(times)
Edit from comments: If you wanted a tuple representation of what's typically called "military" time vs what most people are used to i.e. - AM / PM you can do the following
from datetime import datetime as d, timedelta, time
import datetime as o_d
time_open = '08:00:00'
time_close = '17:00:00'
times = []
for i in range(0, 24 * 4):
date = (d.combine(o_d.date.today(), time()) + timedelta(minutes=15) * i).time()
date_str = date.strftime("%H:%M:%S")
if time_open <= date_str <= time_close:
#If you want a list of just standard times
#times.append(date_str)
#If you want the time representation(s) here and no longer need the
#the datetime object
times.append((date_str, date.strftime("%I:%M %p"))
#If you still need the datetime object append this do list comprehension below in comment with #options = ....
#times.append(date)
print(times)
#assuming you have appended date above see comment
#options = [( c.strftime("%H:%M:%S"), c.strftime("%I:%M %p")) for c in times]

Generate date ranges broken by month for a given period

I'm struggling with writing a pythonic, clean generator method that, given a date period, like ['2014-01-15', '2015-02-03], will give me this:
['2014-01-15', '2014-01-31']
['2014-02-01', '2014-02-28']
...
['2015-02-01', '2015-02-03']
This is what I came up with:
from datetime import datetime
import calendar
def genDatePeriods(startDate, endDate, format='%Y-%m-%d'):
dt1 = datetime.strptime(startDate, format)
dt2 = datetime.strptime(endDate, format)
for year in range(dt1.year, dt2.year + 1):
for month in range(1, 13):
day0 = dt1.day if month == dt1.month and year == dt1.year else 1
day1 = dt2.day if month == dt2.month and year == dt2.year else calendar.monthrange(year, month)[1]
if (year == dt1.year and month < dt1.month) or (year == dt2.year and month > dt2.month):
continue
else:
d0 = (year, month, day0)
d1 = (year, month, day1)
yield [datetime(*d).strftime(format) for d in [d0, d1]]
It works, however I feel like there is a more pythonic/tidy/efficient way to do this. Any ideas?
The following is much more concise, using datetime.date() objects to find the first day of the next month each time, until you reach the end date:
from datetime import datetime, timedelta
def genDatePeriods(startDate, endDate, format='%Y-%m-%d'):
curr = datetime.strptime(startDate, format).date()
end = datetime.strptime(endDate, format).date()
while curr <= end:
# first day of the next month, using modular arithmetic
next_month = curr.replace(
month=curr.month % 12 + 1, year=curr.year + curr.month // 12,
day=1)
curr_formatted = curr.strftime(format)
# end date is next month's first day, minus one day,
# or the given endDate, whichever comes first
end_formatted = min(next_month - timedelta(days=1), end).strftime(format)
yield [curr_formatted, end_formatted]
curr = next_month
Demo:
>>> for res in genDatePeriods('2014-01-15', '2015-02-03'):
... print res
...
['2014-01-15', '2014-01-31']
['2014-02-01', '2014-02-28']
['2014-03-01', '2014-03-31']
['2014-04-01', '2014-04-30']
['2014-05-01', '2014-05-31']
['2014-06-01', '2014-06-30']
['2014-07-01', '2014-07-31']
['2014-08-01', '2014-08-31']
['2014-09-01', '2014-09-30']
['2014-10-01', '2014-10-31']
['2014-11-01', '2014-11-30']
['2014-12-01', '2014-12-31']
['2015-01-01', '2015-01-31']
['2015-02-01', '2015-02-03']

Count number of sundays in current month

How can I get the numberof Sundays of the current month in Python?
Anyone got any idea about this?
This gives you the number of sundays in a current month as you wanted:
import calendar
from datetime import datetime
In [367]: len([1 for i in calendar.monthcalendar(datetime.now().year,
datetime.now().month) if i[6] != 0])
Out[367]: 4
I happened to need a solution for this, but was unsatisfactory with the solutions here, so I came up with my own:
import calendar
year = 2016
month = 3
day_to_count = calendar.SUNDAY
matrix = calendar.monthcalendar(year,month)
num_days = sum(1 for x in matrix if x[day_to_count] != 0)
I'd do it like this:
import datetime
today = datetime.date.today()
day = datetime.date(today.year, today.month, 1)
single_day = datetime.timedelta(days=1)
sundays = 0
while day.month == today.month:
if day.weekday() == 6:
sundays += 1
day += single_day
print 'Sundays:', sundays
My take: (saves having to worry about being in the right month etc...)
from calendar import weekday, monthrange, SUNDAY
y, m = 2012, 10
days = [weekday(y, m, d+1) for d in range(*monthrange(y, m))]
print days.count(SUNDAY)
Or, as #mgilson has pointed out, you can do away with the list-comp, and wrap it all up as a generator:
sum(1 for d in range(*monthrange(y,m)) if weekday(y,m,d+1)==SUNDAY)
And I suppose, you could throw in a:
from collections import Counter
days = Counter(weekday(y, m, d + 1) for d in range(*monthrange(y, m)))
print days[SUNDAY]
Another example using calendar and datetime:
import datetime
import calendar
today = datetime.date.today()
m = today.month
y = today.year
sum(1 for week in calendar.monthcalendar(y,m) if week[-1])
Perhaps a slightly faster way to do it would be:
first_day,month_len = monthrange(y,m)
date_of_first_sun = 1+6-first_day
print sum(1 for x in range(date_of_first_sun,month_len+1,7))
You can do this using ISO week numbers:
from datetime import date
bom = date.today().replace(day=1) # first day of current month
eom = (date(bom.year, 12, 31) if bom.month == 12 else
(bom.replace(month=bom.month + 1) - 1)) # last day of current month
_, b_week, _ = bom.isocalendar()
_, e_week, e_weekday = eom.isocalendar()
num_sundays = (e_week - b_week) + (1 if e_weekday == 7 else 0)
In general for a particular day of the week (1 = Monday, 7 = Sunday) the calculation is:
num_days = ((e_week - b_week) +
(-1 if b_weekday > day else 0) +
( 1 if e_weekday >= day else 0))
import calendar
MONTH = 10
sundays = 0
cal = calendar.Calendar()
for day in cal.itermonthdates(2012, MONTH):
if day.weekday() == 6 and day.month == MONTH:
sundays += 1
PAY ATTENTION:
Here are the Calendar.itermonthdates's docs:
Return an iterator for one month. The iterator will yield datetime.date
values and will always iterate through complete weeks, so it will yield
dates outside the specified month.
That's why day.month == MONTH is needed
If you want the weekdays to be in range 0-6, use day.weekday(),
if you want them to be in range 1-7, use day.isoweekday()
My solution.
The following was inspired by #Lingson's answer, but I think it does lesser loops.
import calendar
def get_number_of_weekdays(year: int, month: int) -> list:
main_calendar = calendar.monthcalendar(year, month)
number_of_weeks = len(main_calendar)
number_of_weekdays = []
for i in range(7):
number_of_weekday = number_of_weeks
if main_calendar[0][i] == 0:
number_of_weekday -= 1
if main_calendar[-1][i] == 0:
number_of_weekday -= 1
number_of_weekdays.append(number_of_weekday)
return sum(number_of_weekdays) # In my application I needed the number of each weekday, so you could return just the list to do that.

Categories