mirror of https://github.com/python/cpython
gh-83861: Fix datetime.astimezone() method (GH-101545)
This commit is contained in:
parent
d4aa8578b1
commit
2b1260c557
|
@ -1965,6 +1965,11 @@ class datetime(date):
|
||||||
def _local_timezone(self):
|
def _local_timezone(self):
|
||||||
if self.tzinfo is None:
|
if self.tzinfo is None:
|
||||||
ts = self._mktime()
|
ts = self._mktime()
|
||||||
|
# Detect gap
|
||||||
|
ts2 = self.replace(fold=1-self.fold)._mktime()
|
||||||
|
if ts2 != ts: # This happens in a gap or a fold
|
||||||
|
if (ts2 > ts) == self.fold:
|
||||||
|
ts = ts2
|
||||||
else:
|
else:
|
||||||
ts = (self - _EPOCH) // timedelta(seconds=1)
|
ts = (self - _EPOCH) // timedelta(seconds=1)
|
||||||
localtm = _time.localtime(ts)
|
localtm = _time.localtime(ts)
|
||||||
|
|
|
@ -6212,6 +6212,10 @@ class ZoneInfoTest(unittest.TestCase):
|
||||||
ts1 = dt.replace(fold=1).timestamp()
|
ts1 = dt.replace(fold=1).timestamp()
|
||||||
self.assertEqual(ts0, s0 + ss / 2)
|
self.assertEqual(ts0, s0 + ss / 2)
|
||||||
self.assertEqual(ts1, s0 - ss / 2)
|
self.assertEqual(ts1, s0 - ss / 2)
|
||||||
|
# gh-83861
|
||||||
|
utc0 = dt.astimezone(timezone.utc)
|
||||||
|
utc1 = dt.replace(fold=1).astimezone(timezone.utc)
|
||||||
|
self.assertEqual(utc0, utc1 + timedelta(0, ss))
|
||||||
finally:
|
finally:
|
||||||
if TZ is None:
|
if TZ is None:
|
||||||
del os.environ['TZ']
|
del os.environ['TZ']
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Fix datetime.astimezone method return value when invoked on a naive datetime
|
||||||
|
instance that represents local time falling in a timezone transition gap.
|
||||||
|
PEP 495 requires that instances with fold=1 produce earlier times than those
|
||||||
|
with fold=0 in this case.
|
|
@ -6153,17 +6153,31 @@ local_to_seconds(int year, int month, int day,
|
||||||
static PyObject *
|
static PyObject *
|
||||||
local_timezone_from_local(PyDateTime_DateTime *local_dt)
|
local_timezone_from_local(PyDateTime_DateTime *local_dt)
|
||||||
{
|
{
|
||||||
long long seconds;
|
long long seconds, seconds2;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
|
int fold = DATE_GET_FOLD(local_dt);
|
||||||
seconds = local_to_seconds(GET_YEAR(local_dt),
|
seconds = local_to_seconds(GET_YEAR(local_dt),
|
||||||
GET_MONTH(local_dt),
|
GET_MONTH(local_dt),
|
||||||
GET_DAY(local_dt),
|
GET_DAY(local_dt),
|
||||||
DATE_GET_HOUR(local_dt),
|
DATE_GET_HOUR(local_dt),
|
||||||
DATE_GET_MINUTE(local_dt),
|
DATE_GET_MINUTE(local_dt),
|
||||||
DATE_GET_SECOND(local_dt),
|
DATE_GET_SECOND(local_dt),
|
||||||
DATE_GET_FOLD(local_dt));
|
fold);
|
||||||
if (seconds == -1)
|
if (seconds == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
seconds2 = local_to_seconds(GET_YEAR(local_dt),
|
||||||
|
GET_MONTH(local_dt),
|
||||||
|
GET_DAY(local_dt),
|
||||||
|
DATE_GET_HOUR(local_dt),
|
||||||
|
DATE_GET_MINUTE(local_dt),
|
||||||
|
DATE_GET_SECOND(local_dt),
|
||||||
|
!fold);
|
||||||
|
if (seconds2 == -1)
|
||||||
|
return NULL;
|
||||||
|
/* Detect gap */
|
||||||
|
if (seconds2 != seconds && (seconds2 > seconds) == fold)
|
||||||
|
seconds = seconds2;
|
||||||
|
|
||||||
/* XXX: add bounds check */
|
/* XXX: add bounds check */
|
||||||
timestamp = seconds - epoch;
|
timestamp = seconds - epoch;
|
||||||
return local_timezone_from_timestamp(timestamp);
|
return local_timezone_from_timestamp(timestamp);
|
||||||
|
|
Loading…
Reference in New Issue