The current "time_elapsed" duration appears as text in the tkinter window, but doesn't update like a timer. I can only assume I'm missing an important method that would allow the duration to update. I'm sure the answer is simple and I'm just looking too deeply into it. Any suggestions?
from tkinter import *
import datetime, time
root = Tk()
root.title("Debut Date")
root.geometry("600x400")
root.config(bg="#000000")
#date/time of first post (August 21, 6:30:54pm):
Year = 2020
Month = 8
Day = 21
Hour = 18
Minute = 30
Second = 54
DOP = datetime.datetime(Year,Month,Day,Hour,Minute,Second) #DOP represents "Date of Post" and
is defined by "Year", "Month", "Day", "Hour", "Minute", & "Second"
DSP = (datetime.datetime.now() - DOP) #DSP represents "Duration Since Post" and is defined by
datetime.now() minus "Date of Post"
duration = DSP.total_seconds() #total number of seconds between DOP and DSP
years = divmod(duration, 31536000)
days = divmod(years[1], 86400) #uses remainder of years to calculate days
hours = divmod(days[1], 3600) #uses remainder of days to calculate hours
minutes = divmod(hours[1], 60) #uses remainder of hours to calculate minutes
seconds = divmod(minutes[1], 1) #uses remainder of minutes to calculate seconds
def update_time():
time_elapsed = ("%d:%d:%d:%d:%d" % (years[0], days[0], hours[0], minutes[0], seconds[0]))
label.config(text = time_elapsed)
label.after(1000, update_time)
label = Label(root, text="", font=("Helvetica", 50), fg="#ffffff", bg="#000000", bd=50)
label.pack()
update_time()
root.mainloop()
Your update_time has three critical flaws. For one, it calls itself both with after and also directly. The call to update_time() causes an infinite loop.
The second problem is that you're calling root.mainloop() inside of update_time. The vast majority of time, you should only ever call mainloop() a single time during the life of your program.
The third problem is that each time update_time is called it creates a new label. You should be creating the label only once, so you need to move the creation of the label to outside of the function. You can update the label by calling the configure method to change the text option.
Try this:
from tkinter import *
import datetime, time
root = Tk()
root.title("Debut Date")
root.geometry("600x400")
root.config(bg="#000000")
#date/time of first post (August 21, 6:30:54pm):
Year = 2020
Month = 8
Day = 21
Hour = 18
Minute = 30
Second = 54
DOP = datetime.datetime(Year,Month,Day,Hour,Minute,Second) #DOP represents "Date of Post" and is defined by "Year", "Month", "Day", "Hour", "Minute", & "Second"
def update_time():
DSP = (datetime.datetime.now() - DOP) #DSP represents "Duration Since Post" and is defined by datetime.now() minus "Date of Post"
duration = DSP.total_seconds() #total number of seconds between DOP and DSP
years = divmod(duration, 31536000)
days = divmod(years[1], 86400) #uses remainder of years to calculate days
hours = divmod(days[1], 3600) #uses remainder of days to calculate hours
minutes = divmod(hours[1], 60) #uses remainder of hours to calculate minutes
seconds = divmod(minutes[1], 1) #uses remainder of minutes to calculate seconds
time_elapsed = ("%d:%d:%d:%d:%d" % (years[0], days[0], hours[0], minutes[0], seconds[0]))
label.config(text = time_elapsed)
label.after(1000, update_time)
label = Label(root, text="", font=("Helvetica", 50), fg="#ffffff", bg="#000000", bd=50)
label.pack()
update_time()
root.mainloop()
Like I pointed out in the comment:
You need to move everything after (including the) label = Label(...) outside of the function.
You also need to update your variables each time the function is called.
Related
from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
How can I find the number of 15 minutes intervals exist between start and finish?
from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
elapsed = finish - start
number_of_intervals = elapsed / timedelta(minutes=15)
elapsed is the timedelta between start and finish. Divide by 15 minutes to calculate how many 15 minute intervals fit in there.
Note that this returns a float, so includes fractional intervals. Round as appropriate.
You need to find the difference between start and finish in minutes, divide by 15, and make that an int:
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
difference = (finish - start).total_seconds()/60
quarters = int(difference/15)
i would write something similar to this:
from datetime import datetime, timedelta
DATE_TIME_STRING_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
from_date_time = datetime.strptime('2016-06-06T05:00:00.000Z',
DATE_TIME_STRING_FORMAT)
to_date_time = datetime.strptime('2016-06-06T06:00:00.000Z',
DATE_TIME_STRING_FORMAT)
date_times = [from_date_time.strftime(DATE_TIME_STRING_FORMAT)]
date_time = from_date_time
while date_time < to_date_time:
date_time += timedelta(minutes=15)
date_times.append(date_time.strftime(DATE_TIME_STRING_FORMAT))
print(date_times)
Output:
['2016-06-06T05:00:00.000000Z', '2016-06-06T05:15:00.000000Z', '2016-06-06T05:30:00.000000Z', '2016-06-06T05:45:00.000000Z', '2016-06-06T06:00:00.000000Z']
Edit:
If you are interested in just the number of 15 minute intervals you can use something like:
from datetime import datetime, timedelta
DATE_TIME_STRING_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
from_date_time = datetime.strptime('2016-06-06T05:00:00.000Z',
DATE_TIME_STRING_FORMAT)
to_date_time = datetime.strptime('2016-06-06T06:00:00.000Z',
DATE_TIME_STRING_FORMAT)
print((to_date_time-from_date_time) / timedelta(minutes=15))
You can use time library instead of date time. time works with seconds and you should convert minutes to seconds:
import time
interval = 45*60
start = time.time()
finish = time.time() + interval
diff = finish - start
print(diff // (15*60))
Simply compare start and finish like so:
from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
elapsed = finish - start # This is a timedelta object
reference_interval = 15*60 # interval in seconds
number_of_intervals = elapsed.seconds/reference_interval
As pointed out by Sören, this will not work if 'elapsed' is more than one day, in which case, simply compute the number as follow:
number_of_intervals = (elapsed.days*86400+elapsed.seconds)/reference_interval
# (86400 seconds in a day)
I was making a countdown calendar that checks how many days left, name and info, but it is the condition that changes the colour for if more than 50 days part that doesn't work. Can you guys check it?. It checks how many left for each festival. Also as u can see If I change the date to today of any festival, it shows 1 Day left until. I want to fix that
Here is the text from festivals.txt
Dashain,14/10/21,This is Nepal Main Festival
Tihar,6/11/21,Festival of Lights
Christmas,25/12/21,Jingle Bells
New Year,1/01/22,The Day of the new year
from tkinter import Tk, Canvas, simpledialog, messagebox
from datetime import date, datetime
# function get_events is to get the celebration events
def get_events():
list_events = []
with open('festivals.txt') as file:
for line in file:
line1 = line.rstrip('\n')
global current_event
current_event = line1.split(',')
current_event[1] = datetime.strptime(current_event[1], '%d/%m/%y').date()
list_events.append(current_event)
return list_events
# Function to get the dates between the 2
def days_between_dates(date1, date2):
time_between = str(date1 - date2)
number_of_days = time_between.split(' ')
return number_of_days[0]
# End of Functions
# -----------------------------------------------------------------------------------------------
# Main program starts here
root = Tk()
root.title('Calendar')
# Make Canvas
c = Canvas(root, width=2000, height=800, bg='black')
c.pack()
c.create_text(100, 50, anchor='w', fill='cyan', font=' Times 40 bold italic underline',
text='My Countdown Calendar' )
# Store the functions in variables
events = get_events()
today = date.today()
# Aligning the text, sorting the list
vertical_space = 100
events.sort(key=lambda x: x[1])
horizontal_space = 100
# Main Loop
for event in events:
event_name = event[0]
days_until = days_between_dates(event[1], today)
display = 'It is %s days until %s. %s is about %s' % (days_until, event_name, event_name,event[2])
if (int(days_until) > 10):
text_col = '#c11a2b'
remin = 'Come one %s in coming' % (event_name)
c.create_text(550, 500, anchor='w', fill='purple', font='Courier 20 bold underline', text=remin)
else:
text_col = 'lime'
c.create_text(200, vertical_space, anchor='w', fill=text_col,
font='Calibri 28 bold', text=display)
vertical_space = vertical_space + 30
horizontal_space = horizontal_space + 40
There are a couple of problems with the date calculations.
Firstly you can obtain the number of days using the days attribute of the timedelta object returned by date1 - date2 in days_between_dates(). That function could be written as:
def days_between_dates(date1, date2):
return (date1 - date2).days
This is more succinct and less error prone, and now it will return an integer that is more useful in other calculations.
This also fixes a bug. When the dates are the same and str(date1 - date2) returns
'0:00:00' which your code fails to parse.
Regarding the greater than 50 condition, there is no such check in your code. There is a > 10 but your test data does not test that condition. You should add a line with a date within 10 days of the current day.
Finally you will need to handle past events for when the event has already happened. Currently the fixed code would display a negative number of days until the event.
When I run my application , its supposed to play an mp3 file when the current time is equal to one of times in a list. The mp3 file is in the same folder as my python file. However, Three things happen. First, the sound doesn't play even though the time is correct and an output is shown in the terminal indicating that the time comparison is true. Second, an extra tkinter window pops up and finally, when I try to close both of the windows, I get these errors:
time to pray at 03:10 PM
invalid command name "2184036301640calc_countdown"
while executing
"2184036301640calc_countdown"
("after" script)
Traceback (most recent call last):
File "d:\My stuff\mypython\Tkinter\azan caller\azan_caller.py", line 266, in <module>
call_azan()
File "d:\My stuff\mypython\Tkinter\azan caller\azan_caller.py", line 152, in call_azan
playsound(azan_path)
File "C:\Users\rahma\AppData\Local\Programs\Python\Python37\lib\site-packages\playsound.py", line 17, in _playsoundWin
from random import random
ImportError: cannot import name 'random' from 'random' (d:\My stuff\mypython\Tkinter\azan caller\random.py)
Random.py is another file in the folder but I never used it in my main python file. This is my full code just for completeness:
import tkinter as tk
from tkinter import Grid
import xlrd
import os
from xlrd import cellname,xldate_as_tuple,xldate_as_datetime
from datetime import date
from datetime import datetime , timedelta
from playsound import playsound
from tkinter import font
#set time and current date
current_time = datetime.strftime(datetime.now(), "%I:%M %p") #time.strftime("%I:%M %p")
todays_date = date.today()
month = todays_date.strftime('%m')
def current_date(todays_date):
format_date = todays_date.strftime("%d/%m/%Y")
return format_date
format_date = current_date(todays_date)
#function to display current time
def display_time():
current_time = datetime.strftime(datetime.now(), "%I:%M %S %p")
lbl_display_time.config(text=current_time)
lbl_display_time.after(1000,display_time)
#function to display current date
def display_date():
todays_date = date.today()
month = todays_date.strftime('%m')
format_date = todays_date.strftime("%d/%m/%Y")
lbl_display_date.config(text=format_date)
lbl_display_date.after(1000,display_date)
#open workbook
filename = os.path.join("D:\My stuff\mypython\Tkinter",'azan caller\prayer_timings.xlsx')
workbook = xlrd.open_workbook(filename)
worksheet = workbook.sheet_by_name('Sheet %s'% month)
def get_date(format_date):
#number of rows in sheet
rows = worksheet.nrows
#get date from excel file and compare with current date
raw_date = ''
for i in range(-1,rows):
raw_date = worksheet.cell_value(i,1)
conv_date = datetime(*xlrd.xldate_as_tuple(raw_date, workbook.datemode))
excel_date = conv_date.strftime("%d/%m/%Y")
if format_date == excel_date:
cell_location = (i,1)
break
return [cell_location , excel_date]
def calc_countdown():
''' This function calculates the remaining time before the next prayer '''
#converts prayer times to datetime object
struc_prayertime_list = [datetime.strptime(i, "%I:%M %p") for i in azan_time]
#gets the current time and converts it to datetime object
current_time = datetime.strptime(datetime.strftime(datetime.now(), "%I:%M:%S %p"), "%I:%M:%S %p")
#gets the next prayer time
nearest_time = next((i for i in struc_prayertime_list if i > current_time), datetime.strptime('01-02 04:18 AM', "%m-%d %I:%M %p"))
#calculates the time left before next prayer, converts it to string and stores it in a variable
time_left_text.set("{} hours {} minutes {} seconds".format(*str(nearest_time - current_time).split(":")))
random_lbl.after(1000, calc_countdown)
#get time for different prayers
def fajr_time(cell_location):
fajr = worksheet.cell_value(cell_location[0][0],3)
return fajr
def zuhr_time(cell_location):
zuhr = worksheet.cell_value(cell_location[0][0],5)
return zuhr
def asr_time(cell_location):
asr = worksheet.cell_value(cell_location[0][0],6)
return asr
def maghrib_time(cell_location):
maghrib = worksheet.cell_value(cell_location[0][0],7)
return maghrib
def isha_time(cell_location):
isha = worksheet.cell_value(cell_location[0][0],8)
return isha
def update_time():
''' this function will run continuoulsy and its function is to keep updating the prayer times
as the day and date changes flow : get the correct cell_location using get_Date() --- set prayer times
using cell_location --- append prayer times(variables) to a list called azan_time--- return azan_time '''
cell_location = get_date(format_date)
#set prayer times
fajr = fajr_time(cell_location)
fajr="0"+fajr
zuhr = zuhr_time(cell_location)
asr = asr_time(cell_location)
maghrib = maghrib_time(cell_location)
isha = isha_time(cell_location)
#store prayer times in a list
azan_time = [fajr,zuhr,asr,maghrib,isha,"3:10 PM"]
#checks if any of the time is in PM. IF so, a '0' is added to the beginning
azan_time.remove(zuhr) #temporarily remove zuhr time
for x in range(0,len(azan_time)):
temp_time = azan_time[x]
if temp_time[-2]+temp_time[-1] == 'PM':
azan_time[x] = '0'+azan_time[x]
azan_time.insert(1,zuhr) # add zuhr time back
random_lbl.after(1000,update_time)
return azan_time #return azan time so it can be used
#function to check if it is time for prayer
def call_azan():
current_time = datetime.strftime(datetime.now(), "%I:%M %p")
for i in range(0,len(azan_time)):
if current_time == azan_time[i]:
print("time to pray at" , azan_time[i])
azan_path = os.path.join("azan caller","azan_sound.mp3")
playsound(azan_path)
else:
continue
random_lbl.after(1000,call_azan)
#GUI
window = tk.Tk()
window.title("Azan Caller")
Grid.rowconfigure(window, 0, weight=1)
Grid.columnconfigure(window, 0, weight=1)
#set up window
height = window.winfo_screenheight()
width = window.winfo_screenwidth()
window.geometry(f'{int(width/2)}x{int(height/2)}')
frm_window = tk.Frame(window,bg="#00BFFF")
frm_window.pack(fill="both",expand=True)
# a label just to run the functions continuously after 1 second
random_lbl = tk.Label(frm_window,width=2)
#create fonts
heading_font = font.Font(family = "ShareTech",size=25,weight='bold')
subheading_font = font.Font(family="ShareTech",size=14)
body_font = font.Font(family="ShareTech",size=10,weight="bold")
# title section
frm_title = tk.Frame(frm_window,relief=tk.SOLID,borderwidth=3,bg="#000000")
frm_title.grid(row=0, column=0, sticky="new",pady=(0,5))
lbl_title = tk.Label(master=frm_title, text="Azan Caller For Abu Dhabi",font=heading_font,fg="#008000")
lbl_title.pack(side='top',fill='x')
#prayer timings table
frm_table = tk.Frame(frm_window,bg="#000000",relief=tk.SOLID,borderwidth=3)
frm_table.grid(row=1,column=0, sticky="nsew",padx=(20,20))
tbl_title = tk.Label(frm_table,text="Today's Prayer Times",relief=tk.SOLID,font=subheading_font,borderwidth=2)
tbl_title.grid(row=0,column=0,columnspan=5,sticky="nsew")
#prayer names
prayer_names = ['Fajr','Zuhr','Asr','Maghrib','Isha']
for j in range(0,len(prayer_names)):
name = prayer_names[j]
cell = tk.Label(frm_table,text=name,relief=tk.SOLID,font=body_font,borderwidth=2)
cell.grid(row=1,column=j,sticky="nsew")
#prayer times
azan_time = update_time()
for i in range(0,len(azan_time)):
prayer_time = azan_time[i]
cell_time = tk.Label(frm_table,text=prayer_time,relief=tk.SOLID,font=body_font,borderwidth=2,fg="#FF8C00")
cell_time.grid(row=2,column=i,sticky="nsew")
#body section
frm_body = tk.Frame(frm_window,relief=tk.SOLID,borderwidth=5,)
frm_body.grid(row=2, column=0, sticky="nsew",pady=(10,10),padx=(20,20))
lbl_date = tk.Label(frm_body,text="Today's Date: ",font=body_font)
lbl_date.grid(row=0,column=0,sticky="nsew",pady=(0,5))
lbl_display_date = tk.Label(frm_body,font=body_font)
lbl_display_date.grid(row=0,column=1,sticky="nsew",pady=(0,5))
lbl_time = tk.Label(frm_body,text="Current Time: ",font=body_font)
lbl_time.grid(row=1,column=0,sticky="nsew",pady=(0,5))
lbl_display_time = tk.Label(frm_body,font=body_font)
lbl_display_time.grid(row=1,column=1,sticky="nsew",pady=(0,5))
time_left_text = tk.StringVar()
lbl_countdown = tk.Label(frm_body,text="Next Prayer in : ",font=body_font)
lbl_countdown.grid(row=2,column=0,sticky="nsew",pady=(0,5))
lbl_display_countdown = tk.Label(frm_body,textvariable=time_left_text,font=body_font,fg="red")
lbl_display_countdown.grid(row=2,column=1,sticky="nsew",pady=(0,5))
#footer
frm_footer = tk.Frame(frm_window,relief=tk.SOLID,borderwidth=3,bg="#000000")
frm_footer.grid(row=3, column=0, sticky="sew",pady=(10,0))
lbl_footer = tk.Label(frm_footer,text="#Copyright AbdulRahman Tijani 2020",font=body_font,fg="#008000")
lbl_footer.pack(side="bottom",fill='x')
#make the structure resizable
#columns
for i in range(frm_window.grid_size()[0]):
frm_window.grid_columnconfigure(i, weight=1)
for i in range(frm_table.grid_size()[0]):
frm_table.grid_columnconfigure(i, weight=1)
for i in range(frm_body.grid_size()[0]):
frm_body.grid_columnconfigure(i,weight=1)
#row
for i in range(frm_window.grid_size()[1]):
frm_window.grid_rowconfigure(i, weight=1)
for i in range(frm_table.grid_size()[1]):
frm_table.grid_rowconfigure(i, weight=1)
for i in range(frm_body.grid_size()[1]):
frm_body.grid_rowconfigure(i,weight=1)
#run functions
display_date()
display_time()
update_time()
call_azan()
calc_countdown()
window.mainloop()
Thank you in Advance
The problem here is because you have a file in your directory called random.py which is being imported here and python is reading that in and not the random module, so try not to name your script files as same as the module names.
And instead of using playsound, why dont you try the pygame module for playing sounds. Refer how to here
I am playing with an algorithm to optimally insert three vacation periods of a total of 30 days into a year calendar.
Sometimes it Works (I have not iterated for optimal yet) and sometimes I get an error: ValueError: cannot set a Timestamp with a non-timestamp
I cannot understand why it Works occasionally, but at other times it doesn't.
Full code is below. Just copy and run.
''' Program to find three periods of vacation of varying length that does not start in a weekend or holiday'''
from datetime import date
from random import randint, choice
import pandas as pd
from pandas.tseries.holiday import Holiday, AbstractHolidayCalendar
class Brazil(AbstractHolidayCalendar):
# Brazilian official holidays for 2018
rules = [Holiday('Universal', year=2018, month=1, day=1), Holiday('Carnaval', year=2018, month=2, day=12),
Holiday('Carnaval', year=2018, month=2, day=13), Holiday('Carnaval', year=2018, month=2, day=14),
Holiday('Paixão', year=2018, month=3, day=30), Holiday('Tiradentes', year=2018, month=4, day=21),
Holiday('Trabalho', year=2018, month=5, day=1), Holiday('Christi', year=2018, month=5, day=31),
Holiday('Independência', year=2018, month=9, day=7), Holiday('Aparecida', year=2018, month=10, day=12),
Holiday('Servidor', year=2018, month=10, day=28), Holiday('Finados', year=2018, month=11, day=2),
Holiday('República', year=2018, month=11, day=15), Holiday('Natal', year=2018, month=12, day=25)]
class Working:
# Initiates a calendar for 2018 as a pandas DataFrame. Includes holidays and weekends as 'not_working' = True
def __init__(self, start, end):
self.cal = Brazil()
self.df = pd.DataFrame()
self.df['date'] = pd.date_range(start=start, end=end)
self.holidays = self.cal.holidays(start=start, end=end)
self.df['not_working'] = self.df.date.apply(lambda x: x.dayofweek == 5 or x.dayofweek == 6
or x in self.holidays)
def total_working_days(self):
# Calculates total working days
print('Total working days this configuration is {} days'.format(sum(self.df['not_working'] == False)))
def apply_vacation(self, d, offset=0):
# Turns sequential number of days of 'not_working' into True
self.df.loc[self.df['date'] == d, 'not_working'] = True
if offset != 0:
for i in range(offset):
self.df.loc[self.df['date'] == (d + pd.Timedelta(days=(i + 1))), 'not_working'] = True
def find_starting_day(self):
# Finds a random 'not_working' day set to False which means a good day to start the vacation.
selected = choice(self.df['date']).date()
if self.df.loc[self.df['date'] == selected, 'not_working'].iloc[0] == True:
self.find_starting_day()
else:
print('Selected day for this vacation period start is: {}'.format(selected))
return selected
def schedule(self, pack):
# Distributes 30 days of vacation within three different periods
for each in pack:
d = self.find_starting_day()
self.apply_vacation(d, each)
def three_periods():
# Selects three periods that add up to 30 days
a = randint(1, 28)
b = randint(1, 29 - a)
c = 30 - a - b
print('Division of days is {}, {} and {}'.format(a, b, c))
return a, b, c
if "__main__" == __name__:
first_day = date(2018, 1, 1)
final_day = date(2018, 12, 31)
leisure = Working(first_day, final_day)
a, b, c = three_periods()
leisure.schedule((a, b, c))
leisure.total_working_days()
I am getting AttributeError: 'str' object has no attribute 'sleep' as specified in the title of this question and I cannot figure out why it is throwing that error message.
Countdown Timer.py
import time, datetime
Year = 2020
Month = 12
Day = 24
Hour = 23
Minute = 18
Second = 50
while True:
Datetime = datetime.datetime(Year, Month, Day, Hour, Minute, Second)
diff = Datetime - datetime.datetime.now()
diff = str(diff)
days, not_useful, time = diff.split()
Day1 = days + " " + "Day" # Day
print(Day1)
time.sleep(1)
That's because you locally erased the variable time that contained the module with a string. Here is a correct code:
import time, datetime
Year = 2020
Month = 12
Day = 24
Hour = 23
Minute = 18
Second = 50
while True:
Datetime = datetime.datetime(Year, Month, Day, Hour, Minute, Second)
diff = Datetime - datetime.datetime.now()
diff = str(diff)
days, not_useful, time_str = diff.split()
Day1 = days + " " + "Day" # Day
print(Day1)
time.sleep(1)
days, not_useful, time = diff.split()
here you will have 'time' as string. change verb name...
It's because you are using Time as a variable in your code:
time = diff.split()
and the above line is locally overwriting the variable timein the time-module.
Try using a different variable:
time_1 = diff.split()