timezone: Use standard library datetime.timezone.utc consistently.

datetime.timezone is available in Python ≥ 3.2.  This also lets us
remove a pytz dependency from the PostgreSQL scripts.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-06-04 21:55:20 -07:00 committed by Tim Abbott
parent 29b8e11e20
commit 1f565a9f41
20 changed files with 75 additions and 102 deletions

View File

@ -2,14 +2,13 @@ import datetime
from typing import Any, Dict
from django.core.management.base import BaseCommand, CommandParser
from django.utils.timezone import utc
from zerver.lib.statistics import seconds_usage_between
from zerver.models import UserProfile
def analyze_activity(options: Dict[str, Any]) -> None:
day_start = datetime.datetime.strptime(options["date"], "%Y-%m-%d").replace(tzinfo=utc)
day_start = datetime.datetime.strptime(options["date"], "%Y-%m-%d").replace(tzinfo=datetime.timezone.utc)
day_end = day_start + datetime.timedelta(days=options["duration"])
user_profile_query = UserProfile.objects.all()

View File

@ -2,12 +2,12 @@ import os
import time
from argparse import ArgumentParser
from typing import Any, Dict
from datetime import timezone
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils.dateparse import parse_datetime
from django.utils.timezone import now as timezone_now
from django.utils.timezone import utc as timezone_utc
from analytics.lib.counts import COUNT_STATS, logger, process_count_stat
from scripts.lib.zulip_tools import ENDC, WARNING
@ -60,11 +60,11 @@ class Command(BaseCommand):
fill_to_time = parse_datetime(options['time'])
if options['utc']:
fill_to_time = fill_to_time.replace(tzinfo=timezone_utc)
fill_to_time = fill_to_time.replace(tzinfo=timezone.utc)
if fill_to_time.tzinfo is None:
raise ValueError("--time must be timezone aware. Maybe you meant to use the --utc option?")
fill_to_time = floor_to_hour(fill_to_time.astimezone(timezone_utc))
fill_to_time = floor_to_hour(fill_to_time.astimezone(timezone.utc))
if options['stat'] is not None:
stats = [COUNT_STATS[options['stat']]]

View File

@ -1,4 +1,4 @@
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional, Tuple, Type
from unittest import mock
@ -8,7 +8,6 @@ from django.db import models
from django.db.models import Sum
from django.test import TestCase
from django.utils.timezone import now as timezone_now
from django.utils.timezone import utc as timezone_utc
from analytics.lib.counts import COUNT_STATS, CountStat, get_count_stats, \
DependentCountStat, LoggingCountStat, do_aggregate_to_summary_table, \
@ -33,7 +32,7 @@ class AnalyticsTestCase(TestCase):
MINUTE = timedelta(seconds = 60)
HOUR = MINUTE * 60
DAY = HOUR * 24
TIME_ZERO = datetime(1988, 3, 14).replace(tzinfo=timezone_utc)
TIME_ZERO = datetime(1988, 3, 14, tzinfo=timezone.utc)
TIME_LAST_HOUR = TIME_ZERO - HOUR
def setUp(self) -> None:

View File

@ -1,8 +1,7 @@
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from typing import List, Optional
from unittest import mock
from django.utils.timezone import utc
from django.http import HttpResponse
import ujson
from django.utils.timezone import now as timezone_now
@ -607,8 +606,8 @@ class TestGetChartDataHelpers(ZulipTestCase):
# the only function that uses it at the moment
def test_last_successful_fill(self) -> None:
self.assertIsNone(last_successful_fill('non-existant'))
a_time = datetime(2016, 3, 14, 19).replace(tzinfo=utc)
one_hour_before = datetime(2016, 3, 14, 18).replace(tzinfo=utc)
a_time = datetime(2016, 3, 14, 19, tzinfo=timezone.utc)
one_hour_before = datetime(2016, 3, 14, 18, tzinfo=timezone.utc)
fillstate = FillState.objects.create(property='property', end_time=a_time,
state=FillState.DONE)
self.assertEqual(last_successful_fill('property'), a_time)
@ -631,9 +630,9 @@ class TestTimeRange(ZulipTestCase):
HOUR = timedelta(hours=1)
DAY = timedelta(days=1)
a_time = datetime(2016, 3, 14, 22, 59).replace(tzinfo=utc)
floor_hour = datetime(2016, 3, 14, 22).replace(tzinfo=utc)
floor_day = datetime(2016, 3, 14).replace(tzinfo=utc)
a_time = datetime(2016, 3, 14, 22, 59, tzinfo=timezone.utc)
floor_hour = datetime(2016, 3, 14, 22, tzinfo=timezone.utc)
floor_day = datetime(2016, 3, 14, tzinfo=timezone.utc)
# test start == end
self.assertEqual(time_range(a_time, a_time, CountStat.HOUR, None), [])

