e_lib.time_utils

e_lib.time_utils

Time formatting helpers.

format_time renders a number of seconds as a human-readable Russian string and is used e.g. by e_lib.assistants.ScheduledAssistant.

 1# -*- coding: utf-8 -*-
 2"""e_lib.time_utils
 3
 4Time formatting helpers.
 5
 6``format_time`` renders a number of seconds as a human-readable Russian string
 7and is used e.g. by :class:`e_lib.assistants.ScheduledAssistant`.
 8"""
 9
10from __future__ import annotations
11
12from datetime import datetime, timedelta
13
14
15def format_time(seconds: int) -> str:
16    """Format seconds as a human-readable Russian string.
17
18    Zero-valued units are omitted.  Supports correct plural forms
19    (день/дня/дней, час/часа/часов, минута/минуты/минут, etc.).
20
21    Args:
22        seconds: Number of seconds.
23
24    Returns:
25        Formatted string, e.g. "2 часа 30 минут", or "0 секунд" for
26        non-positive values.
27    """
28    if seconds < 0:
29        return "0 секунд"
30
31    intervals = [("день", 86400), ("час", 3600), ("минуту", 60), ("секунду", 1)]
32
33    parts = []
34
35    for name, count in intervals:
36        if seconds >= count:
37            value = seconds // count
38            seconds %= count
39
40            # Skip zero values.
41            if value == 0:
42                continue
43
44            # Correct plural forms.
45            if name == "день":
46                if value % 10 == 1 and value % 100 != 11:
47                    name = "день"
48                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
49                    name = "дня"
50                else:
51                    name = "дней"
52            elif name == "час":
53                if value % 10 == 1 and value % 100 != 11:
54                    name = "час"
55                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
56                    name = "часа"
57                else:
58                    name = "часов"
59            elif name == "минуту":
60                if value % 10 == 1 and value % 100 != 11:
61                    name = "минута"
62                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
63                    name = "минуты"
64                else:
65                    name = "минут"
66            elif name == "секунду":
67                if value % 10 == 1 and value % 100 != 11:
68                    name = "секунда"
69                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
70                    name = "секунды"
71                else:
72                    name = "секунд"
73
74            parts.append(f"{int(value)} {name}")
75
76    if not parts:
77        return "0 секунд"
78
79    return " ".join(parts)
80
81
82def time_passed(seconds_ago: int) -> datetime:
83    """Return the datetime that is ``seconds_ago`` seconds in the past.
84
85    Args:
86        seconds_ago: Number of seconds to go back.
87
88    Returns:
89        A ``datetime`` computed from the current moment minus ``seconds_ago``.
90    """
91    current_time = datetime.now()
92    target_time = current_time - timedelta(seconds=seconds_ago)
93    return target_time
def format_time(seconds: int) -> str:
16def format_time(seconds: int) -> str:
17    """Format seconds as a human-readable Russian string.
18
19    Zero-valued units are omitted.  Supports correct plural forms
20    (день/дня/дней, час/часа/часов, минута/минуты/минут, etc.).
21
22    Args:
23        seconds: Number of seconds.
24
25    Returns:
26        Formatted string, e.g. "2 часа 30 минут", or "0 секунд" for
27        non-positive values.
28    """
29    if seconds < 0:
30        return "0 секунд"
31
32    intervals = [("день", 86400), ("час", 3600), ("минуту", 60), ("секунду", 1)]
33
34    parts = []
35
36    for name, count in intervals:
37        if seconds >= count:
38            value = seconds // count
39            seconds %= count
40
41            # Skip zero values.
42            if value == 0:
43                continue
44
45            # Correct plural forms.
46            if name == "день":
47                if value % 10 == 1 and value % 100 != 11:
48                    name = "день"
49                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
50                    name = "дня"
51                else:
52                    name = "дней"
53            elif name == "час":
54                if value % 10 == 1 and value % 100 != 11:
55                    name = "час"
56                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
57                    name = "часа"
58                else:
59                    name = "часов"
60            elif name == "минуту":
61                if value % 10 == 1 and value % 100 != 11:
62                    name = "минута"
63                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
64                    name = "минуты"
65                else:
66                    name = "минут"
67            elif name == "секунду":
68                if value % 10 == 1 and value % 100 != 11:
69                    name = "секунда"
70                elif 2 <= value % 10 <= 4 and (value % 100 < 10 or value % 100 >= 20):
71                    name = "секунды"
72                else:
73                    name = "секунд"
74
75            parts.append(f"{int(value)} {name}")
76
77    if not parts:
78        return "0 секунд"
79
80    return " ".join(parts)

Format seconds as a human-readable Russian string.

Zero-valued units are omitted. Supports correct plural forms (день/дня/дней, час/часа/часов, минута/минуты/минут, etc.).

Args: seconds: Number of seconds.

Returns: Formatted string, e.g. "2 часа 30 минут", or "0 секунд" for non-positive values.

def time_passed(seconds_ago: int) -> datetime.datetime:
83def time_passed(seconds_ago: int) -> datetime:
84    """Return the datetime that is ``seconds_ago`` seconds in the past.
85
86    Args:
87        seconds_ago: Number of seconds to go back.
88
89    Returns:
90        A ``datetime`` computed from the current moment minus ``seconds_ago``.
91    """
92    current_time = datetime.now()
93    target_time = current_time - timedelta(seconds=seconds_ago)
94    return target_time

Return the datetime that is seconds_ago seconds in the past.

Args: seconds_ago: Number of seconds to go back.

Returns: A datetime computed from the current moment minus seconds_ago.