From 8b6f0b24e269f9ec6e124680988f72b1a481f49a Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Thu, 28 May 2026 13:19:23 +0200 Subject: [PATCH] Add date_format config key for csv command - Add get_date_format() to config.py: reads [csv] date_format, returns None when absent (falls back to the default %d/%m/%y) - _cmd_csv applies the format to both single-day and weekly date strings - Add 3 tests for get_date_format in TestGetters - Update timesheets.example.toml and README with [csv] date_format key --- README.md | 3 +++ src/timesheets/cli.py | 11 ++++++++--- src/timesheets/config.py | 5 +++++ tests/test_config.py | 10 ++++++++++ timesheets.example.toml | 3 +++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0355d6..34da466 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ map = "/path/to/project_map.json" [work] daily_hours = 8.0 weekly_hours = 40.0 + +[csv] +date_format = "%d/%m/%y" # default; any strftime format string ``` Priority order: **CLI flag > config file > environment variable > default**. diff --git a/src/timesheets/cli.py b/src/timesheets/cli.py index 1d56381..8de634f 100644 --- a/src/timesheets/cli.py +++ b/src/timesheets/cli.py @@ -6,6 +6,7 @@ from datetime import date from .config import ( find_default_config, get_daily_target, + get_date_format, get_map_path, get_token, get_weekly_target, @@ -422,6 +423,10 @@ def _cmd_stories(args: argparse.Namespace, config: dict) -> None: def _cmd_csv(args: argparse.Namespace, config: dict) -> None: target_date, date_str = _resolve_date(args) project_map = _resolve_project_map(args, config) + date_fmt = get_date_format(config) + + def _fmt(d: date) -> str: + return d.strftime(date_fmt) if date_fmt else format_date(d) if args.weekly: day_sections_raw = _resolve_week_sections(args, config, target_date) @@ -430,7 +435,7 @@ def _cmd_csv(args: argparse.Namespace, config: dict) -> None: return day_sections = [ ( - format_date(day), + _fmt(day), to_csv_entries(rows) if args.raw else aggregate_rows(rows), ) for day, rows in day_sections_raw @@ -448,10 +453,10 @@ def _cmd_csv(args: argparse.Namespace, config: dict) -> None: entries = to_csv_entries(rows) if args.raw else aggregate_rows(rows) if args.output: with open(args.output, "w", newline="", encoding="utf-8") as f: - write_csv(entries, f, date_str, project_map) + write_csv(entries, f, _fmt(target_date), project_map) print(f"Written to {args.output}", file=sys.stderr) else: - write_csv(entries, sys.stdout, date_str, project_map) + write_csv(entries, sys.stdout, _fmt(target_date), project_map) # --------------------------------------------------------------------------- diff --git a/src/timesheets/config.py b/src/timesheets/config.py index e097f4d..664d2af 100644 --- a/src/timesheets/config.py +++ b/src/timesheets/config.py @@ -54,6 +54,11 @@ def get_map_path(config: dict) -> str | None: return config.get("projects", {}).get("map") +def get_date_format(config: dict) -> str | None: + """Extract csv.date_format from config, or None to use the default.""" + return config.get("csv", {}).get("date_format") + + def get_daily_target(config: dict) -> float: """Extract work.daily_hours from config, defaulting to 8.0.""" return float(config.get("work", {}).get("daily_hours", 8.0)) diff --git a/tests/test_config.py b/tests/test_config.py index aa46dd4..7e14c55 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,6 +6,7 @@ import pytest from timesheets.config import ( DEFAULT_CONFIG_FILENAME, find_default_config, + get_date_format, get_map_path, get_token, load_config, @@ -86,3 +87,12 @@ class TestGetters: def test_get_map_path_missing_key(self): assert get_map_path({"projects": {}}) is None + + def test_get_date_format_present(self): + assert get_date_format({"csv": {"date_format": "%Y-%m-%d"}}) == "%Y-%m-%d" + + def test_get_date_format_missing_section(self): + assert get_date_format({}) is None + + def test_get_date_format_missing_key(self): + assert get_date_format({"csv": {}}) is None diff --git a/timesheets.example.toml b/timesheets.example.toml index b29d563..6ee008a 100644 --- a/timesheets.example.toml +++ b/timesheets.example.toml @@ -7,3 +7,6 @@ map = "/path/to/project_map.json" [work] daily_hours = 8.0 weekly_hours = 40.0 + +[csv] +# date_format = "%Y-%m-%d" # default is "%d/%m/%y" (e.g. 28/05/26)