I'm trying to make a tkinter app where the user can select a date range.
The Tkcalendar library only allows to select 1 day, is there a way to select multiple continuous days?
Thank you very much
You can create two calendars and then choose two dates and then find the range between those two dates. The core function would be:
def date_range(start,stop): # Start and stop dates for range
dates = [] # Empty list to return at the end
diff = (stop-start).days # Get the number of days between
for i in range(diff+1): # Loop through the number of days(+1 to include the intervals too)
day = first + timedelta(days=i) # Days in between
dates.append(day) # Add to the list
if dates: # If dates is not an empty list
return dates # Return it
else:
print('Make sure the end date is later than start date') # Print a warning
Now to put things in tkinter perspective, button callbacks cannot return anything, so this should be something like:
from tkinter import *
import tkcalendar
from datetime import timedelta
root = Tk()
def date_range(start,stop):
global dates # If you want to use this outside of functions
dates = []
diff = (stop-start).days
for i in range(diff+1):
day = start + timedelta(days=i)
dates.append(day)
if dates:
print(dates) # Print it, or even make it global to access it outside this
else:
print('Make sure the end date is later than start date')
date1 = tkcalendar.DateEntry(root)
date1.pack(padx=10,pady=10)
date2 = tkcalendar.DateEntry(root)
date2.pack(padx=10,pady=10)
Button(root,text='Find range',command=lambda: date_range(date1.get_date(),date2.get_date())).pack()
root.mainloop()
Keep in mind, the list is full of datetime objects, to make a list full strings of date alone, say:
dates = [x.strftime('%Y-%m-%d') for x in dates] # In the format yyyy-mm-dd
Related
start = "Nov20"
end = "Jan21"
# Expected output:
["Nov20", "Dec20", "Jan21"]
What I've tried so far is the following but am looking for more elegant way.
from calendar import month_abbr
from time import strptime
def get_range(a, b):
start = strptime(a[:3], '%b').tm_mon
end = strptime(b[:3], '%b').tm_mon
dates = []
for m in month_abbr[start:]:
dates.append(m+a[-2:])
for mm in month_abbr[1:end + 1]:
dates.append(mm+b[-2:])
print(dates)
get_range('Nov20', 'Jan21')
Note: i don't want to use pandas as that's not logical to import such library for generating dates.
The date range may span different years so one way is to loop from the start date to end date and increment the month by 1 until end date is reached.
Try this:
from datetime import datetime
def get_range(a, b):
start = datetime.strptime(a, '%b%y')
end = datetime.strptime(b, '%b%y')
dates = []
while start <= end:
dates.append(start.strftime('%b%y'))
if start.month == 12:
start = start.replace(month=1, year=start.year+1)
else:
start = start.replace(month=start.month+1)
return dates
dates = get_range("Nov20", "Jan21")
print(dates)
Output:
['Nov20', 'Dec20', 'Jan21']
You can use timedelta to step one month (31 days) forward, but make sure you stay on the 1st of the month, otherwise the days might add up and eventually skip a month.
from datetime import datetime
from datetime import timedelta
def get_range(a, b):
start = datetime.strptime(a, '%b%y')
end = datetime.strptime(b, '%b%y')
dates = []
while start <= end:
dates.append(start.strftime('%b%y'))
start = (start + timedelta(days=31)).replace(day=1) # go to 1st of next month
return dates
dates = get_range("Jan20", "Jan21")
print(dates)
I am trying to convert a column of dates from MonthYear form to mm/dd/yyyy and I can do it as a string replace but it requires 157 lines of code to get all the data changed. I want to be able to take the month and year and push out the second wednesday of the month in mm/dd/yyyy form. is that possible?
I am currently using this code
df['Column']=df['Column'].str.replace("December2009", "12/11/2009")
I don't know of a standard library tool for this, but it's easy to make your own, something like this:
from datetime import datetime, timedelta
import pandas as pd
test_arr = ['December2009', 'August2012', 'March2015']
def replacer(d):
# take a datestring of format %B%Y and find the second wednesday
dt = datetime.strptime(d, '%B%Y')
x = 0
# start at day 1 and increment through until conditions satisfied
while True:
s = dt.strftime('%A')
if s == 'Wednesday':
x += 1 # if a wednesday found, increment the counter
if x == 2:
break # when two wednesdays found then break
dt += timedelta(days = 1)
return dt.strftime('%m/%d/%Y')
df = pd.DataFrame(test_arr, columns = ['a'])
df['a'].apply(replacer) # .apply() applies the given python function to each element in the df column
Maybe the calendar module as recommended in the other comments could make the code look nicer but I'm unfamiliar with it so it might be something you want to look into the improve the solution
happy holidays!
I am working on the project that needs to send reminders about public holidays 3 weeks in advance. I have completed this part and now need to add a function that will also send the remaining holidays for the year in addition to the upcoming holiday. Any tips or suggestions on how I can approach this will be greatly appreciated as I am new to coding!
Here is the code I have for now:
import datetime
from datetime import timedelta
import calendar
import time
import smtplib as smtp
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.message import EmailMessage
holidayFile = 'calendar.txt'
def run(input):
checkTodaysHolidays()
def checkTodaysHolidays():
file = open(holidayFile, 'r')
date = (datetime.date.today() + datetime.timedelta(days=21)).strftime('%Y/%m/%d')
publicHolidayName = ''
for line in file:
if date in line:
publicHolidayName = " ".join(line.split()[1:])
Thank you.
I think the easiest way to do this would be to use the datetime and timedelta modules you've already imported.
I would convert the data in your text file into an array, and then build a function that compares today's date to the holidays in this list.
holidayFile = open('calendar.txt', 'r')
holidayLines = holidayFile.readlines()
holidayFile.close()
holidayNames = []
holidayDates = []
for x in range(0, len(holidayLines) ):
# ... Get the date, first
this = holidayLines[x].split(" ") # since we know they're formatted "YYYY/MM/DD Name of Holiday"
rawdate = this[0]
datechunks = rawdate.split("/") # separate out the YYYY, MM, and DD for use
newdate = (datechunks[0] ,datechunks[1] , datechunks[2])
holidayDates.append(newdate)
# ... then get the Name
del this[0] # remove the dates from our split array
name = "".join(this)
holidayNames.append(name)
So in the block before our function, I:
1: Open the file and store each line, then close it.
2: Iterate through each line and separate out the date, and store the touples in an array.
3: Save the name to a separate array.
Then we do the comparison.
def CheckAllHolidays():
returnNames = [] # a storage array for the names of each holiday
returnDays = [] # a storage array for all the holidays that are expected in our response
today = datetime.datetime.now()
threeweeks = timedelta(weeks=3)
for x in range(0, len(holidayDates) ):
doi = holidayDates[x] # a touple containing the date of interest
year = doi[0]
month = doi[1]
day = doi[2]
holiday = datetime.datetime(year, month, day)
if holiday > today:
# convert the holiday date to a date three weeks earlier using timedelta
returnDays.append( holiday - threeweeks )
returnNames.append( holidayNames[x] )
else:
pass # do nothing if date has passed
return(returnDays, returnNames)
What I did here is I:
1: Create an array inside the function to store our holiday names.
2: Convert the date from the previous array into a datetime.datetime() object.
3: Compare two objects of like kind in an if block, and
4: Return a list of dates three-weeks before each holiday, with names for the holidays that a reminder should be set for.
Then you're all set. You could call
ReminderDates = CheckAllHolidays()[0]
ReminderNames = CheckAllHolidays()[1]
and then use those two lists to create your reminders! ReminderDates would be an array filled with datetime.datetime() objects, and ReminderNames would be an array filled with string values.
I'm sorry my response was kinda long, but I really hope I was able to help you with your issue! Happy Holidays <3
I need to amend an existing python sript which extracts data from previous day to extract data for last two weeks like biweekly data. Please advise how I can twik to get the date range in the variable
def parse_gov():
reject_patterns = generate_reject_patterns()
today_str = date.today().strftime('%Y.%m.%d')
yesterday =
yesterday_str = yesterday.strftime('%Y.%m.%d')
query_date = date.today()
So need to get the date range in yesterday variable
You can use timedelta to do so. for example,
import datetime
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
I want to add hours to a datetime and use:
date = date_object + datetime.timedelta(hours=6)
Now I want to add a time:
time='-7:00' (string) plus 4 hours.
I tried hours=time+4 but this doesn't work. I think I have to int the string like int(time) but this doesn't work either.
Better you parse your time like below and access datetime attributes for getting time components from the parsed datetime object
input_time = datetime.strptime(yourtimestring,'yourtimeformat')
input_seconds = input_time.second # for seconds
input_minutes = input_time.minute # for minutes
input_hours = input_time.hour # for hours
# Usage: input_time = datetime.strptime("07:00","%M:%S")
Rest you have datetime.timedelta method to compose the duration.
new_time = initial_datetime + datetime.timedelta(hours=input_hours,minutes=input_minutes,seconds=input_seconds)
See docs strptime
and datetime format
You need to convert to a datetime object in order to add timedelta to your current time, then return it back to just the time portion.
Using date.today() just uses the arbitrary current date and sets the time to the time you supply. This allows you to add over days and reset the clock to 00:00.
dt.time() prints out the result you were looking for.
from datetime import date, datetime, time, timedelta
dt = datetime.combine(date.today(), time(7, 00)) + timedelta(hours=4)
print dt.time()
Edit:
To get from a string time='7:00' to what you could split on the colon and then reference each.
this_time = this_time.split(':') # make it a list split at :
this_hour = this_time[0]
this_min = this_time[1]
Edit 2:
To put it all back together then:
from datetime import date, datetime, time, timedelta
this_time = '7:00'
this_time = this_time.split(':') # make it a list split at :
this_hour = int(this_time[0])
this_min = int(this_time[1])
dt = datetime.combine(date.today(), time(this_hour, this_min)) + timedelta(hours=4)
print dt.time()
If you already have a full date to use, as mentioned in the comments, you should convert it to a datetime using strptime. I think another answer walks through how to use it so I'm not going to put an example.