feat: set up modularized version of project with testing
This commit is contained in:
commit
7bea08ddac
19 changed files with 1138 additions and 0 deletions
44
src/timesheets/utils.py
Normal file
44
src/timesheets/utils.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import re
|
||||
from datetime import date
|
||||
|
||||
|
||||
def parse_duration(duration_str: str) -> float:
|
||||
"""Convert HH:MM duration string to decimal hours."""
|
||||
duration_str = duration_str.strip()
|
||||
match = re.match(r"^(\d+):(\d{2})$", duration_str)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid duration format: {duration_str!r}")
|
||||
return int(match.group(1)) + int(match.group(2)) / 60.0
|
||||
|
||||
|
||||
def duration_from_start_end(start_str: str, end_str: str) -> float:
|
||||
"""Calculate duration in decimal hours from two HH:MM time strings."""
|
||||
|
||||
def to_minutes(t: str) -> int:
|
||||
match = re.match(r"^(\d+):(\d{2})$", t.strip())
|
||||
if not match:
|
||||
raise ValueError(f"Invalid time format: {t!r}")
|
||||
return int(match.group(1)) * 60 + int(match.group(2))
|
||||
|
||||
start_minutes = to_minutes(start_str)
|
||||
end_minutes = to_minutes(end_str)
|
||||
if end_minutes < start_minutes:
|
||||
end_minutes += 24 * 60 # midnight rollover
|
||||
return (end_minutes - start_minutes) / 60.0
|
||||
|
||||
|
||||
def decimal_to_hhmm(hours: float) -> str:
|
||||
"""Convert decimal hours to a HH:MM string."""
|
||||
total_minutes = round(hours * 60)
|
||||
h, m = divmod(total_minutes, 60)
|
||||
return f"{h:02d}:{m:02d}"
|
||||
|
||||
|
||||
def strip_markdown_link(text: str) -> str:
|
||||
"""Strip markdown link syntax [label](url), keeping only the label."""
|
||||
return re.sub(r"\[([^\]]+)\]\([^)]*\)", r"\1", text)
|
||||
|
||||
|
||||
def format_date(d: date) -> str:
|
||||
"""Format date as DD/MM/YY."""
|
||||
return d.strftime("%d/%m/%y")
|
||||
Loading…
Add table
Add a link
Reference in a new issue