diff options
Diffstat (limited to 'diplomacy/utils/time.py')
-rw-r--r-- | diplomacy/utils/time.py | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/diplomacy/utils/time.py b/diplomacy/utils/time.py new file mode 100644 index 0000000..6f250dd --- /dev/null +++ b/diplomacy/utils/time.py @@ -0,0 +1,85 @@ +# ============================================================================== +# Copyright (C) 2019 - Philip Paquette +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see <https://www.gnu.org/licenses/>. +# ============================================================================== +""" Time functions + - Contains generic time functions (e.g. to calculate deadlines) +""" +import calendar +import datetime +import math +import pytz + +def str_to_seconds(offset_str): + """ Converts a time in format 00W00D00H00M00S in number of seconds + :param offset_str: The string to convert (e.g. '20D') + :return: Its equivalent in seconds = 1728000 + """ + mult = {'W': 7 * 24 * 60 * 60, 'D': 24 * 60 * 60, 'H': 60 * 60, 'M': 60, 'S': 1, ' ': 1} + buffer = current_sum = 0 + offset_str = str(offset_str) + + # Adding digits to buffer, when a character is found, + # multiply it with buffer and increase the current_sum + for char in offset_str: + if char.isdigit(): + buffer = buffer * 10 + int(char) + elif char.upper() in mult: + current_sum += buffer * mult[char.upper()] + buffer = 0 + else: + buffer = 0 + current_sum += buffer + + return current_sum + +def trunc_time(timestamp, trunc_interval, time_zone='GMT'): + """ Truncates time at a specific interval (e.g. 20M) (i.e. Rounds to the next :20, :40, :60) + :param timestamp: The unix epoch to truncate (e.g. 1498746120) + :param trunc_interval: The truncation interval (e.g. 60*60 or '1H') + :param time_zone: The time to use for conversion (defaults to GMT otherwise) + :return: A timestamp truncated to the nearest (future) interval + """ + midnight_ts = calendar.timegm(datetime.datetime.combine(datetime.date.today(), datetime.time.min).utctimetuple()) + midnight_offset = (timestamp - midnight_ts) % (24*3600) + + dtime = datetime.datetime.fromtimestamp(timestamp, pytz.timezone(time_zone)) + tz_offset = dtime.utcoffset().total_seconds() + interval = str_to_seconds(trunc_interval) + trunc_offset = math.ceil((midnight_offset + tz_offset) / interval) * interval + + trunc_ts = timestamp - midnight_offset + trunc_offset - tz_offset + return int(trunc_ts) + +def next_time_at(timestamp, time_at, time_zone='GMT'): + """ Returns the next timestamp at a specific 'hh:mm' + :param timestamp: The unix timestamp to convert + :param time_at: The next 'hh:mm' to have the time rounded to, or 0 to skip + :param time_zone: The time to use for conversion (defaults to GMT otherwise) + :return: A timestamp truncated to the nearest (future) hh:mm + """ + if not time_at: + return timestamp + + midnight_ts = calendar.timegm(datetime.datetime.combine(datetime.date.today(), datetime.time.min).utctimetuple()) + midnight_offset = (timestamp - midnight_ts) % (24*3600) + + dtime = datetime.datetime.fromtimestamp(timestamp, pytz.timezone(time_zone)) + tz_offset = dtime.utcoffset().total_seconds() + trunc_interval = '%dH%dM' % (int(time_at.split(':')[0]), int(time_at.split(':')[1])) if ':' in time_at else time_at + interval = str_to_seconds(trunc_interval) + at_offset = (-midnight_offset + interval - tz_offset) % (24 * 3600) + at_ts = timestamp + at_offset + return int(at_ts) |