diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index cc5f93a8ff..7032b4b1f8 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -59,10 +59,8 @@ class SessionStore(SessionBase):
         Return the modification time of the file storing the session's content.
         """
         modification = os.stat(self._key_to_file()).st_mtime
-        if settings.USE_TZ:
-            modification = datetime.datetime.utcfromtimestamp(modification)
-            return modification.replace(tzinfo=timezone.utc)
-        return datetime.datetime.fromtimestamp(modification)
+        tz = timezone.utc if settings.USE_TZ else None
+        return datetime.datetime.fromtimestamp(modification, tz=tz)
 
     def _expiry_date(self, session_data):
         """
diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py
index bffdebb082..137049825f 100644
--- a/django/contrib/sitemaps/views.py
+++ b/django/contrib/sitemaps/views.py
@@ -1,5 +1,4 @@
 import datetime
-from calendar import timegm
 from functools import wraps
 
 from django.contrib.sites.shortcuts import get_current_site
@@ -7,6 +6,7 @@ from django.core.paginator import EmptyPage, PageNotAnInteger
 from django.http import Http404
 from django.template.response import TemplateResponse
 from django.urls import reverse
+from django.utils import timezone
 from django.utils.http import http_date
 
 
@@ -72,10 +72,10 @@ def sitemap(request, sitemaps, section=None,
             if all_sites_lastmod:
                 site_lastmod = getattr(site, 'latest_lastmod', None)
                 if site_lastmod is not None:
-                    site_lastmod = (
-                        site_lastmod.utctimetuple() if isinstance(site_lastmod, datetime.datetime)
-                        else site_lastmod.timetuple()
-                    )
+                    if not isinstance(site_lastmod, datetime.datetime):
+                        site_lastmod = datetime.datetime.combine(site_lastmod, datetime.time.min)
+                    if timezone.is_naive(site_lastmod):
+                        site_lastmod = timezone.make_aware(site_lastmod, timezone.utc)
                     lastmod = site_lastmod if lastmod is None else max(lastmod, site_lastmod)
                 else:
                     all_sites_lastmod = False
@@ -88,5 +88,5 @@ def sitemap(request, sitemaps, section=None,
     if all_sites_lastmod and lastmod is not None:
         # if lastmod is defined for all sites, set header so as
         # ConditionalGetMiddleware is able to send 304 NOT MODIFIED
-        response.headers['Last-Modified'] = http_date(timegm(lastmod))
+        response.headers['Last-Modified'] = http_date(lastmod.timestamp())
     return response
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index 6d567dd7db..7200907d7d 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -1,5 +1,3 @@
-from calendar import timegm
-
 from django.contrib.sites.shortcuts import get_current_site
 from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
 from django.http import Http404, HttpResponse
@@ -42,8 +40,7 @@ class Feed:
         if hasattr(self, 'item_pubdate') or hasattr(self, 'item_updateddate'):
             # if item_pubdate or item_updateddate is defined for the feed, set
             # header so as ConditionalGetMiddleware is able to send 304 NOT MODIFIED
-            response.headers['Last-Modified'] = http_date(
-                timegm(feedgen.latest_post_date().utctimetuple()))
+            response.headers['Last-Modified'] = http_date(feedgen.latest_post_date().timestamp())
         feedgen.write(response, 'utf-8')
         return response
 
diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py
index 905113903e..d62083a0f6 100644
--- a/django/core/cache/backends/db.py
+++ b/django/core/cache/backends/db.py
@@ -123,10 +123,9 @@ class DatabaseCache(BaseDatabaseCache):
             now = now.replace(microsecond=0)
             if timeout is None:
                 exp = datetime.max
-            elif settings.USE_TZ:
-                exp = datetime.utcfromtimestamp(timeout)
             else:
-                exp = datetime.fromtimestamp(timeout)
+                tz = timezone.utc if settings.USE_TZ else None
+                exp = datetime.fromtimestamp(timeout, tz=tz)
             exp = exp.replace(microsecond=0)
             if num > self._max_entries:
                 self._cull(db, cursor, now)
@@ -235,11 +234,7 @@ class DatabaseCache(BaseDatabaseCache):
         connection = connections[db]
         quote_name = connection.ops.quote_name
 
-        if settings.USE_TZ:
-            now = datetime.utcnow()
-        else:
-            now = datetime.now()
-        now = now.replace(microsecond=0)
+        now = timezone.now().replace(microsecond=0, tzinfo=None)
 
         with connection.cursor() as cursor:
             cursor.execute(
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index 8190791f9a..2cf5e2a5c7 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -347,11 +347,8 @@ class FileSystemStorage(Storage):
         If timezone support is enabled, make an aware datetime object in UTC;
         otherwise make a naive one in the local timezone.
         """
-        if settings.USE_TZ:
-            # Safe to use .replace() because UTC doesn't have DST
-            return datetime.utcfromtimestamp(ts).replace(tzinfo=timezone.utc)
-        else:
-            return datetime.fromtimestamp(ts)
+        tz = timezone.utc if settings.USE_TZ else None
+        return datetime.fromtimestamp(ts, tz=tz)
 
     def get_accessed_time(self, name):
         return self._datetime_from_timestamp(os.path.getatime(self.path(name)))
diff --git a/django/http/response.py b/django/http/response.py
index f1f0a1ed43..99f0020335 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -203,9 +203,9 @@ class HttpResponseBase:
         self.cookies[key] = value
         if expires is not None:
             if isinstance(expires, datetime.datetime):
-                if timezone.is_aware(expires):
-                    expires = timezone.make_naive(expires, timezone.utc)
-                delta = expires - expires.utcnow()
+                if timezone.is_naive(expires):
+                    expires = timezone.make_aware(expires, timezone.utc)
+                delta = expires - datetime.datetime.now(tz=timezone.utc)
                 # Add one second so the date matches exactly (a fraction of
                 # time gets lost between converting to a timedelta and
                 # then the date string).
diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py
index 4833b5af2c..0d4eb4bdf0 100644
--- a/django/utils/dateformat.py
+++ b/django/utils/dateformat.py
@@ -12,7 +12,6 @@ Usage:
 """
 import calendar
 import datetime
-import time
 from email.utils import format_datetime as format_datetime_rfc5322
 
 from django.utils.dates import (
@@ -20,7 +19,7 @@ from django.utils.dates import (
 )
 from django.utils.regex_helper import _lazy_re_compile
 from django.utils.timezone import (
-    _datetime_ambiguous_or_imaginary, get_default_timezone, is_aware, is_naive,
+    _datetime_ambiguous_or_imaginary, get_default_timezone, is_naive,
     make_aware,
 )
 from django.utils.translation import gettext as _
@@ -295,10 +294,10 @@ class DateFormat(TimeFormat):
 
     def U(self):
         "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
-        if isinstance(self.data, datetime.datetime) and is_aware(self.data):
-            return int(calendar.timegm(self.data.utctimetuple()))
-        else:
-            return int(time.mktime(self.data.timetuple()))
+        value = self.data
+        if not isinstance(value, datetime.datetime):
+            value = datetime.datetime.combine(value, datetime.time.min)
+        return int(value.timestamp())
 
     def w(self):
         "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py
index f08e89b25c..24b2d1d172 100644
--- a/django/utils/feedgenerator.py
+++ b/django/utils/feedgenerator.py
@@ -172,8 +172,7 @@ class SyndicationFeed:
                     if latest_date is None or item_date > latest_date:
                         latest_date = item_date
 
-        # datetime.now(tz=utc) is slower, as documented in django.utils.timezone.now
-        return latest_date or datetime.datetime.utcnow().replace(tzinfo=utc)
+        return latest_date or datetime.datetime.now(tz=utc)
 
 
 class Enclosure:
diff --git a/django/utils/http.py b/django/utils/http.py
index 5397bb8190..6aa45a2cd6 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -1,5 +1,4 @@
 import base64
-import calendar
 import datetime
 import re
 import unicodedata
@@ -112,9 +111,10 @@ def parse_http_date(date):
     else:
         raise ValueError("%r is not in a valid HTTP date format" % date)
     try:
+        tz = datetime.timezone.utc
         year = int(m['year'])
         if year < 100:
-            current_year = datetime.datetime.utcnow().year
+            current_year = datetime.datetime.now(tz=tz).year
             current_century = current_year - (current_year % 100)
             if year - (current_year % 100) > 50:
                 # year that appears to be more than 50 years in the future are
@@ -127,8 +127,8 @@ def parse_http_date(date):
         hour = int(m['hour'])
         min = int(m['min'])
         sec = int(m['sec'])
-        result = datetime.datetime(year, month, day, hour, min, sec)
-        return calendar.timegm(result.utctimetuple())
+        result = datetime.datetime(year, month, day, hour, min, sec, tzinfo=tz)
+        return int(result.timestamp())
     except Exception as exc:
         raise ValueError("%r is not a valid date" % date) from exc
 
diff --git a/django/utils/timezone.py b/django/utils/timezone.py
index cf22ec34d0..bb2b6b9594 100644
--- a/django/utils/timezone.py
+++ b/django/utils/timezone.py
@@ -194,11 +194,7 @@ def now():
     """
     Return an aware or naive datetime.datetime, depending on settings.USE_TZ.
     """
-    if settings.USE_TZ:
-        # timeit shows that datetime.now(tz=utc) is 24% slower
-        return datetime.utcnow().replace(tzinfo=utc)
-    else:
-        return datetime.now()
+    return datetime.now(tz=utc if settings.USE_TZ else None)
 
 
 # By design, these four functions don't perform any checks on their arguments.
diff --git a/django/utils/version.py b/django/utils/version.py
index 18cd1387a0..a72d3202fa 100644
--- a/django/utils/version.py
+++ b/django/utils/version.py
@@ -89,8 +89,9 @@ def get_git_changeset():
         shell=True, cwd=repo_dir, universal_newlines=True,
     )
     timestamp = git_log.stdout
+    tz = datetime.timezone.utc
     try:
-        timestamp = datetime.datetime.utcfromtimestamp(int(timestamp))
+        timestamp = datetime.datetime.fromtimestamp(int(timestamp), tz=tz)
     except ValueError:
         return None
     return timestamp.strftime('%Y%m%d%H%M%S')
diff --git a/django/views/decorators/http.py b/django/views/decorators/http.py
index 5caf13e341..28da8dd921 100644
--- a/django/views/decorators/http.py
+++ b/django/views/decorators/http.py
@@ -2,11 +2,11 @@
 Decorators for views based on HTTP headers.
 """
 
-from calendar import timegm
 from functools import wraps
 
 from django.http import HttpResponseNotAllowed
 from django.middleware.http import ConditionalGetMiddleware
+from django.utils import timezone
 from django.utils.cache import get_conditional_response
 from django.utils.decorators import decorator_from_middleware
 from django.utils.http import http_date, quote_etag
@@ -82,7 +82,9 @@ def condition(etag_func=None, last_modified_func=None):
                 if last_modified_func:
                     dt = last_modified_func(request, *args, **kwargs)
                     if dt:
-                        return timegm(dt.utctimetuple())
+                        if not timezone.is_aware(dt):
+                            dt = timezone.make_aware(dt, timezone.utc)
+                        return int(dt.timestamp())
 
             # The value from etag_func() could be quoted or unquoted.
             res_etag = etag_func(request, *args, **kwargs) if etag_func else None
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py
index 2473a0a732..72d50cad6b 100644
--- a/tests/foreign_object/tests.py
+++ b/tests/foreign_object/tests.py
@@ -92,7 +92,7 @@ class MultiColumnFKTests(TestCase):
 
     def test_reverse_query_filters_correctly(self):
 
-        timemark = datetime.datetime.utcnow()
+        timemark = datetime.datetime.now(tz=datetime.timezone.utc).replace(tzinfo=None)
         timedelta = datetime.timedelta(days=1)
 
         # Creating a to valid memberships
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index 96b2140089..bb7506c052 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -479,8 +479,8 @@ class WriterTests(SimpleTestCase):
         self.serialize_round_trip(models.SET(42))
 
     def test_serialize_datetime(self):
-        self.assertSerializedEqual(datetime.datetime.utcnow())
-        self.assertSerializedEqual(datetime.datetime.utcnow)
+        self.assertSerializedEqual(datetime.datetime.now())
+        self.assertSerializedEqual(datetime.datetime.now)
         self.assertSerializedEqual(datetime.datetime.today())
         self.assertSerializedEqual(datetime.datetime.today)
         self.assertSerializedEqual(datetime.date.today())
@@ -662,8 +662,8 @@ class WriterTests(SimpleTestCase):
         Tests serializing a simple migration.
         """
         fields = {
-            'charfield': models.DateTimeField(default=datetime.datetime.utcnow),
-            'datetimefield': models.DateTimeField(default=datetime.datetime.utcnow),
+            'charfield': models.DateTimeField(default=datetime.datetime.now),
+            'datetimefield': models.DateTimeField(default=datetime.datetime.now),
         }
 
         options = {
diff --git a/tests/responses/test_cookie.py b/tests/responses/test_cookie.py
index fd3a55442c..96dd603aac 100644
--- a/tests/responses/test_cookie.py
+++ b/tests/responses/test_cookie.py
@@ -19,7 +19,7 @@ class SetCookieTests(SimpleTestCase):
         # evaluated expiration time and the time evaluated in set_cookie(). If
         # this difference doesn't exist, the cookie time will be 1 second
         # larger. The sleep guarantees that there will be a time difference.
-        expires = datetime.utcnow() + timedelta(seconds=10)
+        expires = datetime.now(tz=utc).replace(tzinfo=None) + timedelta(seconds=10)
         time.sleep(0.001)
         response.set_cookie('datetime', expires=expires)
         datetime_cookie = response.cookies['datetime']
@@ -28,7 +28,7 @@ class SetCookieTests(SimpleTestCase):
     def test_aware_expiration(self):
         """set_cookie() accepts an aware datetime as expiration time."""
         response = HttpResponse()
-        expires = (datetime.utcnow() + timedelta(seconds=10)).replace(tzinfo=utc)
+        expires = datetime.now(tz=utc) + timedelta(seconds=10)
         time.sleep(0.001)
         response.set_cookie('datetime', expires=expires)
         datetime_cookie = response.cookies['datetime']
diff --git a/tests/utils_tests/test_dateformat.py b/tests/utils_tests/test_dateformat.py
index f57c67078f..17ddd573ed 100644
--- a/tests/utils_tests/test_dateformat.py
+++ b/tests/utils_tests/test_dateformat.py
@@ -54,8 +54,8 @@ class DateFormatTests(SimpleTestCase):
         self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U')), ltz), dt)
         # astimezone() is safe here because the target timezone doesn't have DST
         self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U'))), dt.astimezone(ltz).replace(tzinfo=None))
-        self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U')), tz).utctimetuple(), dt.utctimetuple())
-        self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U')), ltz).utctimetuple(), dt.utctimetuple())
+        self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U')), tz).timetuple(), dt.astimezone(tz).timetuple())
+        self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U')), ltz).timetuple(), dt.astimezone(ltz).timetuple())
 
     def test_epoch(self):
         udt = datetime(1970, 1, 1, tzinfo=utc)
diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py
index 675a6e186e..6867ed8274 100644
--- a/tests/utils_tests/test_http.py
+++ b/tests/utils_tests/test_http.py
@@ -1,6 +1,6 @@
 import platform
 import unittest
-from datetime import datetime
+from datetime import datetime, timezone
 from unittest import mock
 
 from django.test import SimpleTestCase
@@ -288,38 +288,52 @@ class HttpDateProcessingTests(unittest.TestCase):
 
     def test_parsing_rfc1123(self):
         parsed = parse_http_date('Sun, 06 Nov 1994 08:49:37 GMT')
-        self.assertEqual(datetime.utcfromtimestamp(parsed), datetime(1994, 11, 6, 8, 49, 37))
+        self.assertEqual(
+            datetime.fromtimestamp(parsed, timezone.utc),
+            datetime(1994, 11, 6, 8, 49, 37, tzinfo=timezone.utc),
+        )
 
     @unittest.skipIf(platform.architecture()[0] == '32bit', 'The Year 2038 problem.')
     @mock.patch('django.utils.http.datetime.datetime')
     def test_parsing_rfc850(self, mocked_datetime):
         mocked_datetime.side_effect = datetime
-        mocked_datetime.utcnow = mock.Mock()
-        utcnow_1 = datetime(2019, 11, 6, 8, 49, 37)
-        utcnow_2 = datetime(2020, 11, 6, 8, 49, 37)
-        utcnow_3 = datetime(2048, 11, 6, 8, 49, 37)
+        mocked_datetime.now = mock.Mock()
+        now_1 = datetime(2019, 11, 6, 8, 49, 37, tzinfo=timezone.utc)
+        now_2 = datetime(2020, 11, 6, 8, 49, 37, tzinfo=timezone.utc)
+        now_3 = datetime(2048, 11, 6, 8, 49, 37, tzinfo=timezone.utc)
         tests = (
-            (utcnow_1, 'Tuesday, 31-Dec-69 08:49:37 GMT', datetime(2069, 12, 31, 8, 49, 37)),
-            (utcnow_1, 'Tuesday, 10-Nov-70 08:49:37 GMT', datetime(1970, 11, 10, 8, 49, 37)),
-            (utcnow_1, 'Sunday, 06-Nov-94 08:49:37 GMT', datetime(1994, 11, 6, 8, 49, 37)),
-            (utcnow_2, 'Wednesday, 31-Dec-70 08:49:37 GMT', datetime(2070, 12, 31, 8, 49, 37)),
-            (utcnow_2, 'Friday, 31-Dec-71 08:49:37 GMT', datetime(1971, 12, 31, 8, 49, 37)),
-            (utcnow_3, 'Sunday, 31-Dec-00 08:49:37 GMT', datetime(2000, 12, 31, 8, 49, 37)),
-            (utcnow_3, 'Friday, 31-Dec-99 08:49:37 GMT', datetime(1999, 12, 31, 8, 49, 37)),
+            (now_1, 'Tuesday, 31-Dec-69 08:49:37 GMT', datetime(2069, 12, 31, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_1, 'Tuesday, 10-Nov-70 08:49:37 GMT', datetime(1970, 11, 10, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_1, 'Sunday, 06-Nov-94 08:49:37 GMT', datetime(1994, 11, 6, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_2, 'Wednesday, 31-Dec-70 08:49:37 GMT', datetime(2070, 12, 31, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_2, 'Friday, 31-Dec-71 08:49:37 GMT', datetime(1971, 12, 31, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_3, 'Sunday, 31-Dec-00 08:49:37 GMT', datetime(2000, 12, 31, 8, 49, 37, tzinfo=timezone.utc)),
+            (now_3, 'Friday, 31-Dec-99 08:49:37 GMT', datetime(1999, 12, 31, 8, 49, 37, tzinfo=timezone.utc)),
         )
-        for utcnow, rfc850str, expected_date in tests:
+        for now, rfc850str, expected_date in tests:
             with self.subTest(rfc850str=rfc850str):
-                mocked_datetime.utcnow.return_value = utcnow
+                mocked_datetime.now.return_value = now
                 parsed = parse_http_date(rfc850str)
-                self.assertEqual(datetime.utcfromtimestamp(parsed), expected_date)
+                mocked_datetime.now.assert_called_once_with(tz=timezone.utc)
+                self.assertEqual(
+                    datetime.fromtimestamp(parsed, timezone.utc),
+                    expected_date,
+                )
+            mocked_datetime.reset_mock()
 
     def test_parsing_asctime(self):
         parsed = parse_http_date('Sun Nov  6 08:49:37 1994')
-        self.assertEqual(datetime.utcfromtimestamp(parsed), datetime(1994, 11, 6, 8, 49, 37))
+        self.assertEqual(
+            datetime.fromtimestamp(parsed, timezone.utc),
+            datetime(1994, 11, 6, 8, 49, 37, tzinfo=timezone.utc),
+        )
 
     def test_parsing_year_less_than_70(self):
         parsed = parse_http_date('Sun Nov  6 08:49:37 0037')
-        self.assertEqual(datetime.utcfromtimestamp(parsed), datetime(2037, 11, 6, 8, 49, 37))
+        self.assertEqual(
+            datetime.fromtimestamp(parsed, timezone.utc),
+            datetime(2037, 11, 6, 8, 49, 37, tzinfo=timezone.utc),
+        )
 
 
 class EscapeLeadingSlashesTests(unittest.TestCase):