View File

@ -4,7 +4,7 @@ import re
import time
import urllib
from collections import defaultdict
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from typing import Any, Callable, Dict, List, \
@ -18,7 +18,7 @@ from django.db.models.query import QuerySet
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
from django.shortcuts import render
from django.template import loader
from django.utils.timezone import now as timezone_now, utc as timezone_utc
from django.utils.timezone import now as timezone_now
from django.utils.translation import ugettext as _
from django.utils.timesince import timesince
from django.core.validators import URLValidator
@ -253,7 +253,7 @@ def get_chart_data(request: HttpRequest, user_profile: UserProfile, chart_name:
start = realm.date_created
if end is None:
end = max(last_successful_fill(stat.property) or
datetime.min.replace(tzinfo=timezone_utc) for stat in stats)
datetime.min.replace(tzinfo=timezone.utc) for stat in stats)
if start > end and (timezone_now() - start > MAX_TIME_FOR_FULL_ANALYTICS_GENERATION):
logging.warning("User from realm %s attempted to access /stats, but the computed "

View File

@ -1,4 +1,4 @@
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from functools import wraps
from unittest.mock import Mock, patch
@ -14,7 +14,6 @@ import responses
from django.core import signing
from django.urls.resolvers import get_resolver
from django.http import HttpResponse
from django.utils.timezone import utc as timezone_utc
from django.conf import settings
from django.utils.timezone import now as timezone_now
@ -265,9 +264,9 @@ class StripeTestCase(ZulipTestCase):
self.signed_seat_count, self.salt = sign_string(str(self.seat_count))
# Choosing dates with corresponding timestamps below 1500000000 so that they are
# not caught by our timestamp normalization regex in normalize_fixture_data
self.now = datetime(2012, 1, 2, 3, 4, 5).replace(tzinfo=timezone_utc)
self.next_month = datetime(2012, 2, 2, 3, 4, 5).replace(tzinfo=timezone_utc)
self.next_year = datetime(2013, 1, 2, 3, 4, 5).replace(tzinfo=timezone_utc)
self.now = datetime(2012, 1, 2, 3, 4, 5, tzinfo=timezone.utc)
self.next_month = datetime(2012, 2, 2, 3, 4, 5, tzinfo=timezone.utc)
self.next_year = datetime(2013, 1, 2, 3, 4, 5, tzinfo=timezone.utc)
def get_signed_seat_count_from_response(self, response: HttpResponse) -> Optional[str]:
match = re.search(r'name=\"signed_seat_count\" value=\"(.+)\"', response.content.decode("utf-8"))
@ -1552,24 +1551,24 @@ class RequiresBillingAccessTest(ZulipTestCase):
class BillingHelpersTest(ZulipTestCase):
def test_next_month(self) -> None:
anchor = datetime(2019, 12, 31, 1, 2, 3).replace(tzinfo=timezone_utc)
anchor = datetime(2019, 12, 31, 1, 2, 3, tzinfo=timezone.utc)
period_boundaries = [
anchor,
datetime(2020, 1, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 1, 31, 1, 2, 3, tzinfo=timezone.utc),
# Test that this is the 28th even during leap years
datetime(2020, 2, 28, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 3, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 4, 30, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 5, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 6, 30, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 7, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 8, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 9, 30, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 10, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 11, 30, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2020, 12, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2021, 1, 31, 1, 2, 3).replace(tzinfo=timezone_utc),
datetime(2021, 2, 28, 1, 2, 3).replace(tzinfo=timezone_utc)]
datetime(2020, 2, 28, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 3, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 4, 30, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 5, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 6, 30, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 7, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 8, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 9, 30, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 10, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 11, 30, 1, 2, 3, tzinfo=timezone.utc),
datetime(2020, 12, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2021, 1, 31, 1, 2, 3, tzinfo=timezone.utc),
datetime(2021, 2, 28, 1, 2, 3, tzinfo=timezone.utc)]
with self.assertRaises(AssertionError):
add_months(anchor, -1)
# Explicitly test add_months for each value of MAX_DAY_FOR_MONTH and
@ -1586,9 +1585,9 @@ class BillingHelpersTest(ZulipTestCase):
def test_compute_plan_parameters(self) -> None:
# TODO: test rounding down microseconds
anchor = datetime(2019, 12, 31, 1, 2, 3).replace(tzinfo=timezone_utc)
month_later = datetime(2020, 1, 31, 1, 2, 3).replace(tzinfo=timezone_utc)
year_later = datetime(2020, 12, 31, 1, 2, 3).replace(tzinfo=timezone_utc)
anchor = datetime(2019, 12, 31, 1, 2, 3, tzinfo=timezone.utc)
month_later = datetime(2020, 1, 31, 1, 2, 3, tzinfo=timezone.utc)
year_later = datetime(2020, 12, 31, 1, 2, 3, tzinfo=timezone.utc)
test_cases = [
# TODO test with Decimal(85), not 85
# TODO fix the mypy error by specifying the exact type

View File

@ -153,19 +153,19 @@ Python allows datetime objects to not have an associated timezone, which can
cause time-related bugs that are hard to catch with a test suite, or bugs
that only show up during daylight savings time.
Good ways to make timezone-aware datetimes are below. We import `timezone`
functions as `from django.utils.timezone import now as timezone_now` and
`from django.utils.timezone import utc as timezone_utc`.
Good ways to make timezone-aware datetimes are below. We import timezone
libraries as `from datetime import datetime, timezone` and `from
django.utils.timezone import now as timezone_now`.
Use:
* `timezone_now()` to get a datetime when Django is available, such as
in `zerver/`.
* `datetime.now(tz=pytz.utc)` when Django is not available, such as
* `datetime.now(tz=timezone.utc)` when Django is not available, such as
for bots and scripts.
* `datetime.fromtimestamp(timestamp, tz=timezone_utc)` if creating a
* `datetime.fromtimestamp(timestamp, tz=timezone.utc)` if creating a
datetime from a timestamp. This is also available as
`zerver.lib.timestamp.timestamp_to_datetime`.
* `datetime.strptime(date_string, format).replace(tzinfo=timezone_utc)` if
* `datetime.strptime(date_string, format).replace(tzinfo=timezone.utc)` if
creating a datetime from a formatted string that is in UTC.
Idioms that result in timezone-naive datetimes, and should be avoided, are

View File

@ -1,10 +1,9 @@
#!/usr/bin/env python3
import subprocess
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
import dateutil.parser
import pytz
states = {
"OK": 0,
@ -28,7 +27,7 @@ try:
except OSError:
report('UNKNOWN', 'could not determine completion time of last Postgres backup')
if datetime.now(tz=pytz.utc) - last_backup > timedelta(hours=25):
if datetime.now(tz=timezone.utc) - last_backup > timedelta(hours=25):
report('CRITICAL', 'last Postgres backup completed more than 25 hours ago: %s' % (last_backup,))
report('OK', 'last Postgres backup completed less than 25 hours ago: %s' % (last_backup,))

View File

@ -7,9 +7,8 @@ import shlex
import subprocess
import logging
import dateutil.parser
import pytz
import time
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from typing import Dict, List
logging.Formatter.converter = time.gmtime
@ -48,7 +47,7 @@ if len(pg_data_paths) != 1:
pg_data_path = pg_data_paths[0]
run(['env-wal-e', 'backup-push', pg_data_path])
now = datetime.now(tz=pytz.utc)
now = datetime.now(tz=timezone.utc)
with open('/var/lib/nagios_state/last_postgres_backup', 'w') as f:
f.write(now.isoformat())
f.write("\n")

View File

@ -15,10 +15,7 @@ class zulip::postgres_common {
# Postgres Nagios check plugin
'check-postgres',
# Python modules used in our monitoring/worker threads
'python3-tz', # TODO: use a virtualenv instead
'python-tz', # TODO: use a virtualenv instead
'python3-dateutil', # TODO: use a virtualenv instead
'python-dateutil', # TODO: use a virtualenv instead
]
$postgres_user_reqs = [
Package[$postgresql],
@ -39,12 +36,8 @@ class zulip::postgres_common {
# https://bucardo.org/check_postgres/
# 'check-postgres', # TODO
]
exec {'pip2_deps':
# Python modules used in our monitoring/worker threads
command => '/usr/bin/pip2 install pytz python-dateutil'
}
exec {'pip3_deps':
command => 'python3 -m pip install pytz python-dateutil'
command => 'python3 -m pip install python-dateutil'
}
group { 'ssl-cert':
ensure => present,

View File

@ -3,7 +3,6 @@ from typing import Any, Dict, List, Set, Tuple, Union
from collections import defaultdict
import datetime
import logging
import pytz
from django.conf import settings
from django.utils.timezone import now as timezone_now
@ -168,7 +167,7 @@ def handle_digest_email(user_profile_id: int, cutoff: float,
user_profile = get_user_profile_by_id(user_profile_id)
# Convert from epoch seconds to a datetime object.
cutoff_date = datetime.datetime.fromtimestamp(int(cutoff), tz=pytz.utc)
cutoff_date = datetime.datetime.fromtimestamp(int(cutoff), tz=datetime.timezone.utc)
context = common_context(user_profile)

View File

@ -9,7 +9,7 @@ from bs4 import BeautifulSoup
from django.conf import settings
from django.db import connection
from django.db.models import Max
from django.utils.timezone import utc as timezone_utc, now as timezone_now
from django.utils.timezone import now as timezone_now
from typing import Any, Dict, List, Optional, Set, Tuple, \
Iterable, cast
@ -109,7 +109,7 @@ def fix_datetime_fields(data: TableData, table: TableName) -> None:
for item in data[table]:
for field_name in DATE_FIELDS[table]:
if item[field_name] is not None:
item[field_name] = datetime.datetime.fromtimestamp(item[field_name], tz=timezone_utc)
item[field_name] = datetime.datetime.fromtimestamp(item[field_name], tz=datetime.timezone.utc)
def fix_upload_links(data: TableData, message_table: TableName) -> None:
"""

View File

@ -1,14 +1,13 @@
# System documented in https://zulip.readthedocs.io/en/latest/subsystems/logging.html
from django.utils.timezone import now as timezone_now
from django.utils.timezone import utc as timezone_utc
import hashlib
import logging
import threading
import traceback
from typing import Optional, Tuple
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from django.conf import settings
from django.core.cache import cache
from logging import Logger
@ -28,7 +27,7 @@ class _RateLimitFilter:
Adapted from https://djangosnippets.org/snippets/2242/.
"""
last_error = datetime.min.replace(tzinfo=timezone_utc)
last_error = datetime.min.replace(tzinfo=timezone.utc)
# This thread-local variable is used to detect recursive
# exceptions during exception handling (primarily intended for
# when accessing the shared cache throws an exception).

View File

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

View File

@ -3,7 +3,6 @@ import time
from typing import Any
from django.core.management.base import CommandParser
from django.utils.timezone import utc as timezone_utc
from zerver.lib.management import ZulipBaseCommand
from zerver.models import Message, Recipient, Stream
@ -26,7 +25,7 @@ class Command(ZulipBaseCommand):
streams = Stream.objects.filter(realm=realm, invite_only=False)
recipients = Recipient.objects.filter(
type=Recipient.STREAM, type_id__in=[stream.id for stream in streams])
cutoff = datetime.datetime.fromtimestamp(options["since"], tz=timezone_utc)
cutoff = datetime.datetime.fromtimestamp(options["since"], tz=datetime.timezone.utc)
messages = Message.objects.filter(date_sent__gt=cutoff, recipient__in=recipients)
for message in messages:

View File

@ -17,7 +17,6 @@ from django.http import HttpResponse
from django.db import transaction
from django.db.models import F
from django.utils.crypto import get_random_string
from django.utils.timezone import utc as timezone_utc
from analytics.lib.counts import CountStat, LoggingCountStat
from analytics.models import InstallationCount, RealmCount
@ -383,7 +382,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
self.assertEqual(len(tokens), 0)
class AnalyticsBouncerTest(BouncerTestCase):
TIME_ZERO = datetime.datetime(1988, 3, 14).replace(tzinfo=timezone_utc)
TIME_ZERO = datetime.datetime(1988, 3, 14, tzinfo=datetime.timezone.utc)
@override_settings(PUSH_NOTIFICATION_BOUNCER_URL='https://push.zulip.org.example.com')
@mock.patch('zerver.lib.remote_server.requests.request')

View File

@ -81,7 +81,6 @@ import ujson
from typing import Any, List, Optional
import urllib
import pytz
class RedirectAndLogIntoSubdomainTestCase(ZulipTestCase):
def test_data(self) -> None:
@ -4087,22 +4086,22 @@ class FollowupEmailTest(ZulipTestCase):
def test_followup_day2_email(self) -> None:
user_profile = self.example_user('hamlet')
# Test date_joined == Sunday
user_profile.date_joined = datetime.datetime(2018, 1, 7, 1, 0, 0, 0, pytz.UTC)
user_profile.date_joined = datetime.datetime(2018, 1, 7, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
self.assertEqual(followup_day2_email_delay(user_profile), datetime.timedelta(days=2, hours=-1))
# Test date_joined == Tuesday
user_profile.date_joined = datetime.datetime(2018, 1, 2, 1, 0, 0, 0, pytz.UTC)
user_profile.date_joined = datetime.datetime(2018, 1, 2, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
self.assertEqual(followup_day2_email_delay(user_profile), datetime.timedelta(days=2, hours=-1))
# Test date_joined == Thursday
user_profile.date_joined = datetime.datetime(2018, 1, 4, 1, 0, 0, 0, pytz.UTC)
user_profile.date_joined = datetime.datetime(2018, 1, 4, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
self.assertEqual(followup_day2_email_delay(user_profile), datetime.timedelta(days=1, hours=-1))
# Test date_joined == Friday
user_profile.date_joined = datetime.datetime(2018, 1, 5, 1, 0, 0, 0, pytz.UTC)
user_profile.date_joined = datetime.datetime(2018, 1, 5, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
self.assertEqual(followup_day2_email_delay(user_profile), datetime.timedelta(days=3, hours=-1))
# Time offset of America/Phoenix is -07:00
user_profile.timezone = 'America/Phoenix'
# Test date_joined == Friday in UTC, but Thursday in the user's timezone
user_profile.date_joined = datetime.datetime(2018, 1, 5, 1, 0, 0, 0, pytz.UTC)
user_profile.date_joined = datetime.datetime(2018, 1, 5, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
self.assertEqual(followup_day2_email_delay(user_profile), datetime.timedelta(days=1, hours=-1))
class NoReplyEmailTest(ZulipTestCase):

View File

@ -1,21 +1,17 @@
from django.utils.timezone import utc as timezone_utc
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.timestamp import floor_to_hour, floor_to_day, ceiling_to_hour, \
timestamp_to_datetime, datetime_to_timestamp, \
TimezoneNotUTCException, convert_to_UTC
from datetime import timedelta
from datetime import timedelta, timezone
from dateutil import parser
import pytz
class TestTimestamp(ZulipTestCase):
def test_datetime_and_timestamp_conversions(self) -> 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)]:
parser.parse('2017-01-01 00:00:00.123').replace(tzinfo=timezone.utc)]:
self.assertEqual(timestamp_to_datetime(timestamp), dt-timedelta(microseconds=123000))
self.assertEqual(datetime_to_timestamp(dt), timestamp)
@ -28,7 +24,7 @@ class TestTimestamp(ZulipTestCase):
def test_convert_to_UTC(self) -> None:
utc_datetime = parser.parse('2017-01-01 00:00:00.123 UTC')
for dt in [
parser.parse('2017-01-01 00:00:00.123').replace(tzinfo=timezone_utc),
parser.parse('2017-01-01 00:00:00.123').replace(tzinfo=timezone.utc),
parser.parse('2017-01-01 00:00:00.123'),
parser.parse('2017-01-01 05:00:00.123+05')]:
self.assertEqual(convert_to_UTC(dt), utc_datetime)

View File

@ -1,9 +1,8 @@
from datetime import datetime
from datetime import datetime, timezone
from typing import Any, Callable, Dict, List, Tuple
import ujson
from django.http import HttpRequest, HttpResponse
from django.utils.timezone import utc as timezone_utc
from django.utils.translation import ugettext as _
from zerver.decorator import api_key_only_webhook_view
@ -41,7 +40,7 @@ class LibratoWebhookParser:
def parse_violation(self, violation: Dict[str, Any]) -> Tuple[str, str]:
metric_name = violation['metric']
recorded_at = datetime.fromtimestamp((violation['recorded_at']),
tz=timezone_utc).strftime('%Y-%m-%d %H:%M:%S')
tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
return metric_name, recorded_at
def parse_conditions(self) -> List[Dict[str, Any]]:
@ -90,7 +89,7 @@ class LibratoWebhookHandler(LibratoWebhookParser):
def handle_alert_clear_message(self) -> str:
alert_clear_template = "Alert [alert_name]({alert_url}) has cleared at {trigger_time} UTC!"
trigger_time = datetime.fromtimestamp((self.payload['trigger_time']),
tz=timezone_utc).strftime('%Y-%m-%d %H:%M:%S')
tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
alert_id, alert_name, alert_url, alert_runbook_url = self.parse_alert()
content = alert_clear_template.format(alert_name=alert_name,
alert_url=alert_url,

View File

@ -7,7 +7,6 @@ from django.core.validators import validate_email, URLValidator
from django.db import IntegrityError, transaction
from django.http import HttpRequest, HttpResponse
from django.utils import timezone
from django.utils.timezone import utc as timezone_utc
from django.utils.translation import ugettext as _, ugettext as err_
from django.views.decorators.csrf import csrf_exempt
@ -224,7 +223,7 @@ def remote_server_post_analytics(request: HttpRequest,
realm_id=row['realm'],
remote_id=row['id'],
server=server,
end_time=datetime.datetime.fromtimestamp(row['end_time'], tz=timezone_utc),
end_time=datetime.datetime.fromtimestamp(row['end_time'], tz=datetime.timezone.utc),
subgroup=row['subgroup'],
value=row['value']) for row in realm_counts]
batch_create_table_data(server, RemoteRealmCount, row_objects)
@ -233,7 +232,7 @@ def remote_server_post_analytics(request: HttpRequest,
property=row['property'],
remote_id=row['id'],
server=server,
end_time=datetime.datetime.fromtimestamp(row['end_time'], tz=timezone_utc),
end_time=datetime.datetime.fromtimestamp(row['end_time'], tz=datetime.timezone.utc),
subgroup=row['subgroup'],
value=row['value']) for row in installation_counts]
batch_create_table_data(server, RemoteInstallationCount, row_objects)
@ -243,7 +242,7 @@ def remote_server_post_analytics(request: HttpRequest,
realm_id=row['realm'],
remote_id=row['id'],
server=server,
event_time=datetime.datetime.fromtimestamp(row['event_time'], tz=timezone_utc),
event_time=datetime.datetime.fromtimestamp(row['event_time'], tz=datetime.timezone.utc),
backfilled=row['backfilled'],
extra_data=row['extra_data'],
event_type=row['event_type']) for row in realmauditlog_rows]