Commit 5d0c5983 authored by Alexander Belopolsky's avatar Alexander Belopolsky

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

parent 638e6220
......@@ -81,6 +81,7 @@ typedef struct
typedef struct
{
_PyDateTime_TIMEHEAD
unsigned char fold;
PyObject *tzinfo;
} PyDateTime_Time; /* hastzinfo true */
......@@ -108,6 +109,7 @@ typedef struct
typedef struct
{
_PyDateTime_DATETIMEHEAD
unsigned char fold;
PyObject *tzinfo;
} PyDateTime_DateTime; /* hastzinfo true */
......@@ -125,6 +127,7 @@ typedef struct
((((PyDateTime_DateTime*)o)->data[7] << 16) | \
(((PyDateTime_DateTime*)o)->data[8] << 8) | \
((PyDateTime_DateTime*)o)->data[9])
#define PyDateTime_DATE_GET_FOLD(o) (((PyDateTime_DateTime*)o)->fold)
/* Apply for time instances. */
#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0])
......@@ -134,6 +137,7 @@ typedef struct
((((PyDateTime_Time*)o)->data[3] << 16) | \
(((PyDateTime_Time*)o)->data[4] << 8) | \
((PyDateTime_Time*)o)->data[5])
#define PyDateTime_TIME_GET_FOLD(o) (((PyDateTime_Time*)o)->fold)
/* Apply for time delta instances */
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)
......@@ -162,6 +166,11 @@ typedef struct {
PyObject *(*DateTime_FromTimestamp)(PyObject*, 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;
#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
......@@ -217,10 +226,18 @@ static PyDateTime_CAPI *PyDateTimeAPI = NULL;
PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \
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) \
PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \
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) \
PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \
PyDateTimeAPI->DeltaType)
......
This diff is collapsed.
This diff is collapsed.
......@@ -112,6 +112,8 @@ resources to test. Currently only the following are defined:
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
example, to run all the tests except for the gui tests, give the
option '-uall,-gui'.
......@@ -119,7 +121,7 @@ option '-uall,-gui'.
RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network',
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui')
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'tzdata')
class _ArgParser(argparse.ArgumentParser):
......
......@@ -26,6 +26,8 @@ Core and Builtins
Library
-------
- Issue #24773: Implemented PEP 495 (Local Time Disambiguation).
- Expose the EPOLLEXCLUSIVE constant (when it is defined) in the select module.
- 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