Files
zulip/zerver/lib/timestamp.py
Rishi Gupta 0596c4a810 analytics: Enforce various datetime arguments are in UTC.
Sort of a hacky hammer, but
* The original design of the analytics system mistakenly attempted to play
  nicely with non-UTC datetimes.
* Timezone errors are really hard to find and debug, and don't jump out that
  easily when reading code.

I don't know of any outstanding errors, but putting a few "assert this
timezone is in UTC" around will hopefully reduce the chance that there are
any current or future timezone errors.

Note that none of these functions are called outside of the analytics code
(and tests). This commit also doesn't change any current behavior, assuming
a database where all datetimes have been being stored in UTC.
2017-10-05 11:22:06 -07:00

53 lines
1.6 KiB
Python

import datetime
import calendar
from django.utils.timezone import utc as timezone_utc
class TimezoneNotUTCException(Exception):
pass
def verify_UTC(dt):
# type: (datetime.datetime) -> None
if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) != timezone_utc.utcoffset(dt):
raise TimezoneNotUTCException("Datetime %s does not have a UTC timezone." % (dt,))
def convert_to_UTC(dt):
# type: (datetime.datetime) -> datetime.datetime
if dt.tzinfo is None:
return dt.replace(tzinfo=timezone_utc)
return dt.astimezone(timezone_utc)
def floor_to_hour(dt):
# type: (datetime.datetime) -> datetime.datetime
verify_UTC(dt)
return datetime.datetime(*dt.timetuple()[:4]) \
.replace(tzinfo=timezone_utc)
def floor_to_day(dt):
# type: (datetime.datetime) -> datetime.datetime
verify_UTC(dt)
return datetime.datetime(*dt.timetuple()[:3]) \
.replace(tzinfo=timezone_utc)
def ceiling_to_hour(dt):
# type: (datetime.datetime) -> datetime.datetime
floor = floor_to_hour(dt)
if floor == dt:
return floor
return floor + datetime.timedelta(hours=1)
def ceiling_to_day(dt):
# type: (datetime.datetime) -> datetime.datetime
floor = floor_to_day(dt)
if floor == dt:
return floor
return floor + datetime.timedelta(days=1)
def timestamp_to_datetime(timestamp):
# type: (float) -> datetime.datetime
return datetime.datetime.fromtimestamp(float(timestamp), tz=timezone_utc)
def datetime_to_timestamp(dt):
# type: (datetime.datetime) -> int
verify_UTC(dt)
return calendar.timegm(dt.timetuple())