Nanfeng

Notes on software development, code, and curious ideas

Building an End-of-Workday Countdown with Tkinter

Instead of repeatedly checking the clock, this small Tkinter utility displays the remaining time until the end of the workday.

Countdown application

The original script blocked the UI with a while loop and automatically shut down Windows after the timer finished. This version uses Tkinter’s after() scheduler and only displays a reminder, avoiding an unexpected destructive side effect.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from datetime import datetime, timedelta
import tkinter as tk
from tkinter import messagebox


class CountdownApp:
def __init__(self, root):
self.root = root
self.root.title("End-of-Workday Countdown")
self.root.geometry("430x280")
self.root.resizable(False, False)

tk.Label(root, text="Workday Countdown", font=("Arial", 20, "bold")).pack(pady=12)

self.current_label = tk.Label(root, font=("Arial", 13))
self.current_label.pack(pady=8)

time_row = tk.Frame(root)
time_row.pack(pady=8)
tk.Label(time_row, text="End time (HH:MM:SS):").pack(side=tk.LEFT)
self.end_time_entry = tk.Entry(time_row, width=10)
self.end_time_entry.insert(0, "18:00:00")
self.end_time_entry.pack(side=tk.LEFT, padx=8)

self.remaining_label = tk.Label(root, text="00:00:00", font=("Arial", 26))
self.remaining_label.pack(pady=16)

tk.Button(root, text="Start", command=self.start).pack()

self.target = None
self.update_clock()

def update_clock(self):
self.current_label.config(
text=datetime.now().strftime("Current time: %Y-%m-%d %H:%M:%S")
)
self.root.after(1000, self.update_clock)

def start(self):
try:
parsed = datetime.strptime(self.end_time_entry.get(), "%H:%M:%S").time()
except ValueError:
messagebox.showerror("Invalid time", "Use the HH:MM:SS format")
return

now = datetime.now()
self.target = datetime.combine(now.date(), parsed)
if self.target <= now:
self.target += timedelta(days=1)
self.update_countdown()

def update_countdown(self):
if self.target is None:
return

seconds = max(0, int((self.target - datetime.now()).total_seconds()))
hours, remainder = divmod(seconds, 3600)
minutes, seconds = divmod(remainder, 60)
self.remaining_label.config(text=f"{hours:02d}:{minutes:02d}:{seconds:02d}")

if hours == minutes == seconds == 0:
self.target = None
messagebox.showinfo("Reminder", "The countdown has finished")
else:
self.root.after(250, self.update_countdown)


root = tk.Tk()
CountdownApp(root)
root.mainloop()

If a shutdown action is genuinely required, make it a separate opt-in control with a visible confirmation and cancellation path rather than triggering it automatically.

+