I have a problem, which is trying to get a next available date from within list of dates. This list of dates contains dates which are not saturday/sunday or any public holiday. My inputs will be like, what was the first available date in last 180 days, plan is to build a function like below,
1d = current date - interval 180 days2d = get_next_available_date(d)
Breaking down the problem
Initializations
1# Initializing full feb dates2test_dates = ['01-02-2020', '02-02-2020', '03-02-2020', '04-02-2020', '05-02-2020',3 '06-02-2020', '07-02-2020', '08-02-2020', '09-02-2020', '10-02-2020', '11-02-2020',4 '12-02-2020', '13-02-2020', '14-02-2020', '15-02-2020', '16-02-2020', '17-02-2020',5 '18-02-2020', '19-02-2020', '20-02-2020', '21-02-2020', '22-02-2020', '23-02-2020',6 '24-02-2020', '25-02-2020', '26-02-2020', '27-02-2020', '28-02-2020', '29-02-2020']
Remove a week from feb between 09/02/2020 - 15/02/2020
1del test_dates[8:15]
After removing a week data looks like this
1print(test_dates)2
3#Output:4
5['01-02-2020', '02-02-2020', '03-02-2020', '04-02-2020',6 '05-02-2020', '06-02-2020', '07-02-2020', '08-02-2020', '16-02-2020', '17-02-2020',7 '18-02-2020', '19-02-2020', '20-02-2020', '21-02-2020', '22-02-2020', '23-02-2020',8 '24-02-2020', '25-02-2020', '26-02-2020', '27-02-2020', '28-02-2020', '29-02-2020']
Converts string to datetime format
1get_datetime = lambda s: dt.datetime.strptime(s, '%d-%m-%Y')
Main logic to get the next available date
1base_date = '10-02-2020'2base = get_datetime(base_date)3
4# Converting all the dates to datetime format5availdates = list(map(lambda d: get_datetime(d), test_dates))6print('\n Base date =',base, 'Type =',type(base))7print('\n Available dates =\n',availdates, 'Type =',type(availdates), 'Element Type =', type(availdates[0]))8
9# Filtering the dates greater than base date10later = filter(lambda d: d > base, availdates)11
12# Finding the minimum date among the dates greater than base date13closest_date = min(later)14print('\n Next available date =',closest_date, 'Type =',type(closest_date))15print('\n Next available date =',closest_date.strftime("%Y-%m-%d"), 'Type =',type(closest_date.strftime("%Y-%m-%d")))
Output:
1test_dates after removing a week = 2 ['01-02-2020', '02-02-2020', '03-02-2020', '04-02-2020', '05-02-2020', '06-02-2020', '07-02-2020', '08-02-2020', '16-02-2020', '17-02-2020', '18-02-2020', '19-02-2020', '20-02-2020', '21-02-2020', '22-02-2020', '23-02-2020', '24-02-2020', '25-02-2020', '26-02-2020', '27-02-2020', '28-02-2020', '29-02-2020']3
4 Base date = 2020-02-10 00:00:00 Type = <class 'datetime.datetime'>5
6 Available dates =7 [datetime.datetime(2020, 2, 1, 0, 0), datetime.datetime(2020, 2, 2, 0, 0), datetime.datetime(2020, 2, 3, 0, 0), datetime.datetime(2020, 2, 4, 0, 0), datetime.datetime(2020, 2, 5, 0, 0), datetime.datetime(2020, 2, 6, 0, 0), datetime.datetime(2020, 2, 7, 0, 0), datetime.datetime(2020, 2, 8, 0, 0), datetime.datetime(2020, 2, 16, 0, 0), datetime.datetime(2020, 2, 17, 0, 0), datetime.datetime(2020, 2, 18, 0, 0), datetime.datetime(2020, 2, 19, 0, 0), datetime.datetime(2020, 2, 20, 0, 0), datetime.datetime(2020, 2, 21, 0, 0), datetime.datetime(2020, 2, 22, 0, 0), datetime.datetime(2020, 2, 23, 0, 0), datetime.datetime(2020, 2, 24, 0, 0), datetime.datetime(2020, 2, 25, 0, 0), datetime.datetime(2020, 2, 26, 0, 0), datetime.datetime(2020, 2, 27, 0, 0), datetime.datetime(2020, 2, 28, 0, 0), datetime.datetime(2020, 2, 29, 0, 0)] Type = <class 'list'> Element Type = <class 'datetime.datetime'>8
9 Next available date = 2020-02-16 00:00:00 Type = <class 'datetime.datetime'>10
11 Next available date = 2020-02-16 Type = <class 'str'>
Difference between .today() & .now()
.today()
Returns the current local datetime, without tzinfo
1dt.datetime.today() # datetime.datetime(2020, 4, 19, 11, 58, 28, 547738)2print(dt.datetime.today()) # 2020-04-19 11:58:28.831696
.now()
Return the current local date and time. If optional argument tz is None or not specified, this is like today(), but, if possible, supplies more precision
1dt.datetime.now() # datetime.datetime(2020, 4, 19, 11, 58, 28, 335700)2print(dt.datetime.now()) # 2020-04-19 11:58:28.830691
Making .now() timezone aware you will have to use import pytz
1import pytz2d = dt.datetime.now()3timezone = pytz.timezone('Asia/Calcutta')4d_aware = timezone.localize(d)5d_aware.tzinfo6
7#Output:8#<DstTzInfo 'Asia/Calcutta' IST+5:30:00 STD>
pytz.all_timezones
will list all available timezones
1['Africa/Abidjan',2...3'Asia/Calcutta',4'Asia/Shanghai',5'Europe/London',6'America/Los_Angeles',7'America/New_York',8...9 'Zulu']
Above timezone thing, has nothing to do with this article, i just got bit side-tracked.
Below, i am subracting 180 days from current date, that will be the base date or start date.
1base = dt.datetime.today() - dt.timedelta(days=180)2print('Base Date : ',base)3#Output:4#Base Date : 2019-10-22 12:29:19.946372
Now, merging point(1) and timedelta of point(2) to create a new function,
1def get_next_available_date(test_dates, days):2 base = dt.datetime.today() - dt.timedelta(days=days)3 print(' Base date =',base, 'Type =',type(base))4 availdates = list(map(lambda d: get_datetime(d), test_dates))5 #print('\n Available dates =\n',availdates, 'Type =',type(availdates), 'Element Type =', type(availdates[0]))6 later = filter(lambda d: d > base, availdates)7 #closest_date = min(later, key = lambda d: get_datetime(d))8 closest_date = min(later)9 print(' Next available date =',closest_date, 'Type =',type(closest_date))10 closest_date = closest_date.strftime("%Y-%m-%d")11 return closest_date
Below is the call,
1print('timedelta =',dt.datetime.today() - dt.timedelta(days=69))2#timedelta = 2020-02-10 12:45:21.1507613
4print(get_next_available_date(test_dates, 69))5# Base date = 2020-02-10 12:47:05.276859 Type = <class 'datetime.datetime'>6# Next available date = 2020-02-16 00:00:00 Type = <class 'datetime.datetime'>7#2020-02-16
Below is the logic used to generate the dates for initialization,
1start = dt.datetime.strptime("01-02-2020", "%d-%m-%Y")2end = dt.datetime.strptime("29-02-2020", "%d-%m-%Y")3date_generated = [start + dt.timedelta(days=x) for x in range(0, (end-start).days+1)]4
5test_dates = []6for date in date_generated:7 test_dates.append(date.strftime("%d-%m-%Y"))
map(func, *iterables)
Example 1
1my_pets = ['alfred', 'tabitha', 'william', 'arla']2uppered_pets = list(map(str.upper, my_pets))3print(uppered_pets)4# Output : ['ALFRED', 'TABITHA', 'WILLIAM', 'ARLA']
Example 2
1circle_areas = [3.56773, 5.57668, 4.00914, 56.24241, 9.01344, 32.00013]2result = list(map(round, circle_areas, range(1,7)))3print(result)4# Output : [3.6, 5.58, 4.009, 56.2424, 9.01344, 32.00013]
Example 3 ( using repeat to have same value repeated for round() )
1circle_areas = [3.56773, 5.57668, 4.00914, 56.24241, 9.01344, 32.00013]2result = list(map(round, circle_areas, np.repeat(2,6)))3print(result)4# Output : [3.57, 5.58, 4.01, 56.24, 9.01, 32.0]
filter(func, iterable)
Example 1
1scores = [66, 90, 68, 59, 76, 60, 88, 74, 81, 65]2def is_A_student(score):3 return score > 754
5over_75 = list(filter(is_A_student, scores))6print(over_75)7# Output : [90, 76, 88, 81]
Example 2
1dromes = ("demigod", "rewire", "madam", "freer", "anutforajaroftuna", "kiosk")2palindromes = list(filter(lambda word: word == word[::-1], dromes))3print(palindromes)4# Output : ['madam', 'anutforajaroftuna']