def daily_report_timeline(self, output, email, who): """Format a daily report with your timeline entries.""" # Locale is set as a side effect of 'import gtk', so strftime('%a') # would give us translated names weekday_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] weekday = weekday_names[self.min_timestamp.weekday()] week = self.min_timestamp.strftime('%V') print(("%(date)s report for %(who)s" " (%(weekday)s, week %(week)s)" % {'date': self.min_timestamp.strftime('%Y-%m-%d'), 'weekday': weekday, 'week': week, 'who': who}), file=output) print(file=output) items = list(self.all_entries()) if not items: print("No work done today.", file=output) return start, stop, duration, entry = items[0] for start, stop, duration, entry in items[1:]: print("%s - %s (%3s): %s" % ( start.strftime('%H:%M'), stop.strftime('%H:%M'), duration.seconds // 60, entry), file=output) now = datetime.datetime.now() if stop.date() == now.date(): print("%s - %s (%3d): **current task**" % ( stop.strftime('%H:%M'), now.strftime('%H:%M'), (now - stop).seconds / 60), file=output) print(file=output) work, slack, hold = self.grouped_entries() total_work, total_slacking, total_holidays = self.totals() print(("Total work done today: %s" % format_duration_long(total_work)), file=output)
def daily_report(self, output, email, who): """Format a daily report. Writes a daily report template in RFC-822 format to output. """ # Locale is set as a side effect of 'import gtk', so strftime('%a') # would give us translated names weekday_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] weekday = weekday_names[self.min_timestamp.weekday()] week = self.min_timestamp.strftime('%V') print >> output, "To: %(email)s" % {'email': email} print >> output, ("Subject: %(date)s report for %(who)s" " (%(weekday)s, week %(week)s)" % { 'date': self.min_timestamp.strftime('%Y-%m-%d'), 'weekday': weekday, 'week': week, 'who': who }) print >> output items = list(self.all_entries()) if not items: print >> output, "No work done today." return start, stop, duration, entry = items[0] entry = entry[:1].upper() + entry[1:] print >> output, "%s at %s" % (entry, start.strftime('%H:%M')) print >> output work, slack, hold = self.grouped_entries() total_work, total_slacking, total_holidays = self.totals() if work: for start, entry, duration in work: entry = entry[:1].upper() + entry[1:] print >> output, "%-62s %s" % (entry, format_duration_long(duration)) print >> output print >> output, ("Total work done: %s" % format_duration_long(total_work)) print >> output if slack: for start, entry, duration in slack: entry = entry[:1].upper() + entry[1:] print >> output, "%-62s %s" % (entry, format_duration_long(duration)) print >> output print >> output, ("Time spent slacking: %s" % format_duration_long(total_slacking))
def weekly_report(self, output, email, who, estimated_column=False): """Format a weekly report. Writes a weekly report template in RFC-822 format to output. """ week = self.min_timestamp.strftime('%V') print("To: %(email)s" % {'email': email}, file=output) print("Subject: Weekly report for %s (week %s)" % (who, week), file=output) print(file=output) items = list(self.all_entries()) if not items: print("No work done this week.", file=output) return print(" " * 46, end=' ', file=output) if estimated_column: print("estimated actual", file=output) else: print(" time", file=output) work, slack, hold = self.grouped_entries() total_work, total_slacking, total_holidays = self.totals() if work: work = [(entry, duration) for start, entry, duration in work] work.sort() for entry, duration in work: if not duration: continue # skip empty "arrival" entries entry = entry[:1].upper() + entry[1:] if estimated_column: print(("%-46s %-14s %s" % (entry, '-', format_duration_long(duration))), file=output) else: print(("%-62s %s" % (entry, format_duration_long(duration))), file=output) print(file=output) print(("Total work done this week: %s" % format_duration_long(total_work)), file=output)
def test_format_duration_long(self): self.assertEqual(' 0 min', format_duration_long(timedelta(0))) self.assertEqual(' 1 min', format_duration_long(timedelta(minutes=1))) self.assertEqual(' 1 hour ', format_duration_long(timedelta(minutes=60))) self.assertEqual(' 1 hour 5 min', format_duration_long(timedelta(minutes=65))) self.assertEqual(' 2 hours', format_duration_long(timedelta(hours=2))) self.assertEqual(' 2 hours 1 min', format_duration_long(timedelta(hours=2, minutes=1))) self.assertEqual('12 hours 32 min', format_duration_long(timedelta(hours=12, minutes=32)))
def main(): global Colors """Run the program.""" Colors = WithoutColors if curses: try: curses.setupterm() curses.initscr() if curses.can_change_color(): Colors = WithColors curses.endwin() except curses.error: Colors = WithoutColors # Argument parsing parser = argparse.ArgumentParser( description=u'Show the progress of the current week') parser.add_argument( '--day', metavar='YYYY-MM-DD', default=datetime.today().strftime('%Y-%m-%d'), help='Day of the week the progress should be calculated for. ' '(default: today)') args = parser.parse_args() # Load config settings, timelog = gocept.gtimelog.cli.load_config_and_timelog() # Calculate the progress today = datetime.strptime(args.day, '%Y-%m-%d') monday = today - timedelta(today.weekday()) sunday = monday + timedelta(7) week_done, week_exp, week_todo = gocept.gtimelog.util.calc_progress( settings, timelog, (monday, sunday)) today_window = timelog.window_for(today, today + timedelta(1)) today_window.daily_report_timeline(sys.stdout, settings.email, settings.name) total_work, total_slacking, total_holidays = (timelog.window_for( monday, sunday).totals()) print("Total work done this week: {colors.RED}{total_work}{colors.BLACK}" " of {colors.RED}{expected} hours{colors.BLACK}".format( colors=Colors, total_work=format_duration_long(total_work), expected=int(week_exp))) first_of_month = datetime(today.year, today.month, 1) next_month = today.replace(day=28) + timedelta(days=4) last_of_month = next_month - timedelta(days=next_month.day) total_customer, total_intern, total_slacking, total_holidays = ( timelog.window_for(first_of_month, last_of_month).totals(True)) total_work = total_customer + total_intern if total_work.total_seconds(): total_percent = (total_customer.total_seconds() * 100.0 / total_work.total_seconds()) else: total_percent = 0 expected = progress_expected = 0 engagement = settings.engagement if engagement: expected = engagement[today.month - 1] progress_expected = int( get_businessdays_until_now(holidays=settings.holidays) * settings.hours) print("Total work done this month: {colors.RED}{total_work} " "({total_percent} %){colors.BLACK} of " "{colors.RED}{progress_expected}" " ({expected}) hours{colors.BLACK}".format( colors=Colors, progress_expected=progress_expected, expected=expected, total_work=format_duration_long(total_work), total_percent=round(total_percent, 1))) first_of_year = datetime(today.year, 1, 1) last_of_year = datetime(today.year, 12, 31) total_customer, total_intern, total_slacking, total_holidays = ( timelog.window_for(first_of_year, last_of_year).totals(True)) total_work = total_customer + total_intern total_percent = (total_customer.total_seconds() * 100.0 / total_work.total_seconds()) progress_engagement = 0 now = datetime.now() for i in range(1, now.month + 1): if i < now.month: progress_engagement += settings.engagement[i - 1] else: progress_engagement += int( get_businessdays_until_now(holidays=settings.holidays) * settings.hours) engagement = sum(settings.engagement) print("Total work done this year: {colors.RED}{total_work} " "({total_percent} %){colors.BLACK} of {colors.RED}{progress} " "({expected}) hours{colors.BLACK}".format( colors=Colors, progress=progress_engagement, expected=engagement, total_work=format_duration_long(total_work), total_percent=round(total_percent, 1))) print("Overtime this year: {colors.RED}{overtime}".format( colors=Colors, overtime=format_duration_long(total_work - timedelta(hours=progress_engagement)))) if not today_window.items: return d_hours = timedelta(hours=today_window.settings.week_hours / 5.0) time_left = d_hours - today_window.totals()[0] clock_off = today_window.items[0][0] + d_hours + today_window.totals()[1] print("") print("Time left at work: {colors.RED}{time_left}{colors.BLACK}" " (until {until})".format(colors=Colors, time_left=format_duration_long(time_left), until=clock_off.strftime('%H:%M')))
def daily_report_timeline(self, output, email, who, summary=False, filter_=None): """Format a daily report with your timeline entries.""" # Locale is set as a side effect of 'import gtk', so strftime('%a') # would give us translated names weekday_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] weekday = weekday_names[self.min_timestamp.weekday()] week = self.min_timestamp.strftime('%V') print >> output, ("%(date)s report for %(who)s" " (%(weekday)s, week %(week)s)" % { 'date': self.min_timestamp.strftime('%Y-%m-%d'), 'weekday': weekday, 'week': week, 'who': who }) print >> output items = list(self.all_entries(filter_)) if not items: print >> output, "No work done today." return start, stop, duration, entry = items[0] if summary == False: for start, stop, duration, entry in items[1:]: hours, minutes = self._format_duration(duration) print >> output, "%s - %s (%s:%s): %s" % ( start.strftime('%H:%M'), stop.strftime('%H:%M'), hours, minutes, entry.encode('utf-8')) else: combined = {} items_ = items if filter_ else items[1:] for start, stop, duration, entry in items_: if ':' not in entry: continue proj, subproj, entry = entry.split(':', 2) entry = entry.strip() project = '%s:%s' % (proj, subproj) if entry.startswith('#'): project += entry.split(' ')[0] if project not in combined: combined[project] = [] combined[project].append((duration, entry)) for project, items in combined.items(): duration = datetime.timedelta(0) entries = [] for dur, entr in items: duration += dur entries.append(entr) entries = list(set(entries)) if '#' in project: project = project.split('#')[0] entry = project + ': ' + '; '.join(entries) hours, minutes = self._format_duration(duration) print >> output, "(%s:%s): %s" % (hours, minutes, entry.encode('utf-8')) now = datetime.datetime.now() if not filter_ and stop.date() == now.date(): hours, minutes = self._format_duration(now - stop) print >> output, "%s - %s (%s:%s): **current task**" % ( stop.strftime('%H:%M'), now.strftime('%H:%M'), hours, minutes) print >> output work, slack, hold = self.grouped_entries() total_work, total_slacking, total_holidays = self.totals() print >> output, ("Total work done today: %s" % format_duration_long(total_work))