Python · Lesson 14 of 15
JSON, Dates and the Standard Library
Read and write JSON, work with dates and durations, and reach for collections and pathlib.
- Intermediate
- 14 min read
- 3 objectives
Before this lessonLesson 13: Modules, Packages and pip
What you will learn
- Convert data to and from JSON
- Do date arithmetic
- Count and group with collections
Two things show up in almost every real project: exchanging data with other systems, and dealing with time. JSON is the near-universal data format of web APIs, and the datetime module handles dates without you counting days by hand. Both come with Python, so there is nothing to install.
What JSON looks like
JSON is text that describes data using objects (like Python dicts), arrays (lists), strings, numbers, booleans and null (Python's None). The json module converts between that text and Python objects. dumps turns a Python object into a JSON string; loads parses a JSON string back.
import json
user = {"id": 1, "name": "Ada", "admin": True, "tags": ["math", "code"], "manager": None}
text = json.dumps(user)
print(text)
back = json.loads(text)
print(back["tags"][0], back["manager"]){"id": 1, "name": "Ada", "admin": true, "tags": ["math", "code"], "manager": null}
math NonePretty printing and reading and writing files
Pass indent to make the output readable and sort_keys for a stable order. The file versions are json.dump and json.load (no trailing s), which take an open file.
import json
config = {"debug": False, "port": 8000, "hosts": ["a.example", "b.example"]}
print(json.dumps(config, indent=2, sort_keys=True)){
"debug": false,
"hosts": [
"a.example",
"b.example"
],
"port": 8000
}import json
with open("config.json", "w") as f:
json.dump(config, f, indent=2)
with open("config.json") as f:
loaded = json.load(f)
print(loaded["port"])Dates and times
date holds a day, datetime a day and a time, and timedelta a length of time. Subtracting two dates gives a timedelta, and adding one to a date moves it forward.
from datetime import date, datetime, timedelta
launch = date(2026, 3, 1)
today = date(2026, 1, 15)
print(launch - today)
print((launch - today).days)
print(today + timedelta(days=30))
print(today.weekday(), today.strftime("%A, %d %B %Y"))
meeting = datetime(2026, 1, 15, 9, 30)
print(meeting + timedelta(hours=2, minutes=15))45 days, 0:00:00 45 2026-02-14 3 Thursday, 15 January 2026 2026-01-15 11:45:00
Parsing and formatting
strftime formats a date as text using codes like %Y (year), %m (month) and %d (day). strptime does the reverse. For the standard ISO format use isoformat() and fromisoformat(), which is the safest thing to store or send.
from datetime import datetime
parsed = datetime.strptime("15/01/2026 18:45", "%d/%m/%Y %H:%M")
print(parsed)
print(parsed.isoformat())
print(parsed.strftime("%b %d, %Y at %I:%M %p"))
print(datetime.fromisoformat("2026-01-15T18:45:00").year)2026-01-15 18:45:00 2026-01-15T18:45:00 Jan 15, 2026 at 06:45 PM 2026
More standard-library helpers
collections.Counter counts things, defaultdict removes the "does this key exist yet?" check when grouping, and pathlib.Path is the modern way to build file paths without string gluing.
from collections import Counter, defaultdict
from pathlib import Path
votes = ["red", "blue", "red", "green", "red", "blue"]
print(Counter(votes).most_common())
by_length = defaultdict(list)
for word in ["kiwi", "fig", "plum", "pear", "lime"]:
by_length[len(word)].append(word)
print(dict(by_length))
p = Path("data") / "reports" / "2026.csv"
print(p.name, p.suffix, p.parent)[('red', 3), ('blue', 2), ('green', 1)]
{4: ['kiwi', 'plum', 'pear', 'lime'], 3: ['fig']}
2026.csv .csv data/reportsCommon mistakes
- Mixing up
dump/load(files) withdumps/loads(strings). - Forgetting that JSON object keys are always strings, so
{1: "a"}comes back as{"1": "a"}. - Comparing naive and time-zone-aware datetimes, which raises
TypeError. - Formatting dates by hand with string slicing instead of
strftime.
# Write your solution here
