def test_pretty_timedelta_should_return_timestring(self): timedelta_1 = datetime.timedelta(hours=1, minutes=23) timedelta_2 = datetime.timedelta(hours=-1, minutes=-23) timedelta_3 = datetime.timedelta() timedelta_4 = None nt.assert_equal(pretty_timedelta(timedelta_1), "1:23") nt.assert_equal(pretty_timedelta(timedelta_2), "-1:23") nt.assert_equal(pretty_timedelta(timedelta_3), "0:00") nt.assert_equal(pretty_timedelta(timedelta_4), "")
def test_pretty_timedelta_should_return_signed_timestring(self): positive_timedelta = datetime.timedelta(hours=1, minutes=23) negative_timedelta = datetime.timedelta(hours=-1, minutes=-23) zero_timedelta = datetime.timedelta() none_timedelta = None nt.assert_equal(pretty_timedelta(positive_timedelta, signed=True), "+1:23") nt.assert_equal(pretty_timedelta(negative_timedelta, signed=True), "-1:23") nt.assert_equal(pretty_timedelta(zero_timedelta, signed=True), "0:00") nt.assert_equal(pretty_timedelta(none_timedelta, signed=True), "")
def export(self) -> str: string = "{:>2}.".format(self.date.day) if self.start_time: string += " {}:{}".format(self.start_time.hour, self.start_time.strftime("%M")) if self.lunch_duration: string += " {}".format(pretty_timedelta(self.lunch_duration)) if self.deviation: string += " {}".format(pretty_timedelta(self.deviation, signed=True)) if self.end_time: string += " {}".format(self.end_time.strftime("%H:%M")) if self.comment: string += " {}".format(self.comment) return string
def __str__(self): width_label = 20 width_value = 17 value = "{day.date} - {}".format(self.date.strftime("%A"), day=self) string = """\n{:^{width}}\n""".format( value, width=width_label + width_value) if self.day_type == DayType.working_day: string += "-" * (width_label + width_value) string += "\n{:<{width}}".format("Start time:", width=width_label) if self.start_time: value = self.start_time.strftime("%H:%M") string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("Lunch:", width=width_label) if self.lunch_duration: value = pretty_timedelta(self.lunch_duration) string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("Deviation:", width=width_label) if self.deviation > timedelta(): value = pretty_timedelta(self.deviation) string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("End time:", width=width_label) if self.end_time: value = self.end_time.strftime("%H:%M") string += "{:>{width}}".format(value, width=width_value) string += "\n{}".format("-" * (width_label + width_value)) string += "\n{:<{width}}".format( "Worked hours:", width=width_label) if self.complete(): worked_hours = self.worked_hours() else: worked_hours = self.worked_hours( end_time=datetime.now()) value = pretty_timedelta(worked_hours) string += "{:>{width}}".format(value, width=width_value) if not self.complete(): string += " ..." string += "\n" if self.info or self.comment: string += "\n{}\n".format(self.get_info()) return string
def export(self) -> str: string = "{:>2}.".format(self.date.day) if self.start_time: string += " {}:{}".format( self.start_time.hour, self.start_time.strftime('%M')) if self.lunch_duration: string += " {}".format(pretty_timedelta(self.lunch_duration)) if self.deviation: string += " {}".format( pretty_timedelta(self.deviation, signed=True)) if self.end_time: string += " {}".format(self.end_time.strftime('%H:%M')) if self.comment: string += " {}".format(self.comment) return string
def __str__(self): width_label = 20 width_value = 17 value = "{day.date} - {}".format(self.date.strftime("%A"), day=self) string = """\n{:^{width}}\n""".format(value, width=width_label + width_value) if self.day_type == DayType.working_day: string += "-" * (width_label + width_value) string += "\n{:<{width}}".format("Start time:", width=width_label) if self.start_time: value = self.start_time.strftime("%H:%M") string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("Lunch:", width=width_label) if self.lunch_duration: value = pretty_timedelta(self.lunch_duration) string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("Deviation:", width=width_label) if self.deviation > timedelta(): value = pretty_timedelta(self.deviation) string += "{:>{width}}".format(value, width=width_value) string += "\n{:<{width}}".format("End time:", width=width_label) if self.end_time: value = self.end_time.strftime("%H:%M") string += "{:>{width}}".format(value, width=width_value) string += "\n{}".format("-" * (width_label + width_value)) string += "\n{:<{width}}".format("Worked hours:", width=width_label) if self.complete(): worked_hours = self.worked_hours() else: worked_hours = self.worked_hours(end_time=datetime.now()) value = pretty_timedelta(worked_hours) string += "{:>{width}}".format(value, width=width_value) if not self.complete(): string += " ..." string += "\n" if self.info or self.comment: string += "\n{}\n".format(self.get_info()) return string
def list_str(self) -> str: string = "{:<4}{:>2}.".format(self.date.strftime("%a"), self.date.day) if self.day_type == DayType.working_day: string += "{:>7}{:>6}{:>7}{:>6}{:>7} {}".format( self.start_time.strftime("%H:%M") if self.start_time else "", pretty_timedelta(self.lunch_duration), self.end_time.strftime("%H:%M") if self.end_time else "", pretty_timedelta(self.deviation) if self.deviation else "", pretty_timedelta(self.calculate_flextime(), signed=True) if self.end_time else "", self.get_info(), ) elif self.day_type == DayType.weekend: string += " {}".format(self.get_info()) elif self.day_type == DayType.vacation: string += " Vacation {}".format(self.get_info()) elif self.day_type == DayType.holiday: string += " {}".format(self.get_info()) elif self.day_type == DayType.sick_day: string += " Sickday {}".format(self.get_info()) return string.strip()
def __str__(self): width = 40 month_string = "{month.year}-{month.month:02} - {name}".format( month=self, name=datetime(self.year, self.month, 1).strftime("%B")) string = "\n{:^{width}}".format(month_string, width=width) string += "\n{}\n".format("-" * width) string += "\n".join(day.list_str() for day in self.days) string += "\n{}".format("-" * width) string += "\n{:>{width}}\n".format(pretty_timedelta( self.calculate_flextime(), signed=True), width=width) return string
def list_str(self) -> str: string = "{:<4}{:>2}.".format(self.date.strftime("%a"), self.date.day) if self.day_type == DayType.working_day: string += "{:>7}{:>6}{:>7}{:>6}{:>7} {}".format( self.start_time.strftime("%H:%M") if self.start_time else "", pretty_timedelta(self.lunch_duration), self.end_time.strftime("%H:%M") if self.end_time else "", pretty_timedelta(self.deviation) if self.deviation else "", pretty_timedelta(self.calculate_flextime(), signed=True) if self.end_time else "", self.get_info()) elif self.day_type == DayType.weekend: string += " {}".format(self.get_info()) elif self.day_type == DayType.vacation: string += " Vacation {}".format(self.get_info()) elif self.day_type == DayType.holiday: string += " {}".format(self.get_info()) elif self.day_type == DayType.sick_day: string += " Sickday {}".format(self.get_info()) return string.strip()
def __str__(self): width = 40 month_string = "{month.year}-{month.month:02} - {name}".format( month=self, name=datetime(self.year, self.month, 1).strftime("%B")) string = "\n{:^{width}}".format(month_string, width=width) string += "\n{}\n".format("-" * width) string += "\n".join(day.list_str() for day in self.days) string += "\n{}".format("-" * width) string += "\n{:>{width}}\n".format( pretty_timedelta(self.calculate_flextime(), signed=True), width=width) return string
def __str__(self): width = 40 week_string = "{}: {} - {}".format( self.number, self.monday.date.isoformat(), self.sunday.date.isoformat()) string = "\n{:^{width}}".format(week_string, width=width) string += "\n{}\n".format("-" * width) string += "\n".join(weekday.list_str() for weekday in ( self.monday, self.tuesday, self.wednesday, self.thursday, self.friday, self.saturday, self.sunday)) string += "\n{}".format("-" * width) string += "\n{:>{width}}\n".format( pretty_timedelta(self.calculate_flextime(), signed=True), width=width) return string
def __str__(self): width = 40 week_string = "{}: {} - {}".format(self.number, self.monday.date.isoformat(), self.sunday.date.isoformat()) string = "\n{:^{width}}".format(week_string, width=width) string += "\n{}\n".format("-" * width) string += "\n".join( weekday.list_str() for weekday in ( self.monday, self.tuesday, self.wednesday, self.thursday, self.friday, self.saturday, self.sunday, ) ) string += "\n{}".format("-" * width) string += "\n{:>{width}}\n".format(pretty_timedelta(self.calculate_flextime(), signed=True), width=width) return string
def main(): locale.setlocale(locale.LC_ALL, '') arguments = docopt(__doc__) if arguments['--verbose']: print(arguments) config_path = os.path.expanduser("~/.chrono") config = get_config(config_path) reconfigured = False if 'Data' not in config['Paths']: print("Chrono requires a data folder. Specify data folder with the " "--set-data-folder option.") sys.exit(1) elif arguments["--set-data-folder"]: data_folder = os.path.abspath( os.path.expanduser(arguments["--set-data-folder"])) if os.path.isdir(data_folder): config['Paths']['Data'] = data_folder reconfigured = True else: raise ValueError("Couln't find folder '{}'.".format(data_folder)) else: data_folder = os.path.expanduser(config['Paths']['Data']) parser = Parser() parser.parse_user_file(os.path.join(data_folder, "user.cfg")) year_files = [ f[:4] for f in os.listdir(data_folder) if f.endswith(".cfg") and len(os.path.basename(f)) == 8 ] month_files = sorted( glob( os.path.join(data_folder, "[1-2][0-9][0-9][0-9]-[0-1][0-9].txt"))) for month_file in month_files: year = os.path.basename(month_file)[:4] if year in year_files: parser.parse_year_file( os.path.join(data_folder, "{}.cfg".format(year))) year_files.remove(year) parser.parse_month_file(month_file) # Handling CLI commands if arguments['today'] or arguments['day']: if not arguments['<date>']: selected_day = parser.user.today() else: date = arguments['<date>'].split("-") if len(date) == 1: day = int(date[0]) selected_day = [ d for d in parser.user.current_month().days if d.date.day == day ][0] elif len(date) == 2: month, day = date month = int(month) day = int(day) selected_month = [ m for m in parser.user.current_year().months if m.month == month ][0] selected_day = [ d for d in selected_month.days if d.date.day == day ][0] elif len(date) == 3: year, month, day = date year = int(year) month = int(month) day = int(day) selected_year = [ y for y in parser.user.years if y.year == year ][0] selected_month = [ m for m in selected_year.months if m.month == month ][0] selected_day = [ d for d in selected_month.days if d.date.day == day ][0] else: raise errors.BadDateError( "Date string must have between 1 and 3 elements.") print(selected_day) elif arguments['week']: selected_week = parser.user.current_week() print(selected_week) print("Total flextime: {}".format( pretty_timedelta(parser.user.calculate_flextime(), signed=True))) elif arguments['month']: if arguments['<date>']: if "-" in arguments['<date>']: year, month = arguments['<date>'].split("-") year = int(year) month = int(month) else: year = parser.user.current_year().year month = int(arguments['<date>']) selected_year = [ y for y in parser.user.years if y.year == year ][0] selected_month = [ m for m in selected_year.months if m.month == month ][0] else: selected_month = parser.user.years[-1].months[-1] print(selected_month) print("Total flextime: {}".format( pretty_timedelta(parser.user.calculate_flextime(), signed=True))) elif arguments['year']: if arguments['<date>']: selected_year = [ year for year in parser.user.years if str(year.year) == arguments['<date>'] ][0] else: selected_year = parser.user.years[-1] for month in selected_year.months: print(month) elif arguments['report']: if arguments['start']: start_time = (arguments['<time>'] or datetime.datetime.now().strftime("%H:%M")) parser.user.add_day( parser.user.next_workday()).report_start_time(start_time) elif arguments['end']: end_time = (arguments['<time>'] or datetime.datetime.now().strftime("%H:%M")) parser.user.today().report_end_time(end_time) elif arguments['lunch']: parser.user.today().report_lunch_duration(arguments['<time>']) elif arguments["deviation"]: parser.user.today().report_deviation(arguments['<time>']) today = parser.user.today() month_file = os.path.join( data_folder, "{}.txt".format(today.date.strftime("%Y-%m"))) writer.write_line(month_file, today.export()) elif arguments['user']: print() print(parser.user) print() elif arguments['stats']: if arguments['-w']: selected_period = parser.user.current_week().days elif arguments['-m']: selected_period = parser.user.current_month().days elif arguments['-y']: selected_period = parser.user.current_year().days else: selected_period = parser.user.all_days() if arguments['start']: print_start_statistics(selected_period, histogram=arguments['--hist'], bin_width=int(arguments['--bin-width']), height=int(arguments['--height'])) if arguments['end']: print_end_statistics(selected_period, histogram=arguments['--hist'], bin_width=int(arguments['--bin-width']), height=int(arguments['--height'])) elif arguments['vacation']: print("Vacation left: {} / {}".format(parser.user.vacation_left(), parser.user.payed_vacation)) elif arguments['edit']: if 'Editor' in config['Paths']: if arguments['<month>']: month_string = arguments['<month>'] else: month_string = parser.user.today().date.strftime("%Y-%m") month_file = os.path.join(data_folder, "{}.txt".format(month_string)) if not os.path.exists(month_file): raise errors.BadDateError( "Couldn't find month file '{}'".format(month_file)) command = [config['Paths']['Editor'], month_file] subprocess.call(command) else: print("Add an editor to your .chrono configuration file.") if reconfigured: write_config(config, config_path)
def main(): locale.setlocale(locale.LC_ALL, "") arguments = docopt(__doc__) if arguments["--verbose"]: print(arguments) config_path = os.path.expanduser("~/.chrono") config = get_config(config_path) reconfigured = False if "Data" not in config["Paths"]: print("Chrono requires a data folder. Specify data folder with the " "--set-data-folder option.") sys.exit(1) elif arguments["--set-data-folder"]: data_folder = os.path.abspath(os.path.expanduser(arguments["--set-data-folder"])) if os.path.isdir(data_folder): config["Paths"]["Data"] = data_folder reconfigured = True else: raise ValueError("Couln't find folder '{}'.".format(data_folder)) else: data_folder = os.path.expanduser(config["Paths"]["Data"]) parser = Parser() parser.parse_user_file(os.path.join(data_folder, "user.cfg")) year_files = [f[:4] for f in os.listdir(data_folder) if f.endswith(".cfg") and len(os.path.basename(f)) == 8] month_files = sorted(glob(os.path.join(data_folder, "[1-2][0-9][0-9][0-9]-[0-1][0-9].txt"))) for month_file in month_files: year = os.path.basename(month_file)[:4] if year in year_files: parser.parse_year_file(os.path.join(data_folder, "{}.cfg".format(year))) year_files.remove(year) parser.parse_month_file(month_file) # Handling CLI commands if arguments["today"] or arguments["day"]: if not arguments["<date>"]: selected_day = parser.user.today() else: date = arguments["<date>"].split("-") if len(date) == 1: day = int(date[0]) selected_day = [d for d in parser.user.current_month().days if d.date.day == day][0] elif len(date) == 2: month, day = date month = int(month) day = int(day) selected_month = [m for m in parser.user.current_year().months if m.month == month][0] selected_day = [d for d in selected_month.days if d.date.day == day][0] elif len(date) == 3: year, month, day = date year = int(year) month = int(month) day = int(day) selected_year = [y for y in parser.user.years if y.year == year][0] selected_month = [m for m in selected_year.months if m.month == month][0] selected_day = [d for d in selected_month.days if d.date.day == day][0] else: raise errors.BadDateError("Date string must have between 1 and 3 elements.") print(selected_day) elif arguments["week"]: selected_week = parser.user.current_week() print(selected_week) print("Total flextime: {}".format(pretty_timedelta(parser.user.calculate_flextime(), signed=True))) elif arguments["month"]: if arguments["<date>"]: if "-" in arguments["<date>"]: year, month = arguments["<date>"].split("-") year = int(year) month = int(month) else: year = parser.user.current_year().year month = int(arguments["<date>"]) selected_year = [y for y in parser.user.years if y.year == year][0] selected_month = [m for m in selected_year.months if m.month == month][0] else: selected_month = parser.user.years[-1].months[-1] print(selected_month) print("Total flextime: {}".format(pretty_timedelta(parser.user.calculate_flextime(), signed=True))) elif arguments["year"]: if arguments["<date>"]: selected_year = [year for year in parser.user.years if str(year.year) == arguments["<date>"]][0] else: selected_year = parser.user.years[-1] for month in selected_year.months: print(month) elif arguments["report"]: if arguments["start"]: start_time = arguments["<time>"] or datetime.datetime.now().strftime("%H:%M") parser.user.add_day(parser.user.next_workday()).report_start_time(start_time) elif arguments["end"]: end_time = arguments["<time>"] or datetime.datetime.now().strftime("%H:%M") parser.user.today().report_end_time(end_time) elif arguments["lunch"]: parser.user.today().report_lunch_duration(arguments["<time>"]) elif arguments["deviation"]: parser.user.today().report_deviation(arguments["<time>"]) today = parser.user.today() month_file = os.path.join(data_folder, "{}.txt".format(today.date.strftime("%Y-%m"))) writer.write_line(month_file, today.export()) elif arguments["user"]: print() print(parser.user) print() elif arguments["stats"]: if arguments["-w"]: selected_period = parser.user.current_week().days elif arguments["-m"]: selected_period = parser.user.current_month().days elif arguments["-y"]: selected_period = parser.user.current_year().days else: selected_period = parser.user.all_days() if arguments["start"]: print_start_statistics( selected_period, histogram=arguments["--hist"], bin_width=int(arguments["--bin-width"]), height=int(arguments["--height"]), ) if arguments["end"]: print_end_statistics( selected_period, histogram=arguments["--hist"], bin_width=int(arguments["--bin-width"]), height=int(arguments["--height"]), ) elif arguments["vacation"]: print("Vacation left: {} / {}".format(parser.user.vacation_left(), parser.user.payed_vacation)) elif arguments["edit"]: if "Editor" in config["Paths"]: if arguments["<month>"]: month_string = arguments["<month>"] else: month_string = parser.user.today().date.strftime("%Y-%m") month_file = os.path.join(data_folder, "{}.txt".format(month_string)) if not os.path.exists(month_file): raise errors.BadDateError("Couldn't find month file '{}'".format(month_file)) command = [config["Paths"]["Editor"], month_file] subprocess.call(command) else: print("Add an editor to your .chrono configuration file.") if reconfigured: write_config(config, config_path)