Skip to main content

Chapter 19 - Keeping Time, Scheduling Tasks, and Launching Programs (Python)

Here's a concise but complete walkthrough of Chapter 19, following the chapter's structure with small examples.


time module

Epoch timestamp with time.time and human time with time.ctime

  • Unix epoch: midnight Jan 1, 1970 UTC.
  • time.time() → seconds since epoch as float (epoch timestamp).
  • time.ctime() → human-readable string for now, or for a given timestamp.
import time

now_ts = time.time()
print(now_ts) # e.g. 1773813875.35
print(time.ctime()) # 'Tue Mar 17 23:05:38 2026'
print(time.ctime(now_ts)) # same time as above

Profiling code with time.time

Measure elapsed time by subtracting timestamps before and after a block.

import time

def calculate_product():
product = 1
for i in range(1, 100001):
product *= i
return product

start_time = time.time()
result = calculate_product()
end_time = time.time()
print(f'It took {end_time - start_time} seconds to calculate.')

For deeper profiling, the chapter notes cProfile.run() (covered in another book).

Pausing with time.sleep

time.sleep(seconds) blocks the program for the given number of seconds.

import time

for i in range(3):
print('Tick')
time.sleep(1)
print('Tock')
time.sleep(1)

time.sleep(5) # extra pause

Project 14: Super Stopwatch

Goal: track lap times; user presses ENTER to mark laps, CTRL‑C to quit.

High-level steps:

  • Record start time and last lap time with time.time().
  • On ENTER, compute lap duration and total time, increment lap counter.
  • Handle KeyboardInterrupt so CTRL‑C exits cleanly.

Core structure (stopwatch.py):

# A simple stopwatch program
import time

print('Press ENTER to begin and to mark laps. Ctrl-C quits.')
input()
print('Started.')
start_time = time.time()
last_time = start_time
lap_number = 1

try:
while True:
input() # wait for ENTER
lap_time = round(time.time() - last_time, 2)
total_time = round(time.time() - start_time, 2)
print(f'Lap #{lap_number}: {total_time} ({lap_time})', end='')
lap_number += 1
last_time = time.time()
except KeyboardInterrupt:
print('\nDone.')

Ideas for similar programs: timesheet app, progress timers for downloads, cancelling long‑running tasks after a threshold.


datetime module

datetime objects: specific moments

datetime.datetime.now() → current date/time; datetime.datetime(...) → specific moment.

import datetime

now = datetime.datetime.now()
print(now) # datetime(2026, 2, 27, 11, 10, 49, 727297)

dt = datetime.datetime(2026, 10, 21, 16, 29, 0)
print(dt.year, dt.month, dt.day) # 2026 10 21
print(dt.hour, dt.minute, dt.second) # 16 29 0

Convert epoch timestamp to datetime:

import datetime, time

print(datetime.datetime.fromtimestamp(1000000)) # 1970-01-12 05:46:40
print(datetime.datetime.fromtimestamp(time.time())) # current moment

datetime.datetime.now() == datetime.datetime.fromtimestamp(time.time()) in effect.

Compare datetimes:

import datetime

halloween_2026 = datetime.datetime(2026, 10, 31, 0, 0, 0)
new_years_2027 = datetime.datetime(2027, 1, 1, 0, 0, 0)
oct_31_2026 = datetime.datetime(2026, 10, 31, 0, 0, 0)

print(halloween_2026 == oct_31_2026) # True
print(halloween_2026 > new_years_2027) # False
print(new_years_2027 > halloween_2026) # True

timedelta: durations

datetime.timedelta(...) represents a duration (not a moment).

import datetime

delta = datetime.timedelta(days=11, hours=10, minutes=9, seconds=8)
print(delta.days, delta.seconds, delta.microseconds) # 11 36548 0
print(delta.total_seconds()) # 986948.0
print(str(delta)) # '11 days, 10:09:08'

Date arithmetic:

now = datetime.datetime.now()
thousand_days = datetime.timedelta(days=1000)
print(now + thousand_days) # date 1000 days from now

More examples:

oct_21st = datetime.datetime(2026, 10, 21, 16, 29, 0)
about_thirty_years = datetime.timedelta(days=365 * 30)

print(oct_21st - about_thirty_years) # ~1996-10-28
print(oct_21st - 2 * about_thirty_years) # ~1966-11-05

Pausing until a specific date

Loop until now >= target datetime, with sleep to avoid busy‑waiting.

import datetime, time

halloween_2039 = datetime.datetime(2039, 10, 31, 0, 0, 0)
while datetime.datetime.now() < halloween_2039:
time.sleep(1)
# continue after Halloween 2039

Formatting datetimes with strftime

datetime.strftime(format) → string. Directives like %Y, %m, %d, %H, %M, %S, %B, %b, %A, %a, %p, etc.

import datetime

oct_21st = datetime.datetime(2026, 10, 21, 16, 29, 0)

print(oct_21st.strftime('%Y/%m/%d %H:%M:%S')) # '2026/10/21 16:29:00'
print(oct_21st.strftime('%I:%M %p')) # '04:29 PM'
print(oct_21st.strftime("%B of '%y")) # "October of '26"

Reference for directives: Table 19‑1 and strftime.org.

