コード例 #1
0
    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), "")
コード例 #2
0
    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), "")
コード例 #3
0
ファイル: day.py プロジェクト: jonatanlindstrom/chrono
    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
コード例 #4
0
    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
コード例 #5
0
    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
コード例 #6
0
ファイル: day.py プロジェクト: jonatanlindstrom/chrono
    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
コード例 #7
0
ファイル: day.py プロジェクト: jonatanlindstrom/chrono
    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()
コード例 #8
0
ファイル: month.py プロジェクト: jonatanskogsfors/chrono
    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
コード例 #9
0
    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()
コード例 #10
0
ファイル: month.py プロジェクト: jonatanlindstrom/chrono
    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
コード例 #11
0
ファイル: week.py プロジェクト: jonatanskogsfors/chrono
    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
コード例 #12
0
ファイル: week.py プロジェクト: jonatanlindstrom/chrono
    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
コード例 #13
0
ファイル: chrono.py プロジェクト: jonatanskogsfors/chrono
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)
コード例 #14
0
ファイル: chrono.py プロジェクト: jonatanlindstrom/chrono
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)