Introduction
A digital clock is the smallest possible live-updating GUI — and that's exactly why it's worth building. The challenge isn't showing the time; it's *re-showing it every second* inside Tkinter's event loop, without freezing the window. The answer is the after() method, Tkinter's gentle timer, and it is the same scheduling idea behind the Pomodoro timer's autorefresh.
Fifty lines get you a resizable, always-on-top clock with 12/24-hour toggle and the current date.
Features
Prerequisites
sudo apt install python3-tk on Ubuntu).Step 1: Create the Script
Save as digital_clock.py:
import tkinter as tk
from datetime import datetime
class DigitalClock:
def __init__(self, root):
self.root = root
self.root.title("Digital Clock")
self.root.attributes("-topmost", True)
self.root.configure(bg="#0e1117")
self.use_24h = tk.BooleanVar(value=True)
self.time_label = tk.Label(
root, text="", font=("Consolas", 64, "bold"),
fg="#10b981", bg="#0e1117",
)
self.time_label.pack(expand=True)
self.date_label = tk.Label(
root, text="", font=("Arial", 14),
fg="#9ca3af", bg="#0e1117",
)
self.date_label.pack(pady=(0, 10))
tk.Checkbutton(
root, text="24-hour", variable=self.use_24h,
command=self.tick, bg="#0e1117", fg="#9ca3af",
selectcolor="#0e1117", activebackground="#0e1117",
).pack(pady=(0, 8))
self.root.bind("<Configure>", self.rescale)
self.tick()
def rescale(self, event):
if event.widget == self.root:
size = max(24, min(120, event.width // 7))
self.time_label.config(font=("Consolas", size, "bold"))
def tick(self):
now = datetime.now()
fmt = "%H:%M:%S" if self.use_24h.get() else "%I:%M:%S %p"
self.time_label.config(text=now.strftime(fmt))
self.date_label.config(text=now.strftime("%A, %B %d, %Y"))
self.root.after(1000, self.tick)
if __name__ == "__main__":
root = tk.Tk()
DigitalClock(root)
root.mainloop()Step 2: Run the App
python digital_clock.pyThe clock appears and ticks every second. Toggle the format, resize the window — the font follows.
How It Works
The entire app hangs on one line: self.root.after(1000, self.tick). It tells Tkinter: *call tick again in 1000 milliseconds* — and tick reschedules itself at the end, creating an infinite, non-blocking loop inside the event loop. This is the desktop equivalent of the countdown timer's autorefresh, and the crucial contrast is with time.sleep(1000), which would freeze the entire window — no toggling, no dragging, no closing.
Format switching is a strftime pattern swap: %H:%M:%S for 24-hour, %I:%M:%S %p for 12-hour with AM/PM. The toggle's command=self.tick re-renders immediately rather than waiting up to a full second for the next tick — instant feedback for one line of extra code.
The rescale binding watches <Configure> events (resize/move) and maps window width to font size, clamped between 24 and 120. The event.widget == self.root check is the subtle bit — Configure events fire for *every child widget too*, and without the guard the font would flicker on unrelated resizes.
Common Errors & Fixes
tick recursively without after, or used time.sleep; only after() keeps the event loop alive.after(1000) measures from the end of the previous tick; for perfect accuracy, compute the delay to the *next* second boundary: after(1000 - now.microsecond // 1000, self.tick).fg, bg, selectcolor, and activebackground set, as the code does.Key Concepts
after pattern for continuous updates.What to Try Next
datetime.now(timezone(timedelta(hours=n))).root.bell().attributes("-fullscreen", True).FAQ
Why not just print the time in a terminal loop?
You can — but then you have a script, not an app. The point of this project is the GUI update pattern, which transfers to every Tkinter program you'll write.
Does after(1000) guarantee exactly one second?
It guarantees *at least* 1000ms — the callback runs when the event loop gets to it. For a clock, the display re-reading datetime.now() each tick keeps the time correct regardless of small delays.
Can I make the background transparent?
On Windows, root.attributes("-transparentcolor", "#0e1117") works; macOS and Linux support varies. It's a fun trick with portability caveats.