Kaydet (Commit) 5d0c5983 authored tarafından Alexander Belopolsky's avatar Alexander Belopolsky

Closes issue #24773: Implement PEP 495 (Local Time Disambiguation).

üst 638e6220
...@@ -81,6 +81,7 @@ typedef struct ...@@ -81,6 +81,7 @@ typedef struct
typedef struct typedef struct
{ {
_PyDateTime_TIMEHEAD _PyDateTime_TIMEHEAD
unsigned char fold;
PyObject *tzinfo; PyObject *tzinfo;
} PyDateTime_Time; /* hastzinfo true */ } PyDateTime_Time; /* hastzinfo true */
...@@ -108,6 +109,7 @@ typedef struct ...@@ -108,6 +109,7 @@ typedef struct
typedef struct typedef struct
{ {
_PyDateTime_DATETIMEHEAD _PyDateTime_DATETIMEHEAD
unsigned char fold;
PyObject *tzinfo; PyObject *tzinfo;
} PyDateTime_DateTime; /* hastzinfo true */ } PyDateTime_DateTime; /* hastzinfo true */
...@@ -125,6 +127,7 @@ typedef struct ...@@ -125,6 +127,7 @@ typedef struct
((((PyDateTime_DateTime*)o)->data[7] << 16) | \ ((((PyDateTime_DateTime*)o)->data[7] << 16) | \
(((PyDateTime_DateTime*)o)->data[8] << 8) | \ (((PyDateTime_DateTime*)o)->data[8] << 8) | \
((PyDateTime_DateTime*)o)->data[9]) ((PyDateTime_DateTime*)o)->data[9])
#define PyDateTime_DATE_GET_FOLD(o) (((PyDateTime_DateTime*)o)->fold)
/* Apply for time instances. */ /* Apply for time instances. */
#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0]) #define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0])
...@@ -134,6 +137,7 @@ typedef struct ...@@ -134,6 +137,7 @@ typedef struct
((((PyDateTime_Time*)o)->data[3] << 16) | \ ((((PyDateTime_Time*)o)->data[3] << 16) | \
(((PyDateTime_Time*)o)->data[4] << 8) | \ (((PyDateTime_Time*)o)->data[4] << 8) | \
((PyDateTime_Time*)o)->data[5]) ((PyDateTime_Time*)o)->data[5])
#define PyDateTime_TIME_GET_FOLD(o) (((PyDateTime_Time*)o)->fold)
/* Apply for time delta instances */ /* Apply for time delta instances */
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) #define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)
...@@ -162,6 +166,11 @@ typedef struct { ...@@ -162,6 +166,11 @@ typedef struct {
PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*); PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*);
PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*); PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*);
/* PEP 495 constructors */
PyObject *(*DateTime_FromDateAndTimeAndFold)(int, int, int, int, int, int, int,
PyObject*, int, PyTypeObject*);
PyObject *(*Time_FromTimeAndFold)(int, int, int, int, PyObject*, int, PyTypeObject*);
} PyDateTime_CAPI; } PyDateTime_CAPI;
#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" #define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
...@@ -217,10 +226,18 @@ static PyDateTime_CAPI *PyDateTimeAPI = NULL; ...@@ -217,10 +226,18 @@ static PyDateTime_CAPI *PyDateTimeAPI = NULL;
PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \ PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \
min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType) min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType)
#define PyDateTime_FromDateAndTimeAndFold(year, month, day, hour, min, sec, usec, fold) \
PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(year, month, day, hour, \
min, sec, usec, Py_None, fold, PyDateTimeAPI->DateTimeType)
#define PyTime_FromTime(hour, minute, second, usecond) \ #define PyTime_FromTime(hour, minute, second, usecond) \
PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \ PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \
Py_None, PyDateTimeAPI->TimeType) Py_None, PyDateTimeAPI->TimeType)
#define PyTime_FromTimeAndFold(hour, minute, second, usecond, fold) \
PyDateTimeAPI->Time_FromTimeAndFold(hour, minute, second, usecond, \
Py_None, fold, PyDateTimeAPI->TimeType)
#define PyDelta_FromDSU(days, seconds, useconds) \ #define PyDelta_FromDSU(days, seconds, useconds) \
PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \ PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \
PyDateTimeAPI->DeltaType) PyDateTimeAPI->DeltaType)
......
This diff is collapsed.
This diff is collapsed.
...@@ -112,6 +112,8 @@ resources to test. Currently only the following are defined: ...@@ -112,6 +112,8 @@ resources to test. Currently only the following are defined:
gui - Run tests that require a running GUI. gui - Run tests that require a running GUI.
tzdata - Run tests that require timezone data.
To enable all resources except one, use '-uall,-<resource>'. For To enable all resources except one, use '-uall,-<resource>'. For
example, to run all the tests except for the gui tests, give the example, to run all the tests except for the gui tests, give the
option '-uall,-gui'. option '-uall,-gui'.
...@@ -119,7 +121,7 @@ option '-uall,-gui'. ...@@ -119,7 +121,7 @@ option '-uall,-gui'.
RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network', RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network',
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui') 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'tzdata')
class _ArgParser(argparse.ArgumentParser): class _ArgParser(argparse.ArgumentParser):
......
...@@ -26,6 +26,8 @@ Core and Builtins ...@@ -26,6 +26,8 @@ Core and Builtins
Library Library
------- -------
- Issue #24773: Implemented PEP 495 (Local Time Disambiguation).
- Expose the EPOLLEXCLUSIVE constant (when it is defined) in the select module. - Expose the EPOLLEXCLUSIVE constant (when it is defined) in the select module.
- Issue #27567: Expose the EPOLLRDHUP and POLLRDHUP constants in the select - Issue #27567: Expose the EPOLLRDHUP and POLLRDHUP constants in the select
......
This diff is collapsed.
import sys
import os
import struct
from array import array
from collections import namedtuple
from datetime import datetime, timedelta
ttinfo = namedtuple('ttinfo', ['tt_gmtoff', 'tt_isdst', 'tt_abbrind'])
class TZInfo:
def __init__(self, transitions, type_indices, ttis, abbrs):
self.transitions = transitions
self.type_indices = type_indices
self.ttis = ttis
self.abbrs = abbrs
@classmethod
def fromfile(cls, fileobj):
if fileobj.read(4).decode() != "TZif":
raise ValueError("not a zoneinfo file")
fileobj.seek(20)
header = fileobj.read(24)
tzh = (tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt,
tzh_timecnt, tzh_typecnt, tzh_charcnt) = struct.unpack(">6l", header)
transitions = array('i')
transitions.fromfile(fileobj, tzh_timecnt)
if sys.byteorder != 'big':
transitions.byteswap()
type_indices = array('B')
type_indices.fromfile(fileobj, tzh_timecnt)
ttis = []
for i in range(tzh_typecnt):
ttis.append(ttinfo._make(struct.unpack(">lbb", fileobj.read(6))))
abbrs = fileobj.read(tzh_charcnt)
self = cls(transitions, type_indices, ttis, abbrs)
self.tzh = tzh
return self
def dump(self, stream, start=None, end=None):
for j, (trans, i) in enumerate(zip(self.transitions, self.type_indices)):
utc = datetime.utcfromtimestamp(trans)
tti = self.ttis[i]
lmt = datetime.utcfromtimestamp(trans + tti.tt_gmtoff)
abbrind = tti.tt_abbrind
abbr = self.abbrs[abbrind:self.abbrs.find(0, abbrind)].decode()
if j > 0:
prev_tti = self.ttis[self.type_indices[j - 1]]
shift = " %+g" % ((tti.tt_gmtoff - prev_tti.tt_gmtoff) / 3600)
else:
shift = ''
print("%s UTC = %s %-5s isdst=%d" % (utc, lmt, abbr, tti[1]) + shift, file=stream)
@classmethod
def zonelist(cls, zonedir='/usr/share/zoneinfo'):
zones = []
for root, _, files in os.walk(zonedir):
for f in files:
p = os.path.join(root, f)
with open(p, 'rb') as o:
magic = o.read(4)
if magic == b'TZif':
zones.append(p[len(zonedir) + 1:])
return zones
if __name__ == '__main__':
if len(sys.argv) < 2:
zones = TZInfo.zonelist()
for z in zones:
print(z)
sys.exit()
filepath = sys.argv[1]
if not filepath.startswith('/'):
filepath = os.path.join('/usr/share/zoneinfo', filepath)
with open(filepath, 'rb') as fileobj:
tzi = TZInfo.fromfile(fileobj)
tzi.dump(sys.stdout)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment