Skip to content

Commit 0a687a2

Browse files
committed
fix(worked-time): 🏗️ add classes for daterange generation
1 parent d100863 commit 0a687a2

File tree

3 files changed

+96
-88
lines changed

3 files changed

+96
-88
lines changed

time_tracker_api/time_entries/time_entries_namespace.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ def get(self):
294294
summary_attribs_parser.add_argument(
295295
'time_offset',
296296
required=False,
297+
type=int,
297298
store_missing=False,
298299
help="(Filter) Time zone difference, in minutes, from current locale (host system settings) to UTC.",
299300
location='args',

utils/time.py

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,33 @@
11
import pytz
22
from typing import Dict
3-
from datetime import datetime, timezone, timedelta
3+
from datetime import datetime, timezone
44

55

6-
def current_datetime_str() -> str:
7-
from utils.time import datetime_str
8-
9-
return datetime_str(current_datetime())
6+
def datetime_str(value: datetime) -> str:
7+
if value is not None:
8+
return value.isoformat()
9+
else:
10+
return None
1011

1112

1213
def current_datetime() -> datetime:
1314
return datetime.now(pytz.UTC)
1415

1516

17+
def current_datetime_str() -> str:
18+
return datetime_str(current_datetime())
19+
20+
1621
def get_current_year() -> int:
17-
return datetime.now().year
22+
return datetime.now(pytz.UTC).year
1823

1924

2025
def get_current_month() -> int:
21-
return datetime.now().month
26+
return datetime.now(pytz.UTC).month
2227

2328

2429
def get_current_day() -> int:
25-
return datetime.now().day
26-
27-
28-
def datetime_str(value: datetime) -> str:
29-
if value is not None:
30-
return value.isoformat()
31-
else:
32-
return None
30+
return datetime.now(pytz.UTC).day
3331

3432

3533
def get_date_range_of_month(year: int, month: int) -> Dict[str, str]:
@@ -61,35 +59,19 @@ def get_last_day_of_month(year: int, month: int) -> int:
6159
}
6260

6361

64-
def start_datetime_of_current_month() -> datetime:
65-
return datetime(
66-
year=get_current_year(),
67-
month=get_current_month(),
68-
day=1,
69-
tzinfo=timezone.utc,
70-
)
71-
72-
73-
def start_datetime_of_current_week() -> datetime:
74-
today = current_datetime()
75-
monday = today - timedelta(days=today.weekday())
76-
monday = monday.replace(hour=0, minute=0, second=0, microsecond=000000)
77-
return monday
78-
79-
80-
def start_datetime_of_current_day() -> datetime:
81-
today = current_datetime()
82-
today = today.replace(hour=0, minute=0, second=0, microsecond=000000)
83-
return today
84-
85-
86-
def start_datetime_of_current_month_str() -> str:
87-
return datetime_str(start_datetime_of_current_month())
62+
def str_to_datetime(value: str) -> datetime:
63+
def to_utc(date: datetime) -> datetime:
64+
from pytz import timezone
8865

66+
_tz = timezone('UTC')
67+
localized = _tz.localize(date)
68+
return localized
8969

90-
def str_to_datetime(value: str) -> datetime:
9170
from dateutil.parser import isoparse
92-
from dateutil.tz import tzutc
71+
from dateutil import tz
9372

94-
assert type(isoparse(value).tzinfo) == tzutc
95-
return isoparse(value)
73+
there_is_utc_info = type(isoparse(value).tzinfo) == tz.tzutc
74+
if there_is_utc_info:
75+
return isoparse(value)
76+
else:
77+
return to_utc(isoparse(value))

utils/worked_time.py

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,63 @@
1-
from datetime import datetime, timedelta
2-
from utils.time import (
3-
current_datetime,
4-
current_datetime_str,
5-
start_datetime_of_current_month,
6-
start_datetime_of_current_week,
7-
start_datetime_of_current_day,
8-
start_datetime_of_current_month_str,
9-
)
1+
import pytz
2+
from datetime import datetime, timedelta, timezone
3+
from utils.time import datetime_str
4+
5+
6+
class DateRange:
7+
def __init__(self, _timezone):
8+
self.tz = _timezone
9+
10+
def start(self):
11+
raise NotImplementedError
12+
13+
def end(self):
14+
return datetime.now(self.tz)
15+
16+
17+
class MonthDateRange(DateRange):
18+
def start(self):
19+
return (
20+
datetime.now(self.tz)
21+
.replace(hour=0, minute=0, second=0, microsecond=0)
22+
.replace(day=1)
23+
)
24+
25+
26+
class WeekDateRange(DateRange):
27+
def start(self):
28+
result = datetime.now(self.tz).replace(
29+
hour=0, minute=0, second=0, microsecond=0
30+
)
31+
result = result - timedelta(days=result.weekday())
32+
return result
33+
34+
35+
class DayDateRange(DateRange):
36+
def start(self):
37+
return datetime.now(self.tz).replace(
38+
hour=0, minute=0, second=0, microsecond=0
39+
)
1040

