diff --git a/modules/coins.py b/modules/coins.py index 4f366500..8e84c96e 100644 --- a/modules/coins.py +++ b/modules/coins.py @@ -194,7 +194,7 @@ class Module(ModuleManager.BaseModule): time_left = self.bot.cache.until_expiration(cache) event["stderr"].write("%s: Please wait %s before redeeming" % ( event["user"].nickname, - utils.datetime.format.to_pretty_time(time_left))) + utils.datetime.format.to_pretty_until(time_left))) else: event["stderr"].write( "%s: You can only redeem coins when you have none" % @@ -492,7 +492,7 @@ class Module(ModuleManager.BaseModule): def next_lottery(self, event): until = self._until_next_6_hour() event["stdout"].write("Next lottery is in: %s" % - utils.datetime.format.to_pretty_time(until)) + utils.datetime.format.to_pretty_until(until)) @utils.hook("received.command.lotterywinner") @utils.kwarg("help", "Show who last won the lottery") diff --git a/modules/messages.py b/modules/messages.py index f6c37530..19d9a1a3 100644 --- a/modules/messages.py +++ b/modules/messages.py @@ -16,7 +16,7 @@ class Module(ModuleManager.BaseModule): for i, message in enumerate(message_list): seconds = utils.datetime.seconds_since(message.line.timestamp) messages.append("(%d/%d) %s ago %s" % (i+1, message_count, - utils.datetime.format.to_pretty_time(seconds), + utils.datetime.format.to_pretty_since(seconds), message.line.format())) event["stdout"].write("%s: found: %s" diff --git a/modules/seen.py b/modules/seen.py index 780ea99e..01c0d0f3 100644 --- a/modules/seen.py +++ b/modules/seen.py @@ -35,7 +35,7 @@ class Module(ModuleManager.BaseModule): seen_info = " (%s%s)" % (seen_info["action"], utils.consts.RESET) - since = utils.datetime.format.to_pretty_time( + since = utils.datetime.format.to_pretty_since( time.time()-seen_seconds, max_units=2) event["stdout"].write("%s was last seen %s ago%s" % ( event["args_split"][0], since, seen_info or "")) diff --git a/modules/stats.py b/modules/stats.py index d61312f7..4d82ac45 100644 --- a/modules/stats.py +++ b/modules/stats.py @@ -7,7 +7,7 @@ HIDDEN_MODES = set(["s", "p"]) class Module(ModuleManager.BaseModule): def _uptime(self): - return utils.datetime.format.to_pretty_time( + return utils.datetime.format.to_pretty_since( int(time.time()-self.bot.start_time)) @utils.hook("received.command.uptime") diff --git a/modules/tweets/format.py b/modules/tweets/format.py index aab1c62d..540e7638 100644 --- a/modules/tweets/format.py +++ b/modules/tweets/format.py @@ -3,7 +3,7 @@ from src import utils def _timestamp(dt): seconds_since = time.time()-dt.timestamp() - timestamp = utils.datetime.format.to_pretty_time( + timestamp = utils.datetime.format.to_pretty_since( seconds_since, max_units=2) return "%s ago" % timestamp diff --git a/src/utils/datetime/common.py b/src/utils/datetime/common.py index 7235fbab..6e7c7813 100644 --- a/src/utils/datetime/common.py +++ b/src/utils/datetime/common.py @@ -40,3 +40,7 @@ def timestamp(seconds: float) -> _datetime.datetime: def seconds_since(dt: _datetime.datetime) -> float: return (utcnow()-dt).total_seconds() + +class RelativeDirection(enum.Enum): + FORWARD = 1 + BACKWARD = 2 diff --git a/src/utils/datetime/format.py b/src/utils/datetime/format.py index 987d44f2..eeda2601 100644 --- a/src/utils/datetime/format.py +++ b/src/utils/datetime/format.py @@ -48,31 +48,55 @@ def time_unit(seconds: int) -> typing.Tuple[int, str]: unit = "%ss" % unit # pluralise the unit return (since, unit) -def to_pretty_time(total_seconds: int, minimum_unit: int=UNIT_SECOND, - max_units: int=UNIT_MINIMUM) -> str: +def to_pretty_time(total_seconds: int, max_units: int=UNIT_MINIMUM, + direction: typing.Optional[RelativeDirection]=None) -> str: if total_seconds == 0: return "0s" - now = utcnow() - later = now+_datetime.timedelta(seconds=total_seconds) - relative = dateutil.relativedelta.relativedelta(later, now) + if not direction == None: + now = utcnow() + later = now + mod = _datetime.timedelta(seconds=total_seconds) + if direction == RelativeDirection.FORWARD: + later += mod + else: + later -= mod + relative = dateutil.relativedelta.relativedelta( + *sorted([later, now], reverse=True)) + years = relative.years + months = relative.months + weeks, days = divmod(relative.days, 7) + hours = relative.hours + minutes = relative.minutes + seconds = relative.seconds + else: + years, months = 0, 0 + weeks, days = divmod(total_seconds, SECONDS_WEEKS) + days, hours = divmod(days, SECONDS_DAYS) + hours, minutes = divmod(hours, SECONDS_HOURS) + minutes, seconds = divmod(minutes, SECONDS_MINUTES) out: typing.List[str] = [] - if relative.years and minimum_unit >= UNIT_YEAR and len(out) < max_units: - out.append("%dy" % relative.years) - if relative.months and minimum_unit >= UNIT_MONTH and len(out) < max_units: - out.append("%dmo" % relative.months) - weeks, days = divmod(relative.days, 7) - if weeks and minimum_unit >= UNIT_WEEK and len(out) < max_units: + if years and len(out) < max_units: + out.append("%dy" % years) + if months and len(out) < max_units: + out.append("%dmo" % months) + if weeks and len(out) < max_units: out.append("%dw" % weeks) - if days and minimum_unit >= UNIT_DAY and len(out) < max_units: + if days and len(out) < max_units: out.append("%dd" % days) - if relative.hours and minimum_unit >= UNIT_HOUR and len(out) < max_units: - out.append("%dh" % relative.hours) - if relative.minutes and minimum_unit >= UNIT_MINUTE and len(out) < max_units: - out.append("%dmi" % relative.minutes) - if relative.seconds and minimum_unit >= UNIT_SECOND and len(out) < max_units: - out.append("%ds" % relative.seconds) + if hours and len(out) < max_units: + out.append("%dh" % hours) + if minutes and len(out) < max_units: + out.append("%dmi" % minutes) + if seconds and len(out) < max_units: + out.append("%ds" % seconds) return " ".join(out) +def to_pretty_since(total_seconds: int, max_units: int=UNIT_MINIMUM + ) -> str: + return to_pretty_time(total_seconds, max_units, RelativeDirection.BACKWARD) +def to_pretty_until(total_seconds: int, max_units: int=UNIT_MINIMUM + ) -> str: + return to_pretty_time(total_seconds, max_units, RelativeDirection.FORWARD)