Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip handle future intervals #371

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/commands/CmdContinue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,10 @@ int CmdContinue (
Journal& journal)
{
const bool verbose = rules.getBoolean ("verbose");
const Datetime now {};

auto filter = cli.getFilter ({ now, 0 });

if (filter.start > now)
{
throw std::string ("Time tracking cannot be set in the future.");
}

// Gather IDs and TAGs.
std::set <int> ids = cli.getIds ();
auto filter = cli.getFilter ();

if (!ids.empty () && !filter.tags().empty ())
{
Expand Down
9 changes: 8 additions & 1 deletion src/commands/CmdDefault.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ int CmdDefault (Rules& rules, Database& database)

if (verbose)
{
std::cout << "There is no active time tracking.\n";
const Datetime now {};

std::cout << "There is no active time tracking";
if (interval.start > now)
{
std::cout << " but future intervals are present";
}
std::cout << ".\n";
}

return 1;
Expand Down
6 changes: 1 addition & 5 deletions src/commands/CmdStart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ int CmdStart (

auto interval = cli.getFilter ({ now, 0 });

if (interval.start > now)
{
throw std::string ("Time tracking cannot be set in the future.");
}
else if (!interval.is_started () || interval.is_ended ())
if (!interval.is_started () || interval.is_ended ())
{
throw std::string ("The start command does not accept ranges but only a single datetime. "
"Perhaps you want the track command?");
Expand Down
21 changes: 17 additions & 4 deletions src/commands/CmdStop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,6 @@ int CmdStop (
{
throw std::string ("No datetime specified.");
}
else if (filter.start <= latest.start)
{
throw std::string ("The end of a date range must be after the start.");
}

std::set <std::string> diff = {};

Expand All @@ -94,6 +90,23 @@ int CmdStop (
std::inserter(diff, diff.begin()));
}

if (filter.start <= latest.start)
{
std::stringstream sstr;

sstr << "Interval";
auto it = latest.tags ().cbegin ();
auto end = latest.tags ().cend ();
while (it != end)
{
sstr << " " << *it;
++it;
}
sstr << " started at " << latest.start.toISOLocalExtended ()
<< " cannot be stopped at " << filter.start.toISOLocalExtended () << '.';
throw sstr.str ();
}

journal.startTransaction ();

if (diff.empty ())
Expand Down
11 changes: 8 additions & 3 deletions src/commands/CmdSummary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ int CmdSummary (
Rules& rules,
Database& database)
{
const Datetime now {};
const bool verbose = rules.getBoolean ("verbose");

// Create a filter, and if empty, choose 'today'.
Expand Down Expand Up @@ -130,8 +131,10 @@ int CmdSummary (
for (auto& track : subset (day_range, tracked))
{
// Make sure the track only represents one day.
if ((track.is_open () && day > Datetime ()))
if (track.is_open () && day > now)
{
continue;
}

row = table.addRow ();

Expand All @@ -145,8 +148,10 @@ int CmdSummary (

// Intersect track with day.
auto today = day_range.intersect (track);
if (track.is_open () && day <= Datetime () && today.end > Datetime ())
today.end = Datetime ();
if (track.is_open () && day <= now && today.end > now)
{
today.end = (today.start > now) ? today.start : now;
}

std::string tags = join(", ", track.tags());

Expand Down
5 changes: 3 additions & 2 deletions src/data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,14 +516,15 @@ std::vector <Interval> getTracked (

if (! intervals.empty ())
{
const Datetime now {};
auto latest = intervals.back ();

if (latest.is_open ())
if (latest.is_open () && latest.start <= now)
{
// Get the set of expanded exclusions that overlap the range defined by the open interval.
Interval exclusion_range {};
exclusion_range.start = latest.start;
exclusion_range.end = Datetime();
exclusion_range.end = now;

auto exclusions = getAllExclusions (rules, exclusion_range);
if (! exclusions.empty ())
Expand Down
23 changes: 17 additions & 6 deletions src/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ std::string intervalSummarize (const Rules& rules, const Interval& interval)

if (interval.is_started ())
{
Duration total (interval.total ());

// Combine and colorize tags.
std::string tags;
for (auto& tag : interval.tags ())
Expand All @@ -95,10 +93,23 @@ std::string intervalSummarize (const Rules& rules, const Interval& interval)
// Interval open.
if (interval.is_open ())
{
out << "Tracking " << tags << '\n'
const Datetime now {};
if (interval.start <= now)
{
out << "Tracking " << tags << '\n'
<< " Started " << interval.start.toISOLocalExtended () << '\n'
<< " Current " << minimalDelta (interval.start, Datetime ()) << '\n'
<< " Total " << std::setw (19) << std::setfill (' ') << total.formatHours () << '\n';
<< " Current " << minimalDelta (interval.start, now) << '\n'
<< " Total " << std::setw (19) << std::setfill (' ') << Duration (interval.total ()).formatHours () << '\n';
}
else
{
out << "Tracking";
if (! tags.empty ())
{
out << " of " << tags;
}
out << "\n Scheduled for " << interval.start.toISOLocalExtended () << '\n';
}
}

// Interval closed.
Expand All @@ -107,7 +118,7 @@ std::string intervalSummarize (const Rules& rules, const Interval& interval)
out << "Recorded " << tags << '\n'
<< " Started " << interval.start.toISOLocalExtended () << '\n'
<< " Ended " << minimalDelta (interval.start, interval.end) << '\n'
<< " Total " << std::setw (19) << std::setfill (' ') << total.formatHours () << '\n';
<< " Total " << std::setw (19) << std::setfill (' ') << Duration (interval.total ()).formatHours () << '\n';
}
}

Expand Down
9 changes: 5 additions & 4 deletions test/continue.t
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import os
import sys
import unittest

from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone

# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
Expand Down Expand Up @@ -504,7 +504,7 @@ class TestContinue(TestCase):

def test_continue_with_future_time(self):
"""Verify that continue fails with time in the future"""
now_utc = datetime.now().utcnow()
now_utc = datetime.now(timezone.utc)

one_hour_before_utc = now_utc - timedelta(hours=1)
two_hours_before_utc = now_utc - timedelta(hours=2)
Expand All @@ -516,8 +516,9 @@ class TestContinue(TestCase):
code, out, err = self.t("stop")
self.assertIn("Recorded BAR\n", out)

code, out, err = self.t.runError("continue @2 from {:%Y-%m-%dT%H:%M:%S}Z".format(now_utc + timedelta(seconds=10)))
self.assertIn("Time tracking cannot be set in the future", err)
input_time_utc = now_utc + timedelta(seconds=10)
code, out, err = self.t("continue @2 from {:%Y-%m-%dT%H:%M:%S}Z".format(input_time_utc))
self.assertIn("Scheduled for {:%Y-%m-%dT%H:%M:%S}".format(input_time_utc.astimezone()), out)


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions test/start.t
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ class TestStart(TestCase):

one_hour_after_utc = now_utc + timedelta(hours=1)

code, out, err = self.t.runError("start {:%Y-%m-%dT%H:%M:%S}Z FOO".format(one_hour_after_utc))
code, out, err = self.t("start {:%Y-%m-%dT%H:%M:%S}Z FOO".format(one_hour_after_utc))

self.assertIn("Time tracking cannot be set in the future.", err)
self.assertIn("Scheduled for", out)

def test_start_with_open_interval(self):
"""Test start with already open interval, which should be auto-stopped"""
Expand Down
2 changes: 1 addition & 1 deletion test/stop.t
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class TestStop(TestCase):

code, out, err = self.t.runError("stop {:%Y-%m-%dT%H:%M:%S}Z".format(one_hour_before_utc))

self.assertIn("The end of a date range must be after the start.", err)
self.assertIn("cannot be stopped at", err)

j = self.t.export()

Expand Down
9 changes: 9 additions & 0 deletions test/summary.t
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,15 @@ W\d{1,2} \d{4}-\d{2}-\d{2} .{3} ?0:00:00 0:00:00 0:00:00 0:00:00
[ ]+0:00:00
""")

def test_with_open_interval_in_future(self):
"""Summary should show future open intervals"""

now_utc = datetime.now().utcnow()

self.t("start {:%Y-%m-%dT%H}:00:00Z".format(now_utc + timedelta(hours=1)))

code, out, err = self.t("summary yesterday - tomorrow")


if __name__ == "__main__":
from simpletap import TAPTestRunner
Expand Down