diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index fbccd93..4a49e5b 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -247,6 +247,7 @@ stop_on_restart = false date_format = %Y.%m.%d time_format = %H:%M:%S%z week_start = monday +day_start_hour = 0 log_current = false pager = true report_current = false diff --git a/watson/cli.py b/watson/cli.py index cc8c593..e553080 100644 --- a/watson/cli.py +++ b/watson/cli.py @@ -20,7 +20,7 @@ get_rename_old_name, get_rename_types, ) -from .frames import Frame +from .frames import Frame, shifted_from from .utils import ( apply_weekday_offset, build_csv, @@ -1069,6 +1069,8 @@ def log(watson, current, reverse, from_, to, projects, tags, ignore_projects, if _ is not None): from_ = start_time + from_ = shifted_from(from_) + if from_ > to: raise click.ClickException("'from' must be anterior to 'to'") diff --git a/watson/frames.py b/watson/frames.py index 0e51157..1c329c0 100644 --- a/watson/frames.py +++ b/watson/frames.py @@ -7,6 +7,36 @@ HEADERS = ('start', 'stop', 'project', 'id', 'tags', 'updated_at') +hour_shift = 0 + + +def set_hour_shift(hour): + global hour_shift + hour_shift = hour + + +def shifted_floor(time, timeframe): + time = time.shift(hours=-hour_shift) + time = time.floor(timeframe) + time = time.shift(hours=hour_shift) + return time + + +def shifted_ceil(time, timeframe): + time = time.shift(hours=-hour_shift) + time = time.ceil(timeframe) + time = time.shift(hours=hour_shift) + return time + + +def shifted_from(from_): + if from_ == from_.floor('day'): + if arrow.now().hour < hour_shift: + from_ = from_.shift(days=-1) + from_ = from_.shift(hours=hour_shift) + return from_ + + class Frame(namedtuple('Frame', HEADERS)): def __new__(cls, start, stop, project, id, tags=None, updated_at=None,): try: @@ -45,7 +75,7 @@ def dump(self): @property def day(self): - return self.start.floor('day') + return shifted_floor(self.start, 'day') def __lt__(self, other): return self.start < other.start @@ -63,8 +93,8 @@ def __gte__(self, other): class Span(object): def __init__(self, start, stop, timeframe='day'): self.timeframe = timeframe - self.start = start.floor(self.timeframe) - self.stop = stop.ceil(self.timeframe) + self.start = shifted_floor(start, self.timeframe) + self.stop = shifted_ceil(stop, self.timeframe) def overlaps(self, frame): return frame.start <= self.stop and frame.stop >= self.start diff --git a/watson/watson.py b/watson/watson.py index 3f39be2..b0db440 100644 --- a/watson/watson.py +++ b/watson/watson.py @@ -10,7 +10,7 @@ import subprocess from .config import ConfigParser -from .frames import Frames +from .frames import Frames, set_hour_shift, shifted_from from .utils import deduplicate, make_json_writer, safe_save, sorted_groupby from .version import version as __version__ # noqa @@ -66,6 +66,8 @@ def __init__(self, **kwargs): if 'last_sync' in kwargs: self.last_sync = kwargs['last_sync'] + set_hour_shift(self.config.getint('options', 'day_start_hour', 0)) + def _load_json_file(self, filename, type=dict): """ Return the content of the the given JSON file. @@ -533,6 +535,8 @@ def report(self, from_, to, current=None, projects=None, tags=None, if _ is not None): from_ = start_time + from_ = shifted_from(from_) + if not self._validate_report_options(projects, ignore_projects): raise WatsonError( "given projects can't be ignored at the same time")