Skip to content

Basic Alarm Clock

An alarm clock teaches a deceptively rich set of concepts in a small amount of code: parsing user input that represents a time, comparing the current time against a target, looping until that target is reached, and triggering an external effect (sound) once it is. In this project you will build a command-line alarm clock that lets the user enter a 24-hour-format time and waits until exactly that moment to play an alert.

Along the way you will learn:

  • How Python represents time with the datetime and time modules.
  • The polling pattern: “do something until a condition is true.”
  • How to play sounds across platforms.
  • How to validate human-friendly input.
  • How a one-shot alarm grows into a scheduler with snooze, multiple alarms, and persistence.
  • Python 3.6 or above.
  • A text editor or IDE.
  • A working speaker. (Headphones if a 3 AM alarm test would disturb anyone.)
  • Familiarity with running scripts from the terminal.
ConceptPurpose
datetimeGet the current date and time, format it as text, parse text back into a time object.
time.sleep(seconds)Pause execution. Used so we do not check the clock millions of times per second.
winsound / playsound / pygame.mixerMake noise when the alarm fires. Choice depends on your OS.
String formatting (strftime)Turn a datetime object into a string like "14:30:00".
Polling loopA while True loop that wakes periodically and checks whether the alarm time has arrived.
  1. Create a folder named basic-alarm-clock.
  2. Inside it, create basicalarmclock.py.
  3. (Optional) drop a custom alarm.wav file in the folder to use as the alert sound.
Basic Alarm Clock pch.viewSource
Basic Alarm Clock
# Basic Alarm Clock

# Importing the libraries
import datetime
import time
import winsound

# Defining the alarm function
def alarm(Timing):
    altime = str(datetime.datetime.now().strptime(Timing,"%I:%M %p"))
    altime = altime[11:-3]
    print(altime)
    Horeal = altime[:2]
    Horeal = int(Horeal)
    Mireal = altime[3:5]
    Mireal = int(Mireal)
    print(f"Done, alarm is set for {Timing}")
    while True:
        if Horeal  == datetime.datetime.now().hour:
            if Mireal == datetime.datetime.now().minute:
                print("Alarm is running")
                winsound.PlaySound('abc',winsound.SND_LOOP)
            
            elif Mireal<datetime.datetime.now().minute:
                break
            
# Taking user input
print("Set a time to alarm(HH:MM AM/PM)")
Alarm_Time = input("Enter the time of alarm to be set: ")
alarm(Alarm_Time)
command
C:\Users\username\Documents\basic-alarm-clock> python basicalarmclock.py
Enter the time of alarm to be set (HH:MM:SS, 24-hour): 14:30:00
Alarm is set for 14:30:00
Waiting for alarm time...
*Alarm sound plays*
Wake Up! Wake Up!

💡 To test without waiting hours, set the alarm one minute into the future.

Read from the top: this is what runs when you execute the file, and which function calls which. It is generated from the code, so it cannot drift from it.

diagram Diagram mermaid
basicalarmclock.py
import datetime
import time
import winsound        # Windows only — see "Cross-platform sound" below
  • datetime gives you datetime.datetime.now(), which returns the current local date and time.
  • time gives you time.sleep(seconds) for pausing.
  • winsound plays a .wav file with one call. It only works on Windows. macOS and Linux need a different approach.
basicalarmclock.py
alarm_time = input("Enter the time of alarm (HH:MM:SS, 24-hour): ")
print(f"Alarm is set for {alarm_time}")

Using 24-hour format (14:30:00 instead of 2:30:00 PM) is the simplest choice: it avoids ambiguity, and strftime("%H:%M:%S") produces the same format directly.

basicalarmclock.py
while True:
    now = datetime.datetime.now().strftime("%H:%M:%S")
    if now == alarm_time:
        print("Wake Up! Wake Up!")
        winsound.PlaySound("alarm.wav", winsound.SND_ASYNC)
        break
    time.sleep(1)
  • datetime.datetime.now() returns a full date+time object.
  • .strftime("%H:%M:%S") formats it as HH:MM:SS (zero-padded).
  • The comparison is a string equality check — both sides are strings in the same format.
  • winsound.SND_ASYNC plays the sound in the background so the next print is not delayed.
  • time.sleep(1) is the key to making this loop efficient. Without it, Python would check the clock millions of times per second and pin a CPU core.

If the alarm is set for 14:30:00, we have exactly one second during which the time string equals "14:30:00". Sleeping for more than a second could cause us to skip past it entirely. One second is the right balance.

winsound only exists on Windows. For a program that works everywhere, use playsound (any OS) or pygame.mixer:

install
pip install playsound==1.2.2
cross_platform.py
from playsound import playsound
playsound("alarm.wav")

Or with Pygame:

pygame_sound.py
from pygame import mixer
mixer.init()
mixer.music.load("alarm.wav")
mixer.music.play()

