From 4cd12e088bf1be39e49c20f7fa1d1e7f7ed7c61b Mon Sep 17 00:00:00 2001 From: Josh Schneier Date: Sat, 6 Jul 2024 13:42:26 -0400 Subject: [PATCH] [sftp] Format times to UTC (#1420) --- storages/backends/sftpstorage.py | 14 ++++++++------ tests/test_sftp.py | 11 +++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/storages/backends/sftpstorage.py b/storages/backends/sftpstorage.py index ce76f749..3ffb5fa9 100644 --- a/storages/backends/sftpstorage.py +++ b/storages/backends/sftpstorage.py @@ -4,17 +4,16 @@ # # Modeled on the FTP storage by Rafal Jonca +import datetime import getpass import io import os import posixpath import stat -from datetime import datetime from urllib.parse import urljoin import paramiko from django.core.files.base import File -from django.utils import timezone from django.utils.deconstruct import deconstructible from paramiko.util import ClosingContextManager @@ -192,17 +191,20 @@ def size(self, name): remote_path = self._remote_path(name) return self.sftp.stat(remote_path).st_size + # From Django + def _datetime_from_timestamp(self, ts): + tz = datetime.timezone.utc if setting("USE_TZ") else None + return datetime.datetime.fromtimestamp(ts, tz=tz) + def get_accessed_time(self, name): remote_path = self._remote_path(name) utime = self.sftp.stat(remote_path).st_atime - ts = datetime.fromtimestamp(utime) - return timezone.make_aware(ts) if setting("USE_TZ") else ts + return self._datetime_from_timestamp(utime) def get_modified_time(self, name): remote_path = self._remote_path(name) utime = self.sftp.stat(remote_path).st_mtime - ts = datetime.fromtimestamp(utime) - return timezone.make_aware(ts) if setting("USE_TZ") else ts + return self._datetime_from_timestamp(utime) def url(self, name): if self._base_url is None: diff --git a/tests/test_sftp.py b/tests/test_sftp.py index 1c95b674..6332e19e 100644 --- a/tests/test_sftp.py +++ b/tests/test_sftp.py @@ -167,6 +167,17 @@ def test_url(self): self.storage._base_url = None self.storage.url("foo") + @patch( + "storages.backends.sftpstorage.SFTPStorage.sftp", + **{ + "stat.return_value.st_mtime": 1720287559, + "stat.return_value.st_atime": 1720287559, + }, + ) + def test_times(self, mock_sftp): + self.storage.get_modified_time("foo") + self.storage.get_accessed_time("foo") + @patch("paramiko.transport.Transport", **{"is_active.side_effect": (True, False)}) @patch("storages.backends.sftpstorage.SFTPStorage._connect") def test_sftp(self, connect, transport):