1141

1242
def date_range():
43+
dr = MonthDateRange(pytz.UTC)
1344
return {
14-
"start_date": start_datetime_of_current_month_str(),
15-
"end_date": current_datetime_str(),
45+
"start_date": datetime_str(dr.start()),
46+
"end_date": datetime_str(dr.end()),
1647
}
1748

1849

19-
def stop_running_time_entry(time_entries):
50+
def stop_running_time_entry(time_entries, tz):
51+
end = datetime.now(tz)
2052
for t in time_entries:
2153
if t.end_date is None:
22-
t.end_date = current_datetime_str()
54+
t.end_date = datetime_str(end)
2355

2456

2557
class WorkedTime:
2658
def __init__(self, time_entries):
2759
self.time_entries = time_entries
2860

29-
@classmethod
30-
def from_time_entries_in_range(
31-
cls, time_entries, start_date: datetime, end_date: datetime
32-
):
33-
time_entries_in_range = [
34-
t for t in time_entries if t.in_range(start_date, end_date)
35-
]
36-
return cls(time_entries_in_range)
37-
3861
def total_time_in_seconds(self):
3962
times = [t.elapsed_time for t in self.time_entries]
4063
total_time = sum(times, timedelta())
@@ -57,36 +80,38 @@ def summary(self):
5780
}
5881

5982

60-
def worked_time_in_day(time_entries):
61-
return WorkedTime.from_time_entries_in_range(
62-
time_entries,
63-
start_date=start_datetime_of_current_day(),
64-
end_date=current_datetime(),
65-
).summary()
83+
def filter_time_entries(time_entries, dr: DateRange):
84+
return [
85+
t
86+
for t in time_entries
87+
if t.in_range(start_date=dr.start(), end_date=dr.end())
88+
]
89+
90+
91+
def worked_time_in_day(time_entries, tz):
92+
dr = DayDateRange(tz)
93+
day_time_entries = filter_time_entries(time_entries, dr)
94+
return WorkedTime(day_time_entries).summary()
6695

6796

68-
def worked_time_in_week(time_entries):
69-
return WorkedTime.from_time_entries_in_range(
70-
time_entries,
71-
start_date=start_datetime_of_current_week(),
72-
end_date=current_datetime(),
73-
).summary()
97+
def worked_time_in_week(time_entries, tz):
98+
dr = WeekDateRange(tz)
99+
week_time_entries = filter_time_entries(time_entries, dr)
100+
return WorkedTime(week_time_entries).summary()
74101

75102

76-
def worked_time_in_month(time_entries):
77-
return WorkedTime.from_time_entries_in_range(
78-
time_entries,
79-
start_date=start_datetime_of_current_month(),
80-
end_date=current_datetime(),
81-
).summary()
103+
def worked_time_in_month(time_entries, tz):
104+
dr = MonthDateRange(tz)
105+
month_time_entries = filter_time_entries(time_entries, dr)
106+
return WorkedTime(month_time_entries).summary()
82107

83108

84109
def summary(time_entries, time_offset):
85110
offset_in_minutes = time_offset if time_offset else 300
86-
print(offset_in_minutes)
87-
stop_running_time_entry(time_entries)
111+
tz = timezone(timedelta(minutes=-offset_in_minutes))
112+
stop_running_time_entry(time_entries, tz)
88113
return {
89-
'day': worked_time_in_day(time_entries),
90-
'week': worked_time_in_week(time_entries),
91-
'month': worked_time_in_month(time_entries),
114+
'day': worked_time_in_day(time_entries, tz),
115+
'week': worked_time_in_week(time_entries, tz),
116+
'month': worked_time_in_month(time_entries, tz),
92117
}

0 commit comments

Comments
 (0)