If you have no .wav file handy, beep the terminal:

beep.py
print("\a")          # ASCII bell — terminal may flash or beep

The basic version accepts any string. A malformed value like "14:30" (missing seconds) silently fails — the loop just never matches. Validate up front:

validate.py
from datetime import datetime
 
while True:
    raw = input("Enter alarm time (HH:MM:SS): ")
    try:
        alarm_dt = datetime.strptime(raw, "%H:%M:%S")
        break
    except ValueError:
        print("Bad format. Use HH:MM:SS, for example 07:30:00.")

strptime parses the string into a real datetime object and raises ValueError if the format is wrong. Once you have a datetime, you can compare numerically instead of by string.

The polling pattern is fine for short waits. For long waits, it is cleaner to compute exactly how many seconds away the alarm is and sleep that long:

single_sleep.py
from datetime import datetime, timedelta
 
target = datetime.strptime(input("Time HH:MM:SS: "), "%H:%M:%S").time()
now = datetime.now()
alarm_dt = now.replace(hour=target.hour, minute=target.minute,
                       second=target.second, microsecond=0)
if alarm_dt <= now:
    alarm_dt += timedelta(days=1)    # next day if the time already passed
seconds = (alarm_dt - now).total_seconds()
print(f"Sleeping for {seconds:.0f} seconds...")
time.sleep(seconds)
print("Wake Up!")

This:

  • Handles next-day alarms automatically (e.g., set 06:00 at midnight).
  • Sleeps a single, precise interval instead of waking every second.
  • Uses one clear datetime object rather than two strings to compare.
ProblemCauseFix
Alarm never triggersMismatched format ("2:30:00" vs "02:30:00")Use strptime validation; require zero-padding
100 % CPU spikeForgot time.sleep(1)Always sleep inside polling loops
ModuleNotFoundError: No module named 'winsound' on Mac/Linuxwinsound is Windows-onlyUse playsound or pygame.mixer
Sound plays once then silenceSND_ASYNC returns immediately — script then exitsLoop the sound or time.sleep after triggering
Alarm fires twice the same secondLoop did not break after matchAdd break after firing

After the alarm fires, ask the user:

snooze.py
choice = input("Snooze 5 minutes? (y/n): ")
if choice.lower() == "y":
    time.sleep(5 * 60)
    fire_alarm()

Keep a list of alarm times. Sort, then sleep until the soonest:

multi.py
alarms = sorted({"06:30:00", "07:00:00", "07:15:00"})
for a in alarms:
    wait_until(a)
    fire_alarm()
    print(f"Alarm at {a} fired.")

Let the user attach a label: “Take medicine — 14:30” — show it on trigger.

Save alarms to a JSON file so they survive restarts.

persist.py
import json
alarms = json.loads(Path("alarms.json").read_text())

Build a Tkinter window with time-entry fields, a list of pending alarms, and a snooze button. See Simple Reminder App for a similar pattern.

Use the schedule library:

recur.py
import schedule
schedule.every().day.at("07:00").do(fire_alarm)
while True:
    schedule.run_pending()
    time.sleep(30)

On Windows use plyer; on macOS use osascript. Combine with sound for a full desktop alert.

  • Personal wake-up alarm or pomodoro timer.
  • Reminder for medication, meetings, calls.
  • Trigger automation scripts at a specific time (lights, backups, downloads).
  • Build the timing core of a meditation or workout app.
  • Server-side cron alternative for tasks that need a specific local time.
  • 24-hour time format input.
  • Real-time monitoring with a polling loop.
  • Audio alert via winsound.
  • Automatic termination once the alarm fires.
  • Simple, distraction-free CLI.

This project teaches:

  • Working with timedatetime, strftime, strptime, timedelta.
  • Loop control — polling with time.sleep.
  • OS-specific code — recognizing when a module only works on one platform.
  • Input validation — converting and validating user input early.
  • Trade-offs — polling versus single-sleep, simple versus precise.
  • Replace winsound with a cross-platform library so it runs on Mac/Linux.
  • Add a Tkinter GUI with multiple slots, on/off switches, and snooze.
  • Schedule daily recurring alarms with the schedule library.
  • Combine with a TTS library (pyttsx3) to have the alarm read out a message.
  • Persist alarms across restarts in a JSON or SQLite file.
  • Wrap as a Windows Service or macOS LaunchAgent so it runs at boot.

Here’s a live analog clock — the hands track the current time, the same value your code reads from datetime.now() each tick:

sketch A live analog clock p5.js
The hour, minute, and second hands track the current time, updating every second.

You built a working alarm clock and saw two ways to wait for a target time — polling and single-sleep — each with its own trade-offs. The same patterns (polling loop, time formatting, input validation) appear in scheduled-task tools, monitoring scripts, and game timers. Source on GitHub. Explore more beginner projects on Python Central Hub.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading