89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
import re
|
|
import datetime as dt
|
|
|
|
|
|
def strfdelta(delta: dt.timedelta, sec=False, minutes=True, short=False) -> str:
|
|
"""
|
|
Convert a datetime.timedelta object into an easily readable duration string.
|
|
|
|
Parameters
|
|
----------
|
|
delta: datetime.timedelta
|
|
The timedelta object to convert into a readable string.
|
|
sec: bool
|
|
Whether to include the seconds from the timedelta object in the string.
|
|
minutes: bool
|
|
Whether to include the minutes from the timedelta object in the string.
|
|
short: bool
|
|
Whether to abbreviate the units of time ("hour" to "h", "minute" to "m", "second" to "s").
|
|
|
|
Returns: str
|
|
A string containing a time from the datetime.timedelta object, in a readable format.
|
|
Time units will be abbreviated if short was set to True.
|
|
"""
|
|
output = [[delta.days, 'd' if short else ' day'],
|
|
[delta.seconds // 3600, 'h' if short else ' hour']]
|
|
if minutes:
|
|
output.append([delta.seconds // 60 % 60, 'm' if short else ' minute'])
|
|
if sec:
|
|
output.append([delta.seconds % 60, 's' if short else ' second'])
|
|
for i in range(len(output)):
|
|
if output[i][0] != 1 and not short:
|
|
output[i][1] += 's' # type: ignore
|
|
reply_msg = []
|
|
if output[0][0] != 0:
|
|
reply_msg.append("{}{} ".format(output[0][0], output[0][1]))
|
|
if output[0][0] != 0 or output[1][0] != 0 or len(output) == 2:
|
|
reply_msg.append("{}{} ".format(output[1][0], output[1][1]))
|
|
for i in range(2, len(output) - 1):
|
|
reply_msg.append("{}{} ".format(output[i][0], output[i][1]))
|
|
if not short and reply_msg:
|
|
reply_msg.append("and ")
|
|
reply_msg.append("{}{}".format(output[-1][0], output[-1][1]))
|
|
return "".join(reply_msg)
|
|
|
|
def utc_now() -> dt.datetime:
|
|
"""
|
|
Return the current timezone-aware utc timestamp.
|
|
"""
|
|
return dt.datetime.utcnow().replace(tzinfo=dt.timezone.utc)
|
|
|
|
def replace_multiple(format_string, mapping):
|
|
"""
|
|
Subsistutes the keys from the format_dict with their corresponding values.
|
|
|
|
Substitution is non-chained, and done in a single pass via regex.
|
|
"""
|
|
if not mapping:
|
|
raise ValueError("Empty mapping passed.")
|
|
|
|
keys = list(mapping.keys())
|
|
pattern = '|'.join(f"({key})" for key in keys)
|
|
string = re.sub(pattern, lambda match: str(mapping[keys[match.lastindex - 1]]), format_string)
|
|
return string
|
|
|
|
|
|
def parse_dur(time_str):
|
|
"""
|
|
Parses a user provided time duration string into a number of seconds.
|
|
|
|
Parameters
|
|
----------
|
|
time_str: str
|
|
The time string to parse. String can include days, hours, minutes, and seconds.
|
|
|
|
Returns: int
|
|
The number of seconds the duration represents.
|
|
"""
|
|
funcs = {'d': lambda x: x * 24 * 60 * 60,
|
|
'h': lambda x: x * 60 * 60,
|
|
'm': lambda x: x * 60,
|
|
's': lambda x: x}
|
|
time_str = time_str.strip(" ,")
|
|
found = re.findall(r'(\d+)\s?(\w+?)', time_str)
|
|
seconds = 0
|
|
for bit in found:
|
|
if bit[1] in funcs:
|
|
seconds += funcs[bit[1]](int(bit[0]))
|
|
return seconds
|