Skip to content
Prev Previous commit
Next Next commit
fix(worked-time): 🏗️ add classes for daterange generation
  • Loading branch information
Angeluz-07 committed Jun 15, 2020
commit 0a687a29f0ac7c0931a2936867b51e24adc3416a
1 change: 1 addition & 0 deletions time_tracker_api/time_entries/time_entries_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ def get(self):
summary_attribs_parser.add_argument(
'time_offset',
required=False,
type=int,
store_missing=False,
help="(Filter) Time zone difference, in minutes, from current locale (host system settings) to UTC.",
location='args',
Expand Down
68 changes: 25 additions & 43 deletions utils/time.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import pytz
from typing import Dict
from datetime import datetime, timezone, timedelta
from datetime import datetime, timezone


def current_datetime_str() -> str:
from utils.time import datetime_str

return datetime_str(current_datetime())
def datetime_str(value: datetime) -> str:
if value is not None:
return value.isoformat()
else:
return None


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


def current_datetime_str() -> str:
return datetime_str(current_datetime())


def get_current_year() -> int:
return datetime.now().year
return datetime.now(pytz.UTC).year


def get_current_month() -> int:
return datetime.now().month
return datetime.now(pytz.UTC).month


def get_current_day() -> int:
return datetime.now().day


def datetime_str(value: datetime) -> str:
if value is not None:
return value.isoformat()
else:
return None
return datetime.now(pytz.UTC).day


def get_date_range_of_month(year: int, month: int) -> Dict[str, str]:
Expand Down Expand Up @@ -61,35 +59,19 @@ def get_last_day_of_month(year: int, month: int) -> int:
}


def start_datetime_of_current_month() -> datetime:
return datetime(
year=get_current_year(),
month=get_current_month(),
day=1,
tzinfo=timezone.utc,
)


def start_datetime_of_current_week() -> datetime:
today = current_datetime()
monday = today - timedelta(days=today.weekday())
monday = monday.replace(hour=0, minute=0, second=0, microsecond=000000)
return monday


def start_datetime_of_current_day() -> datetime:
today = current_datetime()
today = today.replace(hour=0, minute=0, second=0, microsecond=000000)
return today


def start_datetime_of_current_month_str() -> str:
return datetime_str(start_datetime_of_current_month())
def str_to_datetime(value: str) -> datetime:
def to_utc(date: datetime) -> datetime:
from pytz import timezone

_tz = timezone('UTC')
localized = _tz.localize(date)
return localized

def str_to_datetime(value: str) -> datetime:
from dateutil.parser import isoparse
from dateutil.tz import tzutc
from dateutil import tz

assert type(isoparse(value).tzinfo) == tzutc
return isoparse(value)
there_is_utc_info = type(isoparse(value).tzinfo) == tz.tzutc
if there_is_utc_info:
return isoparse(value)
else:
return to_utc(isoparse(value))
115 changes: 70 additions & 45 deletions utils/worked_time.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,63 @@
from datetime import datetime, timedelta
from utils.time import (
current_datetime,
current_datetime_str,
start_datetime_of_current_month,
start_datetime_of_current_week,
start_datetime_of_current_day,
start_datetime_of_current_month_str,
)
import pytz
from datetime import datetime, timedelta, timezone
from utils.time import datetime_str


class DateRange:
def __init__(self, _timezone):
self.tz = _timezone

def start(self):
raise NotImplementedError

def end(self):
return datetime.now(self.tz)


class MonthDateRange(DateRange):
def start(self):
return (
datetime.now(self.tz)
.replace(hour=0, minute=0, second=0, microsecond=0)
.replace(day=1)
)


class WeekDateRange(DateRange):
def start(self):
result = datetime.now(self.tz).replace(
hour=0, minute=0, second=0, microsecond=0
)
result = result - timedelta(days=result.weekday())
return result


class DayDateRange(DateRange):
def start(self):
return datetime.now(self.tz).replace(
hour=0, minute=0, second=0, microsecond=0
)


def date_range():
dr = MonthDateRange(pytz.UTC)
return {
"start_date": start_datetime_of_current_month_str(),
"end_date": current_datetime_str(),
"start_date": datetime_str(dr.start()),
"end_date": datetime_str(dr.end()),
}


def stop_running_time_entry(time_entries):
def stop_running_time_entry(time_entries, tz):
end = datetime.now(tz)
for t in time_entries:
if t.end_date is None:
t.end_date = current_datetime_str()
t.end_date = datetime_str(end)


class WorkedTime:
def __init__(self, time_entries):
self.time_entries = time_entries

@classmethod
def from_time_entries_in_range(
cls, time_entries, start_date: datetime, end_date: datetime
):
time_entries_in_range = [
t for t in time_entries if t.in_range(start_date, end_date)
]
return cls(time_entries_in_range)

def total_time_in_seconds(self):
times = [t.elapsed_time for t in self.time_entries]
total_time = sum(times, timedelta())
Expand All @@ -57,36 +80,38 @@ def summary(self):
}


def worked_time_in_day(time_entries):
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_day(),
end_date=current_datetime(),
).summary()
def filter_time_entries(time_entries, dr: DateRange):
return [
t
for t in time_entries
if t.in_range(start_date=dr.start(), end_date=dr.end())
]


def worked_time_in_day(time_entries, tz):
dr = DayDateRange(tz)
day_time_entries = filter_time_entries(time_entries, dr)
return WorkedTime(day_time_entries).summary()


def worked_time_in_week(time_entries):
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_week(),
end_date=current_datetime(),
).summary()
def worked_time_in_week(time_entries, tz):
dr = WeekDateRange(tz)
week_time_entries = filter_time_entries(time_entries, dr)
return WorkedTime(week_time_entries).summary()


def worked_time_in_month(time_entries):
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_month(),
end_date=current_datetime(),
).summary()
def worked_time_in_month(time_entries, tz):
dr = MonthDateRange(tz)
month_time_entries = filter_time_entries(time_entries, dr)
return WorkedTime(month_time_entries).summary()


def summary(time_entries, time_offset):
offset_in_minutes = time_offset if time_offset else 300
print(offset_in_minutes)
stop_running_time_entry(time_entries)
tz = timezone(timedelta(minutes=-offset_in_minutes))
stop_running_time_entry(time_entries, tz)
return {
'day': worked_time_in_day(time_entries),
'week': worked_time_in_week(time_entries),
'month': worked_time_in_month(time_entries),
'day': worked_time_in_day(time_entries, tz),
'week': worked_time_in_week(time_entries, tz),
'month': worked_time_in_month(time_entries, tz),
}