diff options
| author | 2019-11-15 13:59:09 +0000 | |
|---|---|---|
| committer | 2019-11-15 13:59:09 +0000 | |
| commit | 5d01db8514f9b06d2e478c0d86ffafe137093d5b (patch) | |
| tree | dba9d73f611e804bf02b6ea7146b0a392be41939 /src/utils/datetime.py | |
| parent | dont expose has_magic/get_magic in utils/__init__.py, ref directly (diff) | |
| signature | ||
move all datetime-related code from utils/__init__ to utils.datetime
Diffstat (limited to 'src/utils/datetime.py')
| -rw-r--r-- | src/utils/datetime.py | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/utils/datetime.py b/src/utils/datetime.py new file mode 100644 index 00000000..0fac2bb3 --- /dev/null +++ b/src/utils/datetime.py @@ -0,0 +1,125 @@ +import re, typing +import datetime as _datetime + +ISO8601_PARSE = "%Y-%m-%dT%H:%M:%S%z" +ISO8601_PARSE_MICROSECONDS = "%Y-%m-%dT%H:%M:%S.%f%z" + +ISO8601_FORMAT_DT = "%Y-%m-%dT%H:%M:%S" +ISO8601_FORMAT_TZ = "%z" + +DATETIME_HUMAN = "%Y/%m/%d %H:%M:%S" +DATE_HUMAN = "%Y-%m-%d" + +def datetime_utcnow() -> _datetime.datetime: + return _datetime.datetime.utcnow().replace(tzinfo=_datetime.timezone.utc) +def datetime_timestamp(seconds: float) -> _datetime.datetime: + return _datetime.datetime.fromtimestamp(seconds).replace( + tzinfo=_datetime.timezone.utc) + +def iso8601_format(dt: _datetime.datetime, milliseconds: bool=False) -> str: + dt_format = dt.strftime(ISO8601_FORMAT_DT) + tz_format = dt.strftime(ISO8601_FORMAT_TZ) + + ms_format = "" + if milliseconds: + ms_format = ".%s" % str(int(dt.microsecond/1000)).zfill(3) + + return "%s%s%s" % (dt_format, ms_format, tz_format) +def iso8601_format_now(milliseconds: bool=False) -> str: + return iso8601_format(datetime_utcnow(), milliseconds=milliseconds) +def iso8601_parse(s: str, microseconds: bool=False) -> _datetime.datetime: + fmt = ISO8601_PARSE_MICROSECONDS if microseconds else ISO8601_PARSE + return _datetime.datetime.strptime(s, fmt) + +def datetime_human(dt: _datetime.datetime): + return _datetime.datetime.strftime(dt, DATETIME_HUMAN) +def date_human(dt: _datetime.datetime): + return _datetime.datetime.strftime(dt, DATE_HUMAN) + +TIME_SECOND = 1 +TIME_MINUTE = TIME_SECOND*60 +TIME_HOUR = TIME_MINUTE*60 +TIME_DAY = TIME_HOUR*24 +TIME_WEEK = TIME_DAY*7 + +def time_unit(seconds: int) -> typing.Tuple[int, str]: + since = None + unit = None + if seconds >= TIME_WEEK: + since = seconds/TIME_WEEK + unit = "week" + elif seconds >= TIME_DAY: + since = seconds/TIME_DAY + unit = "day" + elif seconds >= TIME_HOUR: + since = seconds/TIME_HOUR + unit = "hour" + elif seconds >= TIME_MINUTE: + since = seconds/TIME_MINUTE + unit = "minute" + else: + since = seconds + unit = "second" + since = int(since) + if since > 1: + unit = "%ss" % unit # pluralise the unit + return (since, unit) + +REGEX_PRETTYTIME = re.compile( + r"(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?", re.I) + +SECONDS_MINUTES = 60 +SECONDS_HOURS = SECONDS_MINUTES*60 +SECONDS_DAYS = SECONDS_HOURS*24 +SECONDS_WEEKS = SECONDS_DAYS*7 + +def from_pretty_time(pretty_time: str) -> typing.Optional[int]: + seconds = 0 + + match = re.match(REGEX_PRETTYTIME, pretty_time) + if match: + seconds += int(match.group(1) or 0)*SECONDS_WEEKS + seconds += int(match.group(2) or 0)*SECONDS_DAYS + seconds += int(match.group(3) or 0)*SECONDS_HOURS + seconds += int(match.group(4) or 0)*SECONDS_MINUTES + seconds += int(match.group(5) or 0) + + if seconds > 0: + return seconds + return None + +UNIT_MINIMUM = 6 +UNIT_SECOND = 5 +UNIT_MINUTE = 4 +UNIT_HOUR = 3 +UNIT_DAY = 2 +UNIT_WEEK = 1 +def to_pretty_time(total_seconds: int, minimum_unit: int=UNIT_SECOND, + max_units: int=UNIT_MINIMUM) -> str: + if total_seconds == 0: + return "0s" + + minutes, seconds = divmod(total_seconds, 60) + hours, minutes = divmod(minutes, 60) + days, hours = divmod(hours, 24) + weeks, days = divmod(days, 7) + out = [] + + units = 0 + if weeks and minimum_unit >= UNIT_WEEK and units < max_units: + out.append("%dw" % weeks) + units += 1 + if days and minimum_unit >= UNIT_DAY and units < max_units: + out.append("%dd" % days) + units += 1 + if hours and minimum_unit >= UNIT_HOUR and units < max_units: + out.append("%dh" % hours) + units += 1 + if minutes and minimum_unit >= UNIT_MINUTE and units < max_units: + out.append("%dm" % minutes) + units += 1 + if seconds and minimum_unit >= UNIT_SECOND and units < max_units: + out.append("%ds" % seconds) + units += 1 + return " ".join(out) + |
