diff --git a/botocore/auth.py b/botocore/auth.py index 8389c1579c..2589abe609 100644 --- a/botocore/auth.py +++ b/botocore/auth.py @@ -416,7 +416,7 @@ def signature(self, string_to_sign, request): def add_auth(self, request): if self.credentials is None: raise NoCredentialsError() - datetime_now = datetime.datetime.utcnow() + datetime_now = datetime.datetime.now(datetime.timezone.utc) request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP) # This could be a retry. Make sure the previous # authorization header is removed first. @@ -554,7 +554,7 @@ class S3ExpressPostAuth(S3ExpressAuth): REQUIRES_IDENTITY_CACHE = True def add_auth(self, request): - datetime_now = datetime.datetime.utcnow() + datetime_now = datetime.datetime.now(datetime.timezone.utc) request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP) fields = {} @@ -813,7 +813,7 @@ class S3SigV4PostAuth(SigV4Auth): """ def add_auth(self, request): - datetime_now = datetime.datetime.utcnow() + datetime_now = datetime.datetime.now(datetime.timezone.utc) request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP) fields = {} diff --git a/botocore/crt/auth.py b/botocore/crt/auth.py index 0d1a81def4..dd2eb302bc 100644 --- a/botocore/crt/auth.py +++ b/botocore/crt/auth.py @@ -54,11 +54,7 @@ def add_auth(self, request): if self.credentials is None: raise NoCredentialsError() - # Use utcnow() because that's what gets mocked by tests, but set - # timezone because CRT assumes naive datetime is local time. - datetime_now = datetime.datetime.utcnow().replace( - tzinfo=datetime.timezone.utc - ) + datetime_now = datetime.datetime.now(datetime.timezone.utc) # Use existing 'X-Amz-Content-SHA256' header if able existing_sha256 = self._get_existing_sha256(request) @@ -251,11 +247,7 @@ def add_auth(self, request): if self.credentials is None: raise NoCredentialsError() - # Use utcnow() because that's what gets mocked by tests, but set - # timezone because CRT assumes naive datetime is local time. - datetime_now = datetime.datetime.utcnow().replace( - tzinfo=datetime.timezone.utc - ) + datetime_now = datetime.datetime.now(datetime.timezone.utc) # Use existing 'X-Amz-Content-SHA256' header if able existing_sha256 = self._get_existing_sha256(request) diff --git a/botocore/endpoint.py b/botocore/endpoint.py index adc622c25a..a76b1d07e5 100644 --- a/botocore/endpoint.py +++ b/botocore/endpoint.py @@ -152,10 +152,10 @@ def prepare_request(self, request): def _calculate_ttl( self, response_received_timestamp, date_header, read_timeout ): - local_timestamp = datetime.datetime.utcnow() + local_timestamp = datetime.datetime.now(datetime.timezone.utc) date_conversion = datetime.datetime.strptime( date_header, "%a, %d %b %Y %H:%M:%S %Z" - ) + ).replace(tzinfo=datetime.timezone.utc) estimated_skew = date_conversion - response_received_timestamp ttl = ( local_timestamp @@ -169,7 +169,8 @@ def _set_ttl(self, retries_context, read_timeout, success_response): has_streaming_input = retries_context.get('has_streaming_input') if response_date_header and not has_streaming_input: try: - response_received_timestamp = datetime.datetime.utcnow() + utc = datetime.timezone.utc + response_received_timestamp = datetime.datetime.now(utc) retries_context['ttl'] = self._calculate_ttl( response_received_timestamp, response_date_header, diff --git a/botocore/signers.py b/botocore/signers.py index b42550e05f..3c761465ec 100644 --- a/botocore/signers.py +++ b/botocore/signers.py @@ -607,7 +607,7 @@ def generate_presigned_post( policy = {} # Create an expiration date for the policy - datetime_now = datetime.datetime.utcnow() + datetime_now = datetime.datetime.now(datetime.timezone.utc) expire_date = datetime_now + datetime.timedelta(seconds=expires_in) policy['expiration'] = expire_date.strftime(botocore.auth.ISO8601) diff --git a/botocore/utils.py b/botocore/utils.py index 923217ead9..ca6238d389 100644 --- a/botocore/utils.py +++ b/botocore/utils.py @@ -673,7 +673,7 @@ def _evaluate_expiration(self, credentials): ) jitter = random.randint(120, 600) # Between 2 to 10 minutes refresh_interval_with_jitter = refresh_interval + jitter - current_time = datetime.datetime.utcnow() + current_time = datetime.datetime.now(datetime.timezone.utc) refresh_offset = datetime.timedelta( seconds=refresh_interval_with_jitter ) diff --git a/tests/__init__.py b/tests/__init__.py index 33307c0081..0e78fe3f69 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -568,12 +568,12 @@ class FreezeTime(ContextDecorator): :param module: reference to imported module to patch (e.g. botocore.auth.datetime) :type date: datetime.datetime - :param date: datetime object specifying the output for utcnow() + :param date: datetime object specifying the output for now() """ def __init__(self, module, date=None): if date is None: - date = datetime.datetime.utcnow() + date = datetime.datetime.now(datetime.timezone.utc) self.date = date self.datetime_patcher = mock.patch.object( module, 'datetime', mock.Mock(wraps=datetime.datetime) @@ -581,7 +581,7 @@ def __init__(self, module, date=None): def __enter__(self, *args, **kwargs): mock = self.datetime_patcher.start() - mock.utcnow.return_value = self.date + mock.now.return_value = self.date def __exit__(self, *args, **kwargs): self.datetime_patcher.stop() diff --git a/tests/functional/test_ec2.py b/tests/functional/test_ec2.py index 75ec6dc8f4..31dac41ae7 100644 --- a/tests/functional/test_ec2.py +++ b/tests/functional/test_ec2.py @@ -91,14 +91,15 @@ def setUp(self): '%s\n' '\n' ) - self.now = datetime.datetime(2011, 9, 9, 23, 36) + utc = datetime.timezone.utc + self.now = datetime.datetime(2011, 9, 9, 23, 36, tzinfo=utc) self.datetime_patch = mock.patch.object( botocore.auth.datetime, 'datetime', mock.Mock(wraps=datetime.datetime), ) self.mocked_datetime = self.datetime_patch.start() - self.mocked_datetime.utcnow.return_value = self.now + self.mocked_datetime.now.return_value = self.now def tearDown(self): super().tearDown() diff --git a/tests/functional/test_lex.py b/tests/functional/test_lex.py index a62b0357dd..7dfc22c0b0 100644 --- a/tests/functional/test_lex.py +++ b/tests/functional/test_lex.py @@ -34,7 +34,7 @@ def test_unsigned_payload(self): timestamp = datetime(2017, 3, 22, 0, 0) with mock.patch('botocore.auth.datetime.datetime') as _datetime: - _datetime.utcnow.return_value = timestamp + _datetime.now.return_value = timestamp self.http_stubber.add_response(body=b'{}') with self.http_stubber: self.client.post_content(**params) diff --git a/tests/functional/test_retry.py b/tests/functional/test_retry.py index 27dafb0909..4a0cc37f6e 100644 --- a/tests/functional/test_retry.py +++ b/tests/functional/test_retry.py @@ -66,26 +66,27 @@ def _retry_headers_test_cases(self): ] # The first, third and seventh datetime values of each - # utcnow_side_effects list are side_effect values for when - # utcnow is called in SigV4 signing. - utcnow_side_effects = [ + # dt_now_side_effects list are side_effect values for when + # datetime.now is called in SigV4 signing. + utc = datetime.timezone.utc + dt_now_side_effects = [ [ - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), - datetime.datetime(2019, 6, 1, 0, 0, 1, 0), - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), - datetime.datetime(2019, 6, 1, 0, 0, 1, 0), - datetime.datetime(2019, 6, 1, 0, 0, 2, 0), - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 1, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 1, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 2, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), ], [ - datetime.datetime(2020, 6, 1, 0, 0, 0, 0), - datetime.datetime(2019, 6, 1, 0, 0, 5, 0), - datetime.datetime(2019, 6, 1, 0, 0, 6, 0), - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), - datetime.datetime(2019, 6, 1, 0, 0, 11, 0), - datetime.datetime(2019, 6, 1, 0, 0, 12, 0), - datetime.datetime(2019, 6, 1, 0, 0, 0, 0), + datetime.datetime(2020, 6, 1, 0, 0, 0, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 5, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 6, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 11, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 12, 0, tzinfo=utc), + datetime.datetime(2019, 6, 1, 0, 0, 0, 0, tzinfo=utc), ], ] expected_headers = [ @@ -101,12 +102,12 @@ def _retry_headers_test_cases(self): ], ] test_cases = list( - zip(responses, utcnow_side_effects, expected_headers) + zip(responses, dt_now_side_effects, expected_headers) ) return test_cases def _test_amz_sdk_request_header_with_test_case( - self, responses, utcnow_side_effects, expected_headers, client_config + self, responses, dt_now_side_effects, expected_headers, client_config ): datetime_patcher = mock.patch.object( botocore.endpoint.datetime, @@ -114,7 +115,7 @@ def _test_amz_sdk_request_header_with_test_case( mock.Mock(wraps=datetime.datetime), ) mocked_datetime = datetime_patcher.start() - mocked_datetime.utcnow.side_effect = utcnow_side_effects + mocked_datetime.now.side_effect = dt_now_side_effects client = self.session.create_client( 'dynamodb', self.region, config=client_config diff --git a/tests/functional/test_s3express.py b/tests/functional/test_s3express.py index 390721ee12..ebb89b0b60 100644 --- a/tests/functional/test_s3express.py +++ b/tests/functional/test_s3express.py @@ -108,7 +108,6 @@ def test_s3_express_auth_headers(self): class TestS3ExpressIdentityCache: def test_default_s3_express_cache(self, default_s3_client, mock_datetime): mock_datetime.now.return_value = DATE - mock_datetime.utcnow.return_value = DATE identity_cache = S3ExpressIdentityCache( default_s3_client, @@ -126,7 +125,6 @@ def test_s3_express_cache_one_network_call( self, default_s3_client, mock_datetime ): mock_datetime.now.return_value = DATE - mock_datetime.utcnow.return_value = DATE bucket = 'my_bucket' identity_cache = S3ExpressIdentityCache( @@ -151,7 +149,6 @@ def test_s3_express_cache_multiple_buckets( self, default_s3_client, mock_datetime ): mock_datetime.now.return_value = DATE - mock_datetime.utcnow.return_value = DATE bucket = 'my_bucket' other_bucket = 'other_bucket' @@ -204,7 +201,7 @@ def _call_get_object(self, client): ) def test_create_bucket(self, default_s3_client, mock_datetime): - mock_datetime.utcnow.return_value = DATE + mock_datetime.now.return_value = DATE with ClientHTTPStubber(default_s3_client) as stubber: stubber.add_response() @@ -228,7 +225,6 @@ def test_create_bucket(self, default_s3_client, mock_datetime): self._assert_standard_sigv4_signature(stubber.requests[0].headers) def test_get_object(self, default_s3_client, mock_datetime): - mock_datetime.utcnow.return_value = DATE mock_datetime.now.return_value = DATE with ClientHTTPStubber(default_s3_client) as stubber: @@ -250,7 +246,6 @@ def test_get_object(self, default_s3_client, mock_datetime): def test_cache_with_multiple_requests( self, default_s3_client, mock_datetime ): - mock_datetime.utcnow.return_value = DATE mock_datetime.now.return_value = DATE with ClientHTTPStubber(default_s3_client) as stubber: @@ -275,7 +270,6 @@ def test_cache_with_multiple_requests( def test_delete_objects_injects_correct_checksum( self, default_s3_client, mock_datetime ): - mock_datetime.utcnow.return_value = DATE mock_datetime.now.return_value = DATE with ClientHTTPStubber(default_s3_client) as stubber: diff --git a/tests/functional/test_sts.py b/tests/functional/test_sts.py index 2040fb3017..2f5f1f1d5a 100644 --- a/tests/functional/test_sts.py +++ b/tests/functional/test_sts.py @@ -11,7 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. import re -from datetime import datetime +from datetime import datetime, timezone from botocore.config import Config from botocore.stub import Stubber @@ -37,9 +37,9 @@ def setUp(self): self.stubber.activate() def test_presigned_url_contains_no_content_type(self): - timestamp = datetime(2017, 3, 22, 0, 0) + timestamp = datetime(2017, 3, 22, 0, 0, tzinfo=timezone.utc) with mock.patch('botocore.auth.datetime.datetime') as _datetime: - _datetime.utcnow.return_value = timestamp + _datetime.now.return_value = timestamp url = self.client.generate_presigned_url('get_caller_identity', {}) # There should be no 'content-type' in x-amz-signedheaders diff --git a/tests/unit/auth/test_signers.py b/tests/unit/auth/test_signers.py index 9e92654228..a63d0aa957 100644 --- a/tests/unit/auth/test_signers.py +++ b/tests/unit/auth/test_signers.py @@ -27,10 +27,12 @@ class BaseTestWithFixedDate(unittest.TestCase): def setUp(self): - self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0) + self.fixed_date = datetime.datetime( + 2014, 3, 10, 17, 2, 55, 0, tzinfo=datetime.timezone.utc + ) self.datetime_patch = mock.patch('botocore.auth.datetime.datetime') self.datetime_mock = self.datetime_patch.start() - self.datetime_mock.utcnow.return_value = self.fixed_date + self.datetime_mock.now.return_value = self.fixed_date self.datetime_mock.strptime.return_value = self.fixed_date def tearDown(self): @@ -521,9 +523,11 @@ def test_thread_safe_timestamp(self): 'datetime', mock.Mock(wraps=datetime.datetime), ) as mock_datetime: - original_utcnow = datetime.datetime(2014, 1, 1, 0, 0) + original_now = datetime.datetime( + 2014, 1, 1, 0, 0, tzinfo=datetime.timezone.utc + ) - mock_datetime.utcnow.return_value = original_utcnow + mock_datetime.now.return_value = original_now # Go through the add_auth process once. This will attach # a timestamp to the request at the beginning of auth. auth.add_auth(request) @@ -531,8 +535,8 @@ def test_thread_safe_timestamp(self): # Ensure the date is in the Authorization header self.assertIn('20140101', request.headers['Authorization']) # Now suppose the utc time becomes the next day all of a sudden - mock_datetime.utcnow.return_value = datetime.datetime( - 2014, 1, 2, 0, 0 + mock_datetime.now.return_value = datetime.datetime( + 2014, 1, 2, 0, 0, tzinfo=datetime.timezone.utc ) # Smaller methods like the canonical request and string_to_sign # should have the timestamp attached to the request in their @@ -798,8 +802,8 @@ def setUp(self): mock.Mock(wraps=datetime.datetime), ) mocked_datetime = self.datetime_patcher.start() - mocked_datetime.utcnow.return_value = datetime.datetime( - 2014, 1, 1, 0, 0 + mocked_datetime.now.return_value = datetime.datetime( + 2014, 1, 1, 0, 0, tzinfo=datetime.timezone.utc ) def tearDown(self): @@ -1102,8 +1106,8 @@ def setUp(self): mock.Mock(wraps=datetime.datetime), ) mocked_datetime = self.datetime_patcher.start() - mocked_datetime.utcnow.return_value = datetime.datetime( - 2014, 1, 1, 0, 0 + mocked_datetime.now.return_value = datetime.datetime( + 2014, 1, 1, 0, 0, tzinfo=datetime.timezone.utc ) def tearDown(self): diff --git a/tests/unit/test_credentials.py b/tests/unit/test_credentials.py index 089fcc8695..1dfc75c95c 100644 --- a/tests/unit/test_credentials.py +++ b/tests/unit/test_credentials.py @@ -15,7 +15,7 @@ import shutil import subprocess import tempfile -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from pathlib import Path import pytest @@ -307,8 +307,8 @@ def test_expiration_in_datetime_format(self): self.assertEqual(response, expected_response) def test_retrieves_from_cache(self): - date_in_future = datetime.utcnow() + timedelta(seconds=1000) - utc_timestamp = date_in_future.isoformat() + 'Z' + date_in_future = datetime.now(timezone.utc) + timedelta(seconds=1000) + utc_timestamp = date_in_future.strftime('%Y-%m-%dT%H:%M:%S.%fZ') cache_key = '793d6e2f27667ab2da104824407e486bfec24a47' cache = { cache_key: { @@ -741,8 +741,8 @@ def test_no_cache(self): self.assertEqual(response, expected_response) def test_retrieves_from_cache(self): - date_in_future = datetime.utcnow() + timedelta(seconds=1000) - utc_timestamp = date_in_future.isoformat() + 'Z' + date_in_future = datetime.now(timezone.utc) + timedelta(seconds=1000) + utc_timestamp = date_in_future.strftime('%Y-%m-%dT%H:%M:%S.%fZ') cache_key = '793d6e2f27667ab2da104824407e486bfec24a47' cache = { cache_key: { @@ -859,8 +859,8 @@ def test_assume_role_with_no_cache(self): mock_loader_cls.assert_called_with('/some/path/token.jwt') def test_assume_role_retrieves_from_cache(self): - date_in_future = datetime.utcnow() + timedelta(seconds=1000) - utc_timestamp = date_in_future.isoformat() + 'Z' + date_in_future = datetime.now(timezone.utc) + timedelta(seconds=1000) + utc_timestamp = date_in_future.strftime('%Y-%m-%dT%H:%M:%S.%fZ') cache_key = 'c29461feeacfbed43017d20612606ff76abc073d' cache = { @@ -2029,8 +2029,8 @@ def test_assume_role_refresher_serializes_datetime(self): self.assertEqual(expiry_time, '2016-11-06T01:30:00UTC') def test_assume_role_retrieves_from_cache(self): - date_in_future = datetime.utcnow() + timedelta(seconds=1000) - utc_timestamp = date_in_future.isoformat() + 'Z' + date_in_future = datetime.now(timezone.utc) + timedelta(seconds=1000) + utc_timestamp = date_in_future.strftime('%Y-%m-%dT%H:%M:%S.%fZ') self.fake_config['profiles']['development']['role_arn'] = 'myrole' cache_key = '793d6e2f27667ab2da104824407e486bfec24a47' @@ -2058,8 +2058,8 @@ def test_assume_role_retrieves_from_cache(self): self.assertEqual(creds.token, 'baz-cached') def test_chain_prefers_cache(self): - date_in_future = datetime.utcnow() + timedelta(seconds=1000) - utc_timestamp = date_in_future.isoformat() + 'Z' + date_in_future = datetime.now(timezone.utc) + timedelta(seconds=1000) + utc_timestamp = date_in_future.strftime('%Y-%m-%dT%H:%M:%S.%fZ') # The profile we will be using has a cache entry, but the profile it # is sourcing from does not. This should result in the cached diff --git a/tests/unit/test_signers.py b/tests/unit/test_signers.py index 92a3d5da3f..03bab710cb 100644 --- a/tests/unit/test_signers.py +++ b/tests/unit/test_signers.py @@ -689,9 +689,11 @@ def setUp(self): self.datetime_patch = mock.patch('botocore.signers.datetime') self.datetime_mock = self.datetime_patch.start() - self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0) + self.fixed_date = datetime.datetime( + 2014, 3, 10, 17, 2, 55, 0, tzinfo=datetime.timezone.utc + ) self.fixed_delta = datetime.timedelta(seconds=3600) - self.datetime_mock.datetime.utcnow.return_value = self.fixed_date + self.datetime_mock.datetime.now.return_value = self.fixed_date self.datetime_mock.timedelta.return_value = self.fixed_delta def tearDown(self): @@ -1146,7 +1148,7 @@ def test_generate_db_auth_token(self): clock = datetime.datetime(2016, 11, 7, 17, 39, 33, tzinfo=tzutc()) with mock.patch('datetime.datetime') as dt: - dt.utcnow.return_value = clock + dt.now.return_value = clock result = generate_db_auth_token( self.client, hostname, port, username ) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 32c9f336c3..18ffd2af43 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -3051,7 +3051,7 @@ def test_v1_disabled_by_config(self): def _get_datetime(self, dt=None, offset=None, offset_func=operator.add): if dt is None: - dt = datetime.datetime.utcnow() + dt = datetime.datetime.now(datetime.timezone.utc) if offset is not None: dt = offset_func(dt, offset)