Clean up timestamps.py and add a test.

This commit is contained in:
Rishi Gupta 2017-02-28 09:39:36 -08:00 committed by Tim Abbott
parent 95f5c96bec
commit 4dc791f393
4 changed files with 54 additions and 35 deletions

View File

@ -15,7 +15,6 @@ from django.conf import settings
from analytics.models import RealmCount, UserCount
from analytics.lib.counts import COUNT_STATS, logger, process_count_stat
from zerver.lib.timestamp import datetime_to_string, is_timezone_aware
from zerver.models import UserProfile, Message
from typing import Any
@ -30,7 +29,7 @@ class Command(BaseCommand):
parser.add_argument('--time', '-t',
type=str,
help='Update stat tables from current state to --time. Defaults to the current time.',
default=datetime_to_string(timezone.now()))
default=timezone.now().isoformat())
parser.add_argument('--utc',
type=bool,
help="Interpret --time in UTC.",
@ -61,7 +60,7 @@ class Command(BaseCommand):
if options['utc']:
fill_to_time = fill_to_time.replace(tzinfo=timezone.utc)
if not (is_timezone_aware(fill_to_time)):
if fill_to_time.tzinfo is None:
raise ValueError("--time must be timezone aware. Maybe you meant to use the --utc option?")
logger.info("Starting updating analytics counts through %s" % (fill_to_time,))

View File

@ -3,7 +3,7 @@ from django.utils import timezone
from zerver.models import Realm, UserProfile, Stream, Recipient
from zerver.lib.str_utils import ModelReprMixin
from zerver.lib.timestamp import datetime_to_UTC, floor_to_day
from zerver.lib.timestamp import floor_to_day
import datetime
@ -29,7 +29,7 @@ class FillState(ModelReprMixin, models.Model):
def installation_epoch():
# type: () -> datetime.datetime
earliest_realm_creation = Realm.objects.aggregate(models.Min('date_created'))['date_created__min']
return floor_to_day(datetime_to_UTC(earliest_realm_creation))
return floor_to_day(earliest_realm_creation)
def last_successful_fill(property):
# type: (str) -> Optional[datetime.datetime]

View File

@ -4,37 +4,27 @@ import datetime
import calendar
from django.utils import timezone
def is_timezone_aware(datetime_object):
# type: (datetime.datetime) -> bool
return datetime_object.tzinfo is not None
def datetime_to_UTC(datetime_object):
def floor_to_hour(dt):
# type: (datetime.datetime) -> datetime.datetime
if is_timezone_aware(datetime_object):
return datetime_object.astimezone(timezone.utc)
return datetime_object.replace(tzinfo=timezone.utc)
return datetime.datetime(*dt.timetuple()[:4]) \
.replace(tzinfo=dt.tzinfo)
def floor_to_hour(datetime_object):
def floor_to_day(dt):
# type: (datetime.datetime) -> datetime.datetime
return datetime.datetime(*datetime_object.timetuple()[:4]) \
.replace(tzinfo=datetime_object.tzinfo)
return datetime.datetime(*dt.timetuple()[:3]) \
.replace(tzinfo=dt.tzinfo)
def floor_to_day(datetime_object):
def ceiling_to_hour(dt):
# type: (datetime.datetime) -> datetime.datetime
return datetime.datetime(*datetime_object.timetuple()[:3]) \
.replace(tzinfo=datetime_object.tzinfo)
def ceiling_to_hour(datetime_object):
# type: (datetime.datetime) -> datetime.datetime
floor = floor_to_hour(datetime_object)
if floor == datetime_object:
floor = floor_to_hour(dt)
if floor == dt:
return floor
return floor + datetime.timedelta(hours=1)
def ceiling_to_day(datetime_object):
def ceiling_to_day(dt):
# type: (datetime.datetime) -> datetime.datetime
floor = floor_to_day(datetime_object)
if floor == datetime_object:
floor = floor_to_day(dt)
if floor == dt:
return floor
return floor + datetime.timedelta(days=1)
@ -42,12 +32,11 @@ def timestamp_to_datetime(timestamp):
# type: (float) -> datetime.datetime
return datetime.datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
def datetime_to_timestamp(datetime_object):
# type: (datetime.datetime) -> int
return calendar.timegm(datetime_object.timetuple())
class TimezoneNotUTCException(Exception):
pass
def datetime_to_string(datetime_object):
# type: (datetime.datetime) -> str
assert is_timezone_aware(datetime_object)
date_string = datetime_object.strftime('%Y-%m-%d %H:%M:%S%z')
return date_string
def datetime_to_timestamp(dt):
# type: (datetime.datetime) -> int
if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) != timezone.utc.utcoffset(dt):
raise TimezoneNotUTCException("Datetime %s to be converted does not have a UTC timezone." % (dt,))
return calendar.timegm(dt.timetuple())

View File

@ -0,0 +1,31 @@
from __future__ import absolute_import
from django.utils import timezone
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.timestamp import floor_to_hour, floor_to_day, ceiling_to_hour, \
ceiling_to_day, timestamp_to_datetime, datetime_to_timestamp, \
TimezoneNotUTCException
from datetime import datetime, timedelta
from dateutil import parser
import pytz
from six.moves import zip
class TestTimestamp(ZulipTestCase):
def test_datetime_and_timestamp_conversions(self):
# type: () -> None
timestamp = 1483228800
for dt in [
parser.parse('2017-01-01 00:00:00.123 UTC'),
parser.parse('2017-01-01 00:00:00.123').replace(tzinfo=timezone.utc),
parser.parse('2017-01-01 00:00:00.123').replace(tzinfo=pytz.utc)]:
self.assertEqual(timestamp_to_datetime(timestamp), dt-timedelta(microseconds=123000))
self.assertEqual(datetime_to_timestamp(dt), timestamp)
for dt in [
parser.parse('2017-01-01 00:00:00.123+01:00'),
parser.parse('2017-01-01 00:00:00.123')]:
with self.assertRaises(TimezoneNotUTCException):
datetime_to_timestamp(dt)