From 63ef38e43e682e4bcb78fde885b3d27d1541776e Mon Sep 17 00:00:00 2001 From: KaisAbiyyi Date: Thu, 11 Jun 2026 05:40:24 +0700 Subject: [PATCH 1/2] fix: count days in duration parser --- README.md | 1 + duration_utils.py | 4 +++- tests/test_duration_utils.py | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 53fd498..b438413 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A tiny, dependency-free parser for human-friendly duration strings. from duration_utils import parse_duration parse_duration("1h30m") # 5400 +parse_duration("2d4h") # 187200 parse_duration("1w") # 604800 ``` diff --git a/duration_utils.py b/duration_utils.py index ee515c6..71e92e0 100644 --- a/duration_utils.py +++ b/duration_utils.py @@ -4,9 +4,10 @@ import re -# Seconds per unit. Supported: weeks, hours, minutes, seconds. +# Seconds per unit. Supported: weeks, days, hours, minutes, seconds. _UNITS = { "w": 604800, + "d": 86400, "h": 3600, "m": 60, "s": 1, @@ -20,6 +21,7 @@ def parse_duration(text: str) -> int: Examples: parse_duration("1h30m") -> 5400 + parse_duration("2d4h") -> 187200 parse_duration("1w") -> 604800 Raises ValueError on empty or malformed input. diff --git a/tests/test_duration_utils.py b/tests/test_duration_utils.py index b259480..cb12194 100644 --- a/tests/test_duration_utils.py +++ b/tests/test_duration_utils.py @@ -16,9 +16,18 @@ def test_seconds(self): def test_weeks(self): self.assertEqual(parse_duration("1w"), 604800) + def test_days(self): + self.assertEqual(parse_duration("1d"), 86400) + def test_combined(self): self.assertEqual(parse_duration("1h30m"), 5400) + def test_days_combined_with_hours(self): + self.assertEqual(parse_duration("2d4h"), 187200) + + def test_all_supported_units_combined(self): + self.assertEqual(parse_duration("1w2d3h4m5s"), 788645) + def test_invalid_raises(self): with self.assertRaises(ValueError): parse_duration("abc") From e1106f38be801f7900ae440889bd8ea7eaf9aedb Mon Sep 17 00:00:00 2001 From: KaisAbiyyi Date: Sat, 13 Jun 2026 01:56:05 +0700 Subject: [PATCH 2/2] Validate unsupported duration units --- duration_utils.py | 7 ++++--- tests/test_duration_utils.py | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/duration_utils.py b/duration_utils.py index 71e92e0..90f44da 100644 --- a/duration_utils.py +++ b/duration_utils.py @@ -13,7 +13,7 @@ "s": 1, } -_TOKEN = re.compile(r"(\d+)([wdhms])") +_TOKEN = re.compile(r"(\d+)([a-z]+)") def parse_duration(text: str) -> int: @@ -34,8 +34,9 @@ def parse_duration(text: str) -> int: consumed = 0 for m in _TOKEN.finditer(text): value, unit = int(m.group(1)), m.group(2) - if unit in _UNITS: - total += value * _UNITS[unit] + if unit not in _UNITS: + raise ValueError(f"unsupported duration unit: {unit!r}") + total += value * _UNITS[unit] consumed += len(m.group(0)) if consumed != len(text): diff --git a/tests/test_duration_utils.py b/tests/test_duration_utils.py index cb12194..210c9ea 100644 --- a/tests/test_duration_utils.py +++ b/tests/test_duration_utils.py @@ -32,6 +32,10 @@ def test_invalid_raises(self): with self.assertRaises(ValueError): parse_duration("abc") + def test_unsupported_unit_raises(self): + with self.assertRaisesRegex(ValueError, "unsupported duration unit"): + parse_duration("1x") + def test_empty_raises(self): with self.assertRaises(ValueError): parse_duration("")