Parsing strings into datetimes with strptime

datetime.datetime.strptime(time_string, format) is inverse of strftime.

import datetime

print(datetime.datetime.strptime('October 21, 2026', '%B %d, %Y'))
# datetime(2026, 10, 21, 0, 0)

print(datetime.datetime.strptime('2026/10/21 16:29:00', '%Y/%m/%d %H:%M:%S'))
# datetime(2026, 10, 21, 16, 29)

print(datetime.datetime.strptime("October of '26", "%B of '%y"))
# datetime(2026, 10, 1, 0, 0)

print(datetime.datetime.strptime("November of '63", "%B of '%y"))
# datetime(2063, 11, 1, 0, 0)
print(datetime.datetime.strptime("November of '73", "%B of '%y"))
# datetime(1973, 11, 1, 0, 0)

%y covers years 1970–2069; '63 → 2063, '73 → 1973.

Review of Python time functions

Summary of types:

  • Epoch timestamp: float/int seconds since 1970‑01‑01.
  • datetime object: specific moment (year, month, day, hour, minute, second, microsecond).
  • timedelta object: duration.

Summary of key functions/methods (all covered above): time.time, time.sleep, datetime.datetime(...), datetime.datetime.now, datetime.datetime.fromtimestamp, datetime.timedelta, timedelta.total_seconds, datetime.strftime, datetime.datetime.strptime.


Launching programs with subprocess

subprocess.run

Launches another program and waits for it to finish.

Windows:

import subprocess
subprocess.run(['C:\\Windows\\System32\\calc.exe'])

Ubuntu:

import subprocess
subprocess.run(['/usr/bin/gnome-calculator'])

macOS:

import subprocess
subprocess.run(['open', '/System/Applications/Calculator.app'])

Returns a CompletedProcess with .args and .returncode (0 = success).

subprocess.Popen (non‑blocking)

Popen starts a process and immediately returns a Popen object; your script continues while the other program runs.

import subprocess

calc_proc = subprocess.Popen(['C:\\Windows\\System32\\calc.exe'])

print(calc_proc.poll() == None) # True while running
exit_code = calc_proc.wait() # blocks until program exits
print(exit_code)
print(calc_proc.poll()) # exit code (e.g., 0)

Notes:

  • On newer Windows, calc.exe is a stub that launches the real app then exits, so wait() may return immediately even though the GUI stays open.
  • kill() terminates a launched process immediately (no "Save?" prompts):
paint_proc = subprocess.Popen('C:\\Windows\\System32\\mspaint.exe')
paint_proc.kill()

Passing command line arguments to launched processes

Arguments go after the executable in the list.

Example (Windows):

import subprocess

subprocess.run([
'C:\\Windows\\notepad.exe',
'C:\\Users\\Al\\hello.txt'
])

hello.txt opens directly in Notepad. sys.argv of that program sees those arguments.

Capturing output from commands

Use capture_output=True and text=True with run().

import subprocess

proc = subprocess.run(
['ping', '-n', '4', 'nostarch.com'], # on macOS/Linux use '-c'
capture_output=True,
text=True,
)
print(proc.stdout)

proc.stdout is a string containing the command's standard output; you can parse it in your script.

Scheduling with OS tools

Mentions OS schedulers:

  • Windows: Task Scheduler.
  • macOS: launchd.
  • Linux: cron.

Use these to run your Python scripts at specific times instead of writing your own long‑running loop. For short waits within a script, a loop + time.sleep(1) is fine.

Opening files with default applications

Use OS utilities (start on Windows, open on macOS/Linux) via subprocess.run to mimic double‑clicking a file.

# Create file
file_obj = open('hello.txt', 'w', encoding='utf-8')
file_obj.write('Hello, world!')
file_obj.close()

import subprocess
# Windows
subprocess.run(['start', 'hello.txt'], shell=True)
# macOS/Linux
# subprocess.run(['open', 'hello.txt'])

The OS picks the associated app (e.g., Notepad/TextEdit).


Project 15: Simple Countdown

Goal: display a numeric countdown with 1‑second pauses, then play a sound or open something at the end.

Step 1: Countdown loop

# simplecountdown.py
import time, subprocess

time_left = 60
while time_left > 0:
print(time_left)
time.sleep(1)
time_left -= 1
# TODO: play sound/open file

Step 2: Play sound or open something

Use subprocess.run with start / open to play alarm.wav with default audio player.

# At the end of the countdown, play a sound file.
# Windows:
# subprocess.run(['start', 'alarm.wav'], shell=True)
# macOS/Linux:
# subprocess.run(['open', 'alarm.wav'])

You can instead open a text file (popup message) or a website with webbrowser.open().

Ideas for similar programs: "press CTRL‑C to cancel within N seconds" confirmation dialogs, timed reminders, scheduled file operations using sleep + subprocess.


Overall idea of the chapter

Chapter 19 covers time handling (time.time for timestamps, time.sleep for pausing, time.ctime for human-readable time), the datetime module (creating moments, durations with timedelta, formatting with strftime, parsing with strptime), and launching external programs (subprocess.run for blocking, subprocess.Popen for non-blocking, capturing output, opening files with default apps). OS schedulers (Task Scheduler, launchd, cron) handle recurring tasks.