diff options
-rw-r--r-- | overlays/worktime/default.nix | 2 | ||||
-rwxr-xr-x | overlays/worktime/worktime.py | 68 |
2 files changed, 51 insertions, 19 deletions
diff --git a/overlays/worktime/default.nix b/overlays/worktime/default.nix index 26e1dfed..ab6fb40a 100644 --- a/overlays/worktime/default.nix +++ b/overlays/worktime/default.nix | |||
@@ -5,7 +5,7 @@ final: prev: { | |||
5 | 5 | ||
6 | phases = [ "buildPhase" "installPhase" ]; | 6 | phases = [ "buildPhase" "installPhase" ]; |
7 | 7 | ||
8 | python = prev.python37.withPackages (ps: with ps; [pyxdg dateutil uritools requests configparser]); | 8 | python = prev.python39.withPackages (ps: with ps; [pyxdg dateutil uritools requests configparser tabulate]); |
9 | 9 | ||
10 | buildPhase = '' | 10 | buildPhase = '' |
11 | substituteAll $src worktime | 11 | substituteAll $src worktime |
diff --git a/overlays/worktime/worktime.py b/overlays/worktime/worktime.py index 9e514e65..b9af430a 100755 --- a/overlays/worktime/worktime.py +++ b/overlays/worktime/worktime.py | |||
@@ -22,6 +22,10 @@ import argparse | |||
22 | 22 | ||
23 | from copy import deepcopy | 23 | from copy import deepcopy |
24 | 24 | ||
25 | import sys | ||
26 | |||
27 | from tabulate import tabulate | ||
28 | |||
25 | class TogglAPISection(Enum): | 29 | class TogglAPISection(Enum): |
26 | TOGGL = '/api/v8' | 30 | TOGGL = '/api/v8' |
27 | REPORTS = '/reports/api/v2' | 31 | REPORTS = '/reports/api/v2' |
@@ -100,6 +104,36 @@ class Worktime(object): | |||
100 | time_to_work = None | 104 | time_to_work = None |
101 | force_day_to_work = True | 105 | force_day_to_work = True |
102 | 106 | ||
107 | @staticmethod | ||
108 | def holidays(year): | ||
109 | holidays = dict() | ||
110 | |||
111 | y_easter = datetime.combine(easter(year), time(), tzinfo=tzlocal()) | ||
112 | |||
113 | # Legal holidays in munich, bavaria | ||
114 | holidays[datetime(year, 1, 1, tzinfo=tzlocal()).date()] = 1 | ||
115 | holidays[datetime(year, 1, 6, tzinfo=tzlocal()).date()] = 1 | ||
116 | holidays[(y_easter+timedelta(days=-2)).date()] = 1 | ||
117 | holidays[(y_easter+timedelta(days=+1)).date()] = 1 | ||
118 | holidays[datetime(year, 5, 1, tzinfo=tzlocal()).date()] = 1 | ||
119 | holidays[(y_easter+timedelta(days=+39)).date()] = 1 | ||
120 | holidays[(y_easter+timedelta(days=+50)).date()] = 1 | ||
121 | holidays[(y_easter+timedelta(days=+60)).date()] = 1 | ||
122 | holidays[datetime(year, 8, 15, tzinfo=tzlocal()).date()] = 1 | ||
123 | holidays[datetime(year, 10, 3, tzinfo=tzlocal()).date()] = 1 | ||
124 | holidays[datetime(year, 11, 1, tzinfo=tzlocal()).date()] = 1 | ||
125 | holidays[datetime(year, 12, 25, tzinfo=tzlocal()).date()] = 1 | ||
126 | holidays[datetime(year, 12, 26, tzinfo=tzlocal()).date()] = 1 | ||
127 | |||
128 | return holidays | ||
129 | |||
130 | @staticmethod | ||
131 | def config(): | ||
132 | config = configparser.ConfigParser() | ||
133 | config_dir = BaseDirectory.load_first_config('worktime') | ||
134 | config.read(f"{config_dir}/worktime.ini") | ||
135 | return config | ||
136 | |||
103 | def __init__(self, start_datetime=None, end_datetime=None, now=None, include_running=True, force_day_to_work=True, **kwargs): | 137 | def __init__(self, start_datetime=None, end_datetime=None, now=None, include_running=True, force_day_to_work=True, **kwargs): |
104 | self.include_running = include_running | 138 | self.include_running = include_running |
105 | self.force_day_to_work = force_day_to_work | 139 | self.force_day_to_work = force_day_to_work |
@@ -107,9 +141,8 @@ class Worktime(object): | |||
107 | if now: | 141 | if now: |
108 | self.now = now | 142 | self.now = now |
109 | 143 | ||
110 | config = configparser.ConfigParser() | 144 | config = Worktime.config() |
111 | config_dir = BaseDirectory.load_first_config('worktime') | 145 | config_dir = BaseDirectory.load_first_config('worktime') |
112 | config.read(f"{config_dir}/worktime.ini") | ||
113 | api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace']) | 146 | api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace']) |
114 | date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') | 147 | date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') |
115 | 148 | ||
@@ -136,22 +169,7 @@ class Worktime(object): | |||
136 | holidays = dict() | 169 | holidays = dict() |
137 | 170 | ||
138 | for year in range(start_date.year, end_date.year + 1): | 171 | for year in range(start_date.year, end_date.year + 1): |
139 | y_easter = datetime.combine(easter(year), time(), tzinfo=tzlocal()) | 172 | holidays |= {k: v * time_per_day for k, v in Worktime.holidays(year).items()} |
140 | |||
141 | # Legal holidays in munich, bavaria | ||
142 | holidays[datetime(year, 1, 1, tzinfo=tzlocal()).date()] = time_per_day | ||
143 | holidays[datetime(year, 1, 6, tzinfo=tzlocal()).date()] = time_per_day | ||
144 | holidays[(y_easter+timedelta(days=-2)).date()] = time_per_day | ||
145 | holidays[(y_easter+timedelta(days=+1)).date()] = time_per_day | ||
146 | holidays[datetime(year, 5, 1, tzinfo=tzlocal()).date()] = time_per_day | ||
147 | holidays[(y_easter+timedelta(days=+39)).date()] = time_per_day | ||
148 | holidays[(y_easter+timedelta(days=+50)).date()] = time_per_day | ||
149 | holidays[(y_easter+timedelta(days=+60)).date()] = time_per_day | ||
150 | holidays[datetime(year, 8, 15, tzinfo=tzlocal()).date()] = time_per_day | ||
151 | holidays[datetime(year, 10, 3, tzinfo=tzlocal()).date()] = time_per_day | ||
152 | holidays[datetime(year, 11, 1, tzinfo=tzlocal()).date()] = time_per_day | ||
153 | holidays[datetime(year, 12, 25, tzinfo=tzlocal()).date()] = time_per_day | ||
154 | holidays[datetime(year, 12, 26, tzinfo=tzlocal()).date()] = time_per_day | ||
155 | 173 | ||
156 | try: | 174 | try: |
157 | with open(f"{config_dir}/excused", 'r') as excused: | 175 | with open(f"{config_dir}/excused", 'r') as excused: |
@@ -365,7 +383,19 @@ def diff(now, **args): | |||
365 | now = Worktime(**dict(args, now = now, include_running = False)) | 383 | now = Worktime(**dict(args, now = now, include_running = False)) |
366 | 384 | ||
367 | print(now.time_to_work - then.time_to_work) | 385 | print(now.time_to_work - then.time_to_work) |
386 | |||
387 | def holidays(now, **args): | ||
388 | config = Worktime.config() | ||
389 | date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') | ||
390 | |||
391 | table_data = [] | ||
368 | 392 | ||
393 | holidays = Worktime.holidays(now.year) | ||
394 | for k, v in holidays.items(): | ||
395 | kstr = k.strftime(date_format) | ||
396 | |||
397 | table_data += [[kstr, v]] | ||
398 | print(tabulate(table_data, tablefmt="plain")) | ||
369 | 399 | ||
370 | def main(): | 400 | def main(): |
371 | parser = argparse.ArgumentParser(prog = "worktime", description = 'Track worktime using toggl API') | 401 | parser = argparse.ArgumentParser(prog = "worktime", description = 'Track worktime using toggl API') |
@@ -379,6 +409,8 @@ def main(): | |||
379 | time_worked_parser.set_defaults(cmd = time_worked) | 409 | time_worked_parser.set_defaults(cmd = time_worked) |
380 | diff_parser = subparsers.add_parser('diff') | 410 | diff_parser = subparsers.add_parser('diff') |
381 | diff_parser.set_defaults(cmd = diff) | 411 | diff_parser.set_defaults(cmd = diff) |
412 | holidays_parser = subparsers.add_parser('holidays') | ||
413 | holidays_parser.set_defaults(cmd = holidays) | ||
382 | args = parser.parse_args() | 414 | args = parser.parse_args() |
383 | 415 | ||
384 | args.cmd(**vars(args)) | 416 | args.cmd(**vars(args)) |