diff --git a/analytics/management/commands/analyze_user_activity.py b/analytics/management/commands/analyze_user_activity.py index 4b72fe3163..0e41d6deaa 100644 --- a/analytics/management/commands/analyze_user_activity.py +++ b/analytics/management/commands/analyze_user_activity.py @@ -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() diff --git a/analytics/management/commands/update_analytics_counts.py b/analytics/management/commands/update_analytics_counts.py index 61d603e9b9..886b744853 100644 --- a/analytics/management/commands/update_analytics_counts.py +++ b/analytics/management/commands/update_analytics_counts.py @@ -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']]] diff --git a/analytics/tests/test_counts.py b/analytics/tests/test_counts.py index 7e306cd45b..2d760fecd7 100644 --- a/analytics/tests/test_counts.py +++ b/analytics/tests/test_counts.py @@ -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: diff --git a/analytics/tests/test_views.py b/analytics/tests/test_views.py index c144f9e56b..21b129e02c 100644 --- a/analytics/tests/test_views.py +++ b/analytics/tests/test_views.py @@ -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), []) diff --git a/analytics/views.py b/analytics/views.py index dd5ca98cf3..f0ed1a4b1c 100644 --- a/analytics/views.py +++ b/analytics/views.py @@ -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 " diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index 5e2517afaa..94ec72b515 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -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 diff --git a/docs/contributing/code-style.md b/docs/contributing/code-style.md index 939f7b0d50..c94255364e 100644 --- a/docs/contributing/code-style.md +++ b/docs/contributing/code-style.md @@ -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 diff --git a/puppet/zulip/files/nagios_plugins/zulip_postgres_common/check_postgres_backup b/puppet/zulip/files/nagios_plugins/zulip_postgres_common/check_postgres_backup index ae05c16510..7b7ef54d0c 100755 --- a/puppet/zulip/files/nagios_plugins/zulip_postgres_common/check_postgres_backup +++ b/puppet/zulip/files/nagios_plugins/zulip_postgres_common/check_postgres_backup @@ -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,)) diff --git a/puppet/zulip/files/postgresql/pg_backup_and_purge b/puppet/zulip/files/postgresql/pg_backup_and_purge index f35b2a2749..1fed9ab152 100755 --- a/puppet/zulip/files/postgresql/pg_backup_and_purge +++ b/puppet/zulip/files/postgresql/pg_backup_and_purge @@ -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") diff --git a/puppet/zulip/manifests/postgres_common.pp b/puppet/zulip/manifests/postgres_common.pp index 17925a301b..de8c47f2d7 100644 --- a/puppet/zulip/manifests/postgres_common.pp +++ b/puppet/zulip/manifests/postgres_common.pp @@ -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, diff --git a/zerver/lib/digest.py b/zerver/lib/digest.py index 4b60d8f87f..d4192644f8 100644 --- a/zerver/lib/digest.py +++ b/zerver/lib/digest.py @@ -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) diff --git a/zerver/lib/import_realm.py b/zerver/lib/import_realm.py index adafc6ab1f..1d7a2066e1 100644 --- a/zerver/lib/import_realm.py +++ b/zerver/lib/import_realm.py @@ -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: """ diff --git a/zerver/lib/logging_util.py b/zerver/lib/logging_util.py index 96abac54b7..0018de4788 100644 --- a/zerver/lib/logging_util.py +++ b/zerver/lib/logging_util.py @@ -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). diff --git a/zerver/lib/timestamp.py b/zerver/lib/timestamp.py index 7159861cd0..7f4f47d64f 100644 --- a/zerver/lib/timestamp.py +++ b/zerver/lib/timestamp.py @@ -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) diff --git a/zerver/management/commands/dump_messages.py b/zerver/management/commands/dump_messages.py index d337ba14af..6a6e2daf3c 100644 --- a/zerver/management/commands/dump_messages.py +++ b/zerver/management/commands/dump_messages.py @@ -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: diff --git a/zerver/tests/test_push_notifications.py b/zerver/tests/test_push_notifications.py index 743b89a03d..cf30c849e6 100644 --- a/zerver/tests/test_push_notifications.py +++ b/zerver/tests/test_push_notifications.py @@ -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') diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index 7420a7dba2..a67d978300 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -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): diff --git a/zerver/tests/test_timestamp.py b/zerver/tests/test_timestamp.py index 243fb97b8e..cd2aa739c5 100644 --- a/zerver/tests/test_timestamp.py +++ b/zerver/tests/test_timestamp.py @@ -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) diff --git a/zerver/webhooks/librato/view.py b/zerver/webhooks/librato/view.py index 4c299e30e9..8a89f41be9 100644 --- a/zerver/webhooks/librato/view.py +++ b/zerver/webhooks/librato/view.py @@ -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, diff --git a/zilencer/views.py b/zilencer/views.py index 7630f60360..c39b9b697c 100644 --- a/zilencer/views.py +++ b/zilencer/views.py @@ -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]