Problem Statement:
Am developing a custom job scheduler that needs to be run on given days. It takes start date and end date as string and third param is list of week days on which job should run.
Start day can be different with given days but first job should run on next valid day
Let suppose Start date is 2022-09-07 (so day name is Wednesday) but given frequency days are ["Monday", "Friday", "Saturday"] so i need to run my first job on coming Friday and for this i need to calculate difference between start date and first valid day (in this case it's Friday)
So how can i do this python to run my first job on valid day (that can be in any position of given frequency days list) and also after one job complete i need to also get next valid day. I did some work but unfortunately its not working. Here is what i did
sorted_week_days_list = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
start_date = "2022-09-07"
valid_frequency_days = ["Monday", "Tuesday", "Friday"] # It can be any days in sorted order
start_date_object = datetime.datetime.strptime(start_date, "%Y-%m-%d")
given_start_day = start_date_object.strftime("%A")
if given_start_day not in valid_frequency_days:
# Need help to implement logic to get date for valid day
You should use the datetime.weekday() method to pull out the day of the week for days of interest. Assuming that you have dates similar to the format you show above, it is easy to convert, and also just use the day index for your "allowable start days" (Monday=0).
Then you can jig up a little function to look for the next start date in your sorted list and figure out how many days you need to wait.
Example below does that and also "rolls over" the weekend as needed.
Code:
from datetime import datetime, timedelta
from bisect import bisect_left
start_date = "2022-09-09"
valid_start_dates = [1, 4] # It can be any days in sorted order
start_date_object = datetime.strptime(start_date, "%Y-%m-%d")
d=start_date_object.weekday()
print(f'the numbered day of the week is: {d}')
def days_till_start(day, valid_start_days):
idx = bisect_left(valid_start_days, day)
if idx >= len(valid_start_days): # wrap around to next start
return valid_start_days[0] + 7 - day
elif day == valid_start_days[idx]:
return 0
else:
return valid_start_days[idx] - day
print(days_till_start(d, valid_start_dates))
start_dates = ['2022-09-05', '2022-09-06', '2022-09-07', '2022-09-08', '2022-09-09', '2022-09-10']
start_wkdys = [datetime.strptime(d, "%Y-%m-%d").weekday() for d in start_dates]
for d in start_wkdys:
print(f'day index is: {d}')
print(f'next start date is {days_till_start(d, valid_start_dates)} away')
print()
Output:
the numbered day of the week is: 4
0
day index is: 0
next start date is 1 away
day index is: 1
next start date is 0 away
day index is: 2
next start date is 2 away
day index is: 3
next start date is 1 away
day index is: 4
next start date is 0 away
day index is: 5
next start date is 3 away
Related
I need to find the day of each other day of a month if the first day is Friday of that month. Need to write a function named returnDay which will take one parameter that is the date of that month. The date should be in range of 1 and 31. When I input a date of the month, then have to call that function which returns it's day. If the actual parameter is less than 1 or greater than 31, give a hint that the input isn't available date of that month.
So my question is how to put the 1-31 range here and what is the issue that it shows name 'date' is not defined whenever I run this?
def returnDay(date):
day_names= ['Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
day= input("Enter first day of the month: ")
date = int(input('please enter the date of October: '))
i = date%7 -1
if day in day_names:
j = day_names.index(day)+i
if j >= 7:
j = j - 7
return(day_names[j])
print(returnDay(date))
I see a couple of problems in your code. From the way you are calling returnDay(date), it looks like you want to have the date as a parameter to this function. You cannot retrieve the date as input from the user, from within the same function that also needs the date as an argument. So first rewrite your code so that you set the input from outside this function scope, and then supply it to your function for processing. The same goes for the integer part of your date. Now for the logic behind calculating the day to return:
A user supplies the first day
A user supplies the current date
let's go
def returnDay(firstDay,currentDate):
days_in_week = ['Monday','Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
day_offset = 0
for i in range(7):
if firstDay == days_in_week[i]:
day_offset += i
index_days_in_week = (currentDate + day_offset)%7 - 1
return days_in_week[index_days_in_week]
def main():
firstDay = input("supply the first day of the month")
currentDate = input("supply current day of the month")
returnDay(firstDay, currentDate)
main()
You may need to optimise it in order to work completely. I leave this as a homework assessment to you.
I am trying to round a pandas datetime column to its nearest year or month but I cannot figure out how to do it. For instance, this minimal example rounds to the closest hour:
pd.Timestamp.now().round('60min')
What I'd like is a way to replace the '60min' in order to round pd.Timestamp.now() to obtain either 2020-01-01 (for the year case) or 2019-08-01 (for the month case) (note that now() is exactly 2019-07-30 16:41:23.612004 at the time of asking!).
The pandas.Series.dt.round doc suggest a freq argument linking to this page, but trying the months/years options there return this error:
ValueError: is a non-fixed frequency
Any idea what I am missing?
If the column is really DateTime column (check with df.dtypes), you can get the year, month & day with the code below.
df['Year'] = df['Date'].dt.year
df['Month'] = df['Date'].dt.month
df['Day'] = df['Date'].dt.day
df['round_Year'] = df['Date']+ pd.offsets.YearBegin(-1)
rounds off to start of current year. Change -1 to 0 rounds off to start of next year.
df['round_Month'] = df['Date'] + pd.offsets.MonthBegin(-1)
rounds off to start of current Month. Change -1 to 0 rounds off to start of next Month
Example of rounding a Python Timestamp to the nearest half year:
from Pandas import Timestamp
def round_date_to_nearest_half_year(ts: Timestamp) -> Timestamp:
if 4 <= ts.month <=8:
return Timestamp(ts.year, 7, 1)
elif ts.month >=9:
return Timestamp(ts.year+1, 1, 1)
elif ts.month <= 3:
return Timestamp(ts.year, 1, 1)
else:
raise Exception("Logic error.")
Test:
print(round_date_to_nearest_half_year(Timestamp("2022-6-5")))
print(round_date_to_nearest_half_year(Timestamp("2022-7-3")))
print(round_date_to_nearest_half_year(Timestamp("2022-12-15")))
print(round_date_to_nearest_half_year(Timestamp("2023-1-5")))
Out:
2022-07-01 00:00:00
2022-07-01 00:00:00
2023-01-01 00:00:00
2023-01-01 00:00:00
I'm attempting to output all days within the current week. e.g. for this week, show all days, 05/12/2019 through 05/18/2019 only. when the bot is executed next week, only show days 05/19/2019 through 05/25/2019. My current logic outputs the days for this week, but come tomorrow, the dates for this week will be thrown off. Please see the following
...could I get some help with this please?
Using VBS
I would do this using a VBS script, using Run Script command.
The default week start is Sunday you can change it check: https://www.w3schools.com/asp/func_weekday.asp
Pass the day you that you want as a parameter from 0 to 6, and get the data as a return value.
DayNumber: 0 = Sunday ..... 6 = Saturday
InputDate = Date
DayNumber = WScript.Arguments.Item(0)
Result = DateAdd("d", DayNumber - WeekDay(InputDate, 2), InputDate)
WScript.StdOut.Write(Result)
'MsgBox(Result)
Using MetaBot
Metabot Link: Change Date and Time Format
You will have to run the following logic in sequence.
Input: DayNumber: 0 = Sunday ..... 6 = Saturday
Using DayOfWeek Logic, Get the Day of the week and assign it to
WeekDay variable, it will return the name, not the number, and the input will be Date.
Using IF conditions convert the name of
the day to number, start from 0 to 6 as your first day in the week,
which is Sunday, and using variable operation assigns the value to
NumWeekDay variable.
Using variable operation, Get the offset by subtracting DayNumber, the day you want minus NumWeekDay,
and assign the value to Offset variable.
Using AddDays, Input
the date and the offset, and you will get the date of the day that you want.
I'm looking to achieve a search of files based on user input on a date. For example, I'm attempting to write the script to ask user for a range in which to search (month to date, last full week, or specific day).
last full week needs to go backward, to the last full week - so if today is Wednesday, the script should go back to the previous (2)Sunday(s) as a start range to the Saturday that just past, while also accounting for what day it is currently:
Sun(start)---Mon---Tue---Wed---Thu---Fri---Sat(end)---Sun---Mon---Tue---Wed (today)
Howevver, it needs to also account for what day it is in relation to the above, meaning that regardless of what "today" is, the search criteria is always one full week behind (if its Sunday, it just goes to last sunday to 'yesterday, Saturday')
From some examples attempting similar things I've seen here and here, I've attempted to join, modify, and add over the last couple of days:
import datetime
import os
import dateutil.relativedelta
import timedelta
class AuditFileCheck():
"""File Compliance Checker."""
def datechoice(self):
"""Select date."""
print("Checking the Audit Files for compliance.")
print("Today is", datetime.date.today().strftime(" %A."))
print("\nI will check either for file compliances."
"\nSearch criteria is either by MONTH to date, last full WEEK, "
"or individual DAY: [M/W/D]")
print(now.strftime('Week of %Y%m%d'))
weekbefore = now - timedelta(days=6)
print(
"Week of {weekbefore:%A, %m-%d-%Y} to {now:%A, %m-%d-%Y}").format(**vars())
input_search = input(
"Enter search range: Month to date, Prior Week, or by day [M/W/D]")
def search_month(d, w, m, weekday, month):
"""Establish search from month start, or prior month if today is first of current month."""
if input_search.lower() == "m":
current_month = datetime(today.month, 1, today.year)
if current_month == datetime.today():
current_month == dateutil.relativedelta.relativedelta(
months=-1)
return m - datetime.timedelta(current_month)
m = current_month()
print(current_month)
# TODO ensure the prior month is used if 'today' is before the end of
# first full week in current month
if input_search.lower() == "w":
prior_week = weekday + d.weekday()
if prior_week >= 0: # Target day already happened this week
prior_week -= 6
return d - datetime.timedelta(prior_week)
d = datetime.date.today()
# 6 = Sunday, 0 = Monday, 1 = Tuesday...
previous_monday = previous_weekday(d, 6)
print(previous_monday)
# TODO search files
if input_search.lower() == "d":
day_search = input(
"Enter a specific date within to search [YYYYMMDD]")
return d
print("Searching through...")
# TODO search files from set_day
This bit:
previous_sunday = previous_weekday(d, 8)
adjusting the integer adjusts how far back it looks.
I'm having some trouble with getting this to function properly. What am I doing wrong here? The more I attempt to play with it, the more confused I become and less it works...
I am writing code that lets users write down dates and times for things they have on. It takes in the date on which it starts, the start time and finish time. It also allows the user to specify if they want it to carry over into multiple weeks (every Monday for a month for example)
I am using a for loop to do this, and because of the different months having different days I obviously want (if the next Monday for example is in the next month) it to have the correct date.
This is my code:
for i in range(0 , times):
day = day
month = month
fulldateadd = datetime.date(year, month, day)
day = day + 7
if month == ( '01' or '03' or '05' or '07' or '10'or '12'):
if day > 31:
print(day)
day = day - 31
print(day)
month = month + 1
elif month == ( '04' or '06'or '09' or '11'):
if day > 30:
print(day)
day = day - 30
print(day)
month = month + 1
elif month == '02':
if day > 29:
print(day)
day = day - 29
print(day)
month = month + 1
When running this and testing to see if it goes correctly into the new month I get the error:
File "C:\Users\dansi\AppData\Local\Programs\Python\Python36-32\gui test 3.py", line 73, in addtimeslot
fulldateadd = datetime.date(year, month, day)
ValueError: day is out of range for month
Where have I gone wrong?
It's hard to be completely accurate without seeing some of the previous code (for example, where do day, month, year, and times come from?), but here's how you might be able to use timedelta in your code:
fulldateadd = datetime.date(year, month, day)
for i in range(times):
fulldateadd = fulldateadd + datetime.timedelta(7)
A timedelta instance represents a period of time, rather than a specific absolute time. By default, a single integer passed to the constructor represents a number of days. So timedelta(7) gives you an object that represents 7 days.
timedelta instances can then be used with datetime or date instances using basic arithmetic. For example, date(2016, 12, 31) + timedelta(1) would give you date(2017, 1, 1) without you needing to do anything special.