Repository: conan-io/conan
Pull request #16095 (2024-04-17 09:14:57)

fix deprecated datetime timestamps calls
Changelog: Fix: Avoid ``datetime`` deprecated calls in Python 3.12
Docs: Omit

Python 3.12 CI is issuing now a bunch of deprecation warnings. Better try to improve them earlier, otherwise it can be painful in the future

I have checked manually the places these calls are made, they should be relatively low risk, but still:

TODO: Check the time response format from Artifactory.


Patch:
diff --git a/conans/__init__.py b/conans/__init__.py
index 75491bf9a..78ef1f15f 100644
--- a/conans/__init__.py
+++ b/conans/__init__.py
@@ -2,4 +2,4 @@ CHECKSUM_DEPLOY = "checksum_deploy"  # Only when v2
 REVISIONS = "revisions"  # Only when enabled in config, not by default look at server_launcher.py
 OAUTH_TOKEN = "oauth_token"
 
-__version__ = '2.3.0-dev'
+__version__ = '2.4.0-dev'
diff --git a/conans/server/crypto/jwt/jwt_manager.py b/conans/server/crypto/jwt/jwt_manager.py
index ba4f35bdc..fadd972f2 100644
--- a/conans/server/crypto/jwt/jwt_manager.py
+++ b/conans/server/crypto/jwt/jwt_manager.py
@@ -1,10 +1,10 @@
-from datetime import datetime
+from datetime import datetime, timezone
 from calendar import timegm
 
 import jwt
 
 
-class JWTManager(object):
+class JWTManager:
     """
         Handles the JWT token generation and encryption.
     """
@@ -21,7 +21,8 @@ class JWTManager(object):
         profile_fields = profile_fields or {}
 
         if self.expire_time:
-            profile_fields["exp"] = timegm((datetime.utcnow() + self.expire_time).timetuple())
+            profile_fields["exp"] = timegm((datetime.now(timezone.utc)
+                                            + self.expire_time).timetuple())
 
         return jwt.encode(profile_fields, self.secret, algorithm="HS256")
 
diff --git a/conans/util/dates.py b/conans/util/dates.py
index a76067c5d..1881326af 100644
--- a/conans/util/dates.py
+++ b/conans/util/dates.py
@@ -9,7 +9,7 @@ from conans.errors import ConanException
 
 def from_timestamp_to_iso8601(timestamp):
     # Used exclusively by conan_server to return the date in iso format (same as artifactory)
-    return "%sZ" % datetime.datetime.utcfromtimestamp(timestamp).isoformat()
+    return "%s" % datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc).isoformat()
 
 
 def _from_iso8601_to_datetime(iso_str):
@@ -34,7 +34,7 @@ def revision_timestamp_now():
 def timestamp_to_str(timestamp):
     # used by ref.repr_humantime() to print human readable time
     assert timestamp is not None
-    return datetime.datetime.utcfromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S UTC')
+    return datetime.datetime.fromtimestamp(int(timestamp), datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
 
 
 def timelimit(expression):


Test patch:
diff --git a/conans/test/unittests/client/util/time_test.py b/conans/test/unittests/client/util/time_test.py
index dda8bfeff..e90050f68 100644
--- a/conans/test/unittests/client/util/time_test.py
+++ b/conans/test/unittests/client/util/time_test.py
@@ -3,7 +3,8 @@ import unittest
 
 from dateutil.tz import tzutc
 
-from conans.util.dates import from_timestamp_to_iso8601, _from_iso8601_to_datetime
+from conans.util.dates import from_timestamp_to_iso8601, _from_iso8601_to_datetime, \
+    from_iso8601_to_timestamp
 
 
 class TimeTest(unittest.TestCase):
@@ -11,7 +12,7 @@ class TimeTest(unittest.TestCase):
     def test_time_conversions(self):
         timestamp = 1547138099
         iso = from_timestamp_to_iso8601(timestamp)
-        self.assertEqual(iso, "2019-01-10T16:34:59Z")
+        self.assertEqual(iso, "2019-01-10T16:34:59+00:00")
 
         dt = _from_iso8601_to_datetime(iso)
         expected = datetime.datetime(year=2019, month=1, day=10, hour=16, minute=34, second=59,
@@ -29,3 +30,11 @@ class TimeTest(unittest.TestCase):
         expected = datetime.datetime(year=2019, month=5, day=14, hour=15, minute=52, second=28,
                                      microsecond=383000, tzinfo=tzutc())
         self.assertEqual(dt, expected)
+
+        artifactory_ret = "2024-01-23T08:39:53.776+0000"
+        ts = from_iso8601_to_timestamp(artifactory_ret)
+        assert ts == 1705999193.776
+
+        artifactory_ret = "2024-01-23T08:39:53.776+00:00"
+        ts = from_iso8601_to_timestamp(artifactory_ret)
+        assert ts == 1705999193.776