python
31 lines · 8 steps
Parsing duration strings like 1h30m in Python
A regex scanner turns compact duration strings into a total number of seconds while rejecting malformed input.
Explained by
highlit
1import re
2
3_UNIT_SECONDS = {
4 "w": 604800,
5 "d": 86400,
6 "h": 3600,
7 "m": 60,
8 "s": 1,
9}
10
11_TOKEN = re.compile(r"(\d+)([wdhms])")
12
13
14def parse_duration(value: str) -> int:
15 text = value.strip().lower()
16 if not text:
17 raise ValueError("empty duration string")
18
19 pos = 0
20 total = 0
21 for match in _TOKEN.finditer(text):
22 if match.start() != pos:
23 raise ValueError(f"unexpected token near {text[pos:]!r}")
24 amount, unit = match.groups()
25 total += int(amount) * _UNIT_SECONDS[unit]
26 pos = match.end()
27
28 if pos != len(text):
29 raise ValueError(f"invalid duration: {value!r}")
30
31 return total
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A lookup table maps units to a common base so each token contributes cleanly to one total.
- 2Tracking the match position lets a regex scanner detect gaps and reject unexpected characters.
- 3Validating that the scan reached the end of the string catches trailing junk the pattern skipped.
Related explainers
python
from collections import ChainMap from functools import reduce from typing import Any, Iterable, Mapping
Five ways to merge dicts in Python
dictionaries
merging
recursion
Intermediate
8 steps
php
<?php namespace App\Http\Controllers\Auth;
Rate-limited login in Laravel
authentication
rate-limiting
validation
Intermediate
9 steps
javascript
function validateSignup({ email, password, confirmPassword, username, age }) { const errors = {}; if (!email) {
Building a signup validator in JavaScript
validation
regex
guard-clauses
Beginner
7 steps
python
from fastapi import Depends, FastAPI, HTTPException from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker
Wiring SQLAlchemy sessions into FastAPI
dependency-injection
orm
sessions
Intermediate
7 steps
ruby
class EmailValidator < ActiveModel::EachValidator EMAIL_FORMAT = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\z/i def validate_each(record, attribute, value)
Writing a custom email validator in Rails
validation
regex
custom validators
Intermediate
7 steps
javascript
const { validationResult, matchedData } = require('express-validator'); function validate(schema) { const runners = schema.map((rule) => rule.run.bind(rule));
A reusable validation middleware in Express
middleware
validation
higher-order-functions
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/parsing-duration-strings-like-1h30m-in-python-explained-python-1e10/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.