diff --git a/evennia/contrib/game_systems/mail/mail.py b/evennia/contrib/game_systems/mail/mail.py index 6127d1af9d..1315a4e764 100644 --- a/evennia/contrib/game_systems/mail/mail.py +++ b/evennia/contrib/game_systems/mail/mail.py @@ -45,7 +45,7 @@ import re from evennia import AccountDB, ObjectDB, default_cmds from evennia.comms.models import Msg -from evennia.utils import create, datetime_format, evtable, inherits_from, make_iter +from evennia.utils import create, datetime_format, evtable, inherits_from, make_iter, utc_to_local _HEAD_CHAR = "|015-|n" _SUB_HEAD_CHAR = "-" @@ -164,6 +164,7 @@ class CmdMail(default_cmds.MuxAccountCommand): subject = "" body = "" + time_zone = self.account.options.get("timezone") if self.switches or self.args: if "delete" in self.switches or "del" in self.switches: @@ -296,9 +297,10 @@ class CmdMail(default_cmds.MuxAccountCommand): ) # note that we cannot use %-d format here since Windows does not support it day = message.db_date_created.day + date_created = utc_to_local(message.db_date_created, time_zone) messageForm.append( "|wSent:|n %s" - % message.db_date_created.strftime(f"%b {day}, %Y - %H:%M:%S") + % date_created.strftime(f"%b {day}, %Y - %H:%M:%S") ) messageForm.append("|wSubject:|n %s" % message.header) messageForm.append(_SUB_HEAD_CHAR * _WIDTH) @@ -330,11 +332,12 @@ class CmdMail(default_cmds.MuxAccountCommand): if status == "NEW": status = "|gNEW|n" + date_created = utc_to_local(message.db_date_created, time_zone) table.add_row( index, message.senders[0].get_display_name(self.caller), message.header, - datetime_format(message.db_date_created), + datetime_format(date_created, time_zone), status, ) index += 1 diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 8a7daebffa..5f1478d420 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -21,6 +21,7 @@ import textwrap import threading import traceback import types +import pytz from ast import literal_eval from collections import OrderedDict, defaultdict from inspect import getmembers, getmodule, getmro, ismodule, trace @@ -682,13 +683,16 @@ def time_format(seconds, style=0): return retval.strip() -def datetime_format(dtobj): +def datetime_format(dtobj, time_zone=None): """ Pretty-prints the time since a given time. Args: dtobj (datetime): An datetime object, e.g. from Django's `DateTimeField`. + time_zone (tzfile): If provided, the current date/time is + adjusted to the given time zone for the elapsed time + calculations. This should be used if `dtobj` is not UTC. Returns: deltatime (str): A string describing how long ago `dtobj` @@ -697,6 +701,8 @@ def datetime_format(dtobj): """ now = timezone.now() + if time_zone: + now = utc_to_local(now, time_zone) if dtobj.year < now.year: # another year (Apr 5, 2019) @@ -3124,3 +3130,23 @@ def value_is_integer(value): return False return True + + +def utc_to_local(utc_time, time_zone): + """ + Convert a date/time from UTC to a local date/time based on `timezone`. + + Args: + utc_time (datetime): The time to convert. + time_zone (tzfile): The time zone to convert to. + + Returns + result (datetime): The converted time. + """ + if not time_zone: + return utc_time + # don't convert a time that's not UTC + if utc_time.utcoffset().total_seconds() != 0: + return utc_time + + return utc_time.replace(tzinfo=pytz.utc).astimezone(time_zone)