Merge pull request #617 from JackDandy/feature/UpdateDateutil

Update dateutil library 2.4.2 (083f666) to 2.4.2 (d4baf97).
This commit is contained in:
JackDandy 2016-01-12 03:20:48 +00:00
commit d32327576e
10 changed files with 497 additions and 289 deletions

View file

@ -11,6 +11,7 @@
* Update cachecontrol library 0.11.2 to 0.11.5 * Update cachecontrol library 0.11.2 to 0.11.5
* Update Certifi to 2015.11.20.1 (385476b) * Update Certifi to 2015.11.20.1 (385476b)
* Update chardet packages 2.3.0 (26982c5) to 2.3.0 (d7fae98) * Update chardet packages 2.3.0 (26982c5) to 2.3.0 (d7fae98)
* Update dateutil library 2.4.2 (083f666) to 2.4.2 (d4baf97)
### 0.11.0 (2016-01-10 22:30:00 UTC) ### 0.11.0 (2016-01-10 22:30:00 UTC)

View file

@ -71,12 +71,6 @@ class _timelex(object):
instream = StringIO(instream) instream = StringIO(instream)
self.instream = instream self.instream = instream
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'
'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'
'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ')
self.numchars = '0123456789'
self.whitespace = ' \t\r\n'
self.charstack = [] self.charstack = []
self.tokenstack = [] self.tokenstack = []
self.eof = False self.eof = False
@ -101,9 +95,6 @@ class _timelex(object):
seenletters = False seenletters = False
token = None token = None
state = None state = None
wordchars = self.wordchars
numchars = self.numchars
whitespace = self.whitespace
while not self.eof: while not self.eof:
# We only realize that we've reached the end of a token when we # We only realize that we've reached the end of a token when we
@ -124,11 +115,11 @@ class _timelex(object):
# First character of the token - determines if we're starting # First character of the token - determines if we're starting
# to parse a word, a number or something else. # to parse a word, a number or something else.
token = nextchar token = nextchar
if nextchar in wordchars: if self.isword(nextchar):
state = 'a' state = 'a'
elif nextchar in numchars: elif self.isnum(nextchar):
state = '0' state = '0'
elif nextchar in whitespace: elif self.isspace(nextchar):
token = ' ' token = ' '
break # emit token break # emit token
else: else:
@ -137,7 +128,7 @@ class _timelex(object):
# If we've already started reading a word, we keep reading # If we've already started reading a word, we keep reading
# letters until we find something that's not part of a word. # letters until we find something that's not part of a word.
seenletters = True seenletters = True
if nextchar in wordchars: if self.isword(nextchar):
token += nextchar token += nextchar
elif nextchar == '.': elif nextchar == '.':
token += nextchar token += nextchar
@ -148,7 +139,7 @@ class _timelex(object):
elif state == '0': elif state == '0':
# If we've already started reading a number, we keep reading # If we've already started reading a number, we keep reading
# numbers until we find something that doesn't fit. # numbers until we find something that doesn't fit.
if nextchar in numchars: if self.isnum(nextchar):
token += nextchar token += nextchar
elif nextchar == '.' or (nextchar == ',' and len(token) >= 2): elif nextchar == '.' or (nextchar == ',' and len(token) >= 2):
token += nextchar token += nextchar
@ -160,9 +151,9 @@ class _timelex(object):
# If we've seen some letters and a dot separator, continue # If we've seen some letters and a dot separator, continue
# parsing, and the tokens will be broken up later. # parsing, and the tokens will be broken up later.
seenletters = True seenletters = True
if nextchar == '.' or nextchar in wordchars: if nextchar == '.' or self.isword(nextchar):
token += nextchar token += nextchar
elif nextchar in numchars and token[-1] == '.': elif self.isnum(nextchar) and token[-1] == '.':
token += nextchar token += nextchar
state = '0.' state = '0.'
else: else:
@ -171,9 +162,9 @@ class _timelex(object):
elif state == '0.': elif state == '0.':
# If we've seen at least one dot separator, keep going, we'll # If we've seen at least one dot separator, keep going, we'll
# break up the tokens later. # break up the tokens later.
if nextchar == '.' or nextchar in numchars: if nextchar == '.' or self.isnum(nextchar):
token += nextchar token += nextchar
elif nextchar in wordchars and token[-1] == '.': elif self.isword(nextchar) and token[-1] == '.':
token += nextchar token += nextchar
state = 'a.' state = 'a.'
else: else:
@ -206,9 +197,24 @@ class _timelex(object):
def next(self): def next(self):
return self.__next__() # Python 2.x support return self.__next__() # Python 2.x support
@classmethod
def split(cls, s): def split(cls, s):
return list(cls(s)) return list(cls(s))
split = classmethod(split)
@classmethod
def isword(cls, nextchar):
""" Whether or not the next character is part of a word """
return nextchar.isalpha()
@classmethod
def isnum(cls, nextchar):
""" Whether the next character is part of a number """
return nextchar.isdigit()
@classmethod
def isspace(cls, nextchar):
""" Whether the next character is whitespace """
return nextchar.isspace()
class _resultbase(object): class _resultbase(object):
@ -462,7 +468,7 @@ class parser(object):
:class:`tzinfo` is not in a valid format, or if an invalid date :class:`tzinfo` is not in a valid format, or if an invalid date
would be created. would be created.
:raises OverFlowError: :raises OverflowError:
Raised if the parsed date exceeds the largest valid C integer on Raised if the parsed date exceeds the largest valid C integer on
your system. your system.
""" """
@ -643,7 +649,7 @@ class parser(object):
>>> from dateutil.parser import parse >>> from dateutil.parser import parse
>>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True) >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
(datetime.datetime(2011, 1, 1, 8, 21), (u'Today is ', u' ', u'at ')) (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
""" """
if fuzzy_with_tokens: if fuzzy_with_tokens:
@ -1202,7 +1208,7 @@ def parse(timestr, parserinfo=None, **kwargs):
:class:`tzinfo` is not in a valid format, or if an invalid date :class:`tzinfo` is not in a valid format, or if an invalid date
would be created. would be created.
:raises OverFlowError: :raises OverflowError:
Raised if the parsed date exceeds the largest valid C integer on Raised if the parsed date exceeds the largest valid C integer on
your system. your system.
""" """

View file

@ -40,75 +40,75 @@ MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
class relativedelta(object): class relativedelta(object):
""" """
The relativedelta type is based on the specification of the excellent The relativedelta type is based on the specification of the excellent
work done by M.-A. Lemburg in his work done by M.-A. Lemburg in his
`mx.DateTime <http://www.egenix.com/files/python/mxDateTime.html>`_ extension. `mx.DateTime <http://www.egenix.com/files/python/mxDateTime.html>`_ extension.
However, notice that this type does *NOT* implement the same algorithm as However, notice that this type does *NOT* implement the same algorithm as
his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
There are two different ways to build a relativedelta instance. The There are two different ways to build a relativedelta instance. The
first one is passing it two date/datetime classes:: first one is passing it two date/datetime classes::
relativedelta(datetime1, datetime2) relativedelta(datetime1, datetime2)
The second one is passing it any number of the following keyword arguments:: The second one is passing it any number of the following keyword arguments::
relativedelta(arg1=x,arg2=y,arg3=z...) relativedelta(arg1=x,arg2=y,arg3=z...)
year, month, day, hour, minute, second, microsecond: year, month, day, hour, minute, second, microsecond:
Absolute information (argument is singular); adding or subtracting a Absolute information (argument is singular); adding or subtracting a
relativedelta with absolute information does not perform an aritmetic relativedelta with absolute information does not perform an aritmetic
operation, but rather REPLACES the corresponding value in the operation, but rather REPLACES the corresponding value in the
original datetime with the value(s) in relativedelta. original datetime with the value(s) in relativedelta.
years, months, weeks, days, hours, minutes, seconds, microseconds: years, months, weeks, days, hours, minutes, seconds, microseconds:
Relative information, may be negative (argument is plural); adding Relative information, may be negative (argument is plural); adding
or subtracting a relativedelta with relative information performs or subtracting a relativedelta with relative information performs
the corresponding aritmetic operation on the original datetime value the corresponding aritmetic operation on the original datetime value
with the information in the relativedelta. with the information in the relativedelta.
weekday: weekday:
One of the weekday instances (MO, TU, etc). These instances may One of the weekday instances (MO, TU, etc). These instances may
receive a parameter N, specifying the Nth weekday, which could receive a parameter N, specifying the Nth weekday, which could
be positive or negative (like MO(+1) or MO(-2). Not specifying be positive or negative (like MO(+1) or MO(-2). Not specifying
it is the same as specifying +1. You can also use an integer, it is the same as specifying +1. You can also use an integer,
where 0=MO. where 0=MO.
leapdays: leapdays:
Will add given days to the date found, if year is a leap Will add given days to the date found, if year is a leap
year, and the date found is post 28 of february. year, and the date found is post 28 of february.
yearday, nlyearday: yearday, nlyearday:
Set the yearday or the non-leap year day (jump leap days). Set the yearday or the non-leap year day (jump leap days).
These are converted to day/month/leapdays information. These are converted to day/month/leapdays information.
Here is the behavior of operations with relativedelta: Here is the behavior of operations with relativedelta:
1. Calculate the absolute year, using the 'year' argument, or the 1. Calculate the absolute year, using the 'year' argument, or the
original datetime year, if the argument is not present. original datetime year, if the argument is not present.
2. Add the relative 'years' argument to the absolute year. 2. Add the relative 'years' argument to the absolute year.
3. Do steps 1 and 2 for month/months. 3. Do steps 1 and 2 for month/months.
4. Calculate the absolute day, using the 'day' argument, or the 4. Calculate the absolute day, using the 'day' argument, or the
original datetime day, if the argument is not present. Then, original datetime day, if the argument is not present. Then,
subtract from the day until it fits in the year and month subtract from the day until it fits in the year and month
found after their operations. found after their operations.
5. Add the relative 'days' argument to the absolute day. Notice 5. Add the relative 'days' argument to the absolute day. Notice
that the 'weeks' argument is multiplied by 7 and added to that the 'weeks' argument is multiplied by 7 and added to
'days'. 'days'.
6. Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, 6. Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds,
microsecond/microseconds. microsecond/microseconds.
7. If the 'weekday' argument is present, calculate the weekday, 7. If the 'weekday' argument is present, calculate the weekday,
with the given (wday, nth) tuple. wday is the index of the with the given (wday, nth) tuple. wday is the index of the
weekday (0-6, 0=Mon), and nth is the number of weeks to add weekday (0-6, 0=Mon), and nth is the number of weeks to add
forward or backward, depending on its signal. Notice that if forward or backward, depending on its signal. Notice that if
the calculated date is already Monday, for example, using the calculated date is already Monday, for example, using
(0, 1) or (0, -1) won't change the day. (0, 1) or (0, -1) won't change the day.
""" """
def __init__(self, dt1=None, dt2=None, def __init__(self, dt1=None, dt2=None,

View file

@ -10,7 +10,10 @@ import datetime
import calendar import calendar
import sys import sys
from fractions import gcd try:
from math import gcd
except ImportError:
from fractions import gcd
from six import advance_iterator, integer_types from six import advance_iterator, integer_types
from six.moves import _thread from six.moves import _thread

View file

@ -0,0 +1,20 @@
from .tz import *
from six import PY3
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"]
def tzname_in_python2(namefunc):
"""Change unicode output into bytestrings in Python 2
tzname() API changed in Python 3. It used to return bytes, but was changed
to unicode strings
"""
def adjust_encoding(*args, **kwargs):
name = namefunc(*args, **kwargs)
if name is not None and not PY3:
name = name.encode()
return name
return adjust_encoding

View file

@ -14,9 +14,10 @@ import sys
import os import os
from six import string_types, PY3 from six import string_types, PY3
from .__init__ import tzname_in_python2
try: try:
from dateutil.tzwin import tzwin, tzwinlocal from .win import tzwin, tzwinlocal
except ImportError: except ImportError:
tzwin = tzwinlocal = None tzwin = tzwinlocal = None
@ -24,29 +25,9 @@ relativedelta = None
parser = None parser = None
rrule = None rrule = None
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"]
def tzname_in_python2(namefunc):
"""Change unicode output into bytestrings in Python 2
tzname() API changed in Python 3. It used to return bytes, but was changed
to unicode strings
"""
def adjust_encoding(*args, **kwargs):
name = namefunc(*args, **kwargs)
if name is not None and not PY3:
name = name.encode()
return name
return adjust_encoding
ZERO = datetime.timedelta(0) ZERO = datetime.timedelta(0)
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
class tzutc(datetime.tzinfo): class tzutc(datetime.tzinfo):
def utcoffset(self, dt): def utcoffset(self, dt):

187
lib/dateutil/tz/tzwin.py Normal file
View file

@ -0,0 +1,187 @@
# This code was originally contributed by Jeffrey Harris.
import datetime
import struct
from six.moves import winreg
from .__init__ import tzname_in_python2
__all__ = ["tzwin", "tzwinlocal"]
ONEWEEK = datetime.timedelta(7)
TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
def _settzkeyname():
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
winreg.OpenKey(handle, TZKEYNAMENT).Close()
TZKEYNAME = TZKEYNAMENT
except WindowsError:
TZKEYNAME = TZKEYNAME9X
handle.Close()
return TZKEYNAME
TZKEYNAME = _settzkeyname()
class tzwinbase(datetime.tzinfo):
"""tzinfo class based on win32's timezones available in the registry."""
def utcoffset(self, dt):
if self._isdst(dt):
return datetime.timedelta(minutes=self._dstoffset)
else:
return datetime.timedelta(minutes=self._stdoffset)
def dst(self, dt):
if self._isdst(dt):
minutes = self._dstoffset - self._stdoffset
return datetime.timedelta(minutes=minutes)
else:
return datetime.timedelta(0)
@tzname_in_python2
def tzname(self, dt):
if self._isdst(dt):
return self._dstname
else:
return self._stdname
def list():
"""Return a list of all time zones known to the system."""
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
tzkey = winreg.OpenKey(handle, TZKEYNAME)
result = [winreg.EnumKey(tzkey, i)
for i in range(winreg.QueryInfoKey(tzkey)[0])]
tzkey.Close()
handle.Close()
return result
list = staticmethod(list)
def display(self):
return self._display
def _isdst(self, dt):
if not self._dstmonth:
# dstmonth == 0 signals the zone has no daylight saving time
return False
dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek,
self._dsthour, self._dstminute,
self._dstweeknumber)
dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek,
self._stdhour, self._stdminute,
self._stdweeknumber)
if dston < dstoff:
return dston <= dt.replace(tzinfo=None) < dstoff
else:
return not dstoff <= dt.replace(tzinfo=None) < dston
class tzwin(tzwinbase):
def __init__(self, name):
self._name = name
# multiple contexts only possible in 2.7 and 3.1, we still support 2.6
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle,
"%s\%s" % (TZKEYNAME, name)) as tzkey:
keydict = valuestodict(tzkey)
self._stdname = keydict["Std"]
self._dstname = keydict["Dlt"]
self._display = keydict["Display"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=3l16h", keydict["TZI"])
self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1
# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[4:9]
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[12:17]
def __repr__(self):
return "tzwin(%s)" % repr(self._name)
def __reduce__(self):
return (self.__class__, (self._name,))
class tzwinlocal(tzwinbase):
def __init__(self):
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
keydict = valuestodict(tzlocalkey)
self._stdname = keydict["StandardName"]
self._dstname = keydict["DaylightName"]
try:
with winreg.OpenKey(
handle, "%s\%s" % (TZKEYNAME, self._stdname)) as tzkey:
_keydict = valuestodict(tzkey)
self._display = _keydict["Display"]
except OSError:
self._display = None
self._stdoffset = -keydict["Bias"]-keydict["StandardBias"]
self._dstoffset = self._stdoffset-keydict["DaylightBias"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=8h", keydict["StandardStart"])
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[1:6]
tup = struct.unpack("=8h", keydict["DaylightStart"])
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[1:6]
def __reduce__(self):
return (self.__class__, ())
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
first = datetime.datetime(year, month, 1, hour, minute)
weekdayone = first.replace(day=((dayofweek-first.isoweekday()) % 7+1))
for n in range(whichweek):
dt = weekdayone+(whichweek-n)*ONEWEEK
if dt.month == month:
return dt
def valuestodict(key):
"""Convert a registry key's values to a dictionary."""
dict = {}
size = winreg.QueryInfoKey(key)[1]
for i in range(size):
data = winreg.EnumValue(key, i)
dict[data[0]] = data[1]
return dict

187
lib/dateutil/tz/win.py Normal file
View file

@ -0,0 +1,187 @@
# This code was originally contributed by Jeffrey Harris.
import datetime
import struct
from six.moves import winreg
from .__init__ import tzname_in_python2
__all__ = ["tzwin", "tzwinlocal"]
ONEWEEK = datetime.timedelta(7)
TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
def _settzkeyname():
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
winreg.OpenKey(handle, TZKEYNAMENT).Close()
TZKEYNAME = TZKEYNAMENT
except WindowsError:
TZKEYNAME = TZKEYNAME9X
handle.Close()
return TZKEYNAME
TZKEYNAME = _settzkeyname()
class tzwinbase(datetime.tzinfo):
"""tzinfo class based on win32's timezones available in the registry."""
def utcoffset(self, dt):
if self._isdst(dt):
return datetime.timedelta(minutes=self._dstoffset)
else:
return datetime.timedelta(minutes=self._stdoffset)
def dst(self, dt):
if self._isdst(dt):
minutes = self._dstoffset - self._stdoffset
return datetime.timedelta(minutes=minutes)
else:
return datetime.timedelta(0)
@tzname_in_python2
def tzname(self, dt):
if self._isdst(dt):
return self._dstname
else:
return self._stdname
def list():
"""Return a list of all time zones known to the system."""
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
tzkey = winreg.OpenKey(handle, TZKEYNAME)
result = [winreg.EnumKey(tzkey, i)
for i in range(winreg.QueryInfoKey(tzkey)[0])]
tzkey.Close()
handle.Close()
return result
list = staticmethod(list)
def display(self):
return self._display
def _isdst(self, dt):
if not self._dstmonth:
# dstmonth == 0 signals the zone has no daylight saving time
return False
dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek,
self._dsthour, self._dstminute,
self._dstweeknumber)
dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek,
self._stdhour, self._stdminute,
self._stdweeknumber)
if dston < dstoff:
return dston <= dt.replace(tzinfo=None) < dstoff
else:
return not dstoff <= dt.replace(tzinfo=None) < dston
class tzwin(tzwinbase):
def __init__(self, name):
self._name = name
# multiple contexts only possible in 2.7 and 3.1, we still support 2.6
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle,
"%s\%s" % (TZKEYNAME, name)) as tzkey:
keydict = valuestodict(tzkey)
self._stdname = keydict["Std"]
self._dstname = keydict["Dlt"]
self._display = keydict["Display"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=3l16h", keydict["TZI"])
self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1
# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[4:9]
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[12:17]
def __repr__(self):
return "tzwin(%s)" % repr(self._name)
def __reduce__(self):
return (self.__class__, (self._name,))
class tzwinlocal(tzwinbase):
def __init__(self):
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
keydict = valuestodict(tzlocalkey)
self._stdname = keydict["StandardName"]
self._dstname = keydict["DaylightName"]
try:
with winreg.OpenKey(
handle, "%s\%s" % (TZKEYNAME, self._stdname)) as tzkey:
_keydict = valuestodict(tzkey)
self._display = _keydict["Display"]
except OSError:
self._display = None
self._stdoffset = -keydict["Bias"]-keydict["StandardBias"]
self._dstoffset = self._stdoffset-keydict["DaylightBias"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=8h", keydict["StandardStart"])
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[1:6]
tup = struct.unpack("=8h", keydict["DaylightStart"])
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[1:6]
def __reduce__(self):
return (self.__class__, ())
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
first = datetime.datetime(year, month, 1, hour, minute)
weekdayone = first.replace(day=((dayofweek-first.isoweekday()) % 7+1))
for n in range(whichweek):
dt = weekdayone+(whichweek-n)*ONEWEEK
if dt.month == month:
return dt
def valuestodict(key):
"""Convert a registry key's values to a dictionary."""
dict = {}
size = winreg.QueryInfoKey(key)[1]
for i in range(size):
data = winreg.EnumValue(key, i)
dict[data[0]] = data[1]
return dict

View file

@ -1,187 +1,2 @@
# This code was originally contributed by Jeffrey Harris. # tzwin has moved to dateutil.tz.win
import datetime from .tz.win import *
import struct
from six.moves import winreg
from .tz import tzname_in_python2
__all__ = ["tzwin", "tzwinlocal"]
ONEWEEK = datetime.timedelta(7)
TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
def _settzkeyname():
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
winreg.OpenKey(handle, TZKEYNAMENT).Close()
TZKEYNAME = TZKEYNAMENT
except WindowsError:
TZKEYNAME = TZKEYNAME9X
handle.Close()
return TZKEYNAME
TZKEYNAME = _settzkeyname()
class tzwinbase(datetime.tzinfo):
"""tzinfo class based on win32's timezones available in the registry."""
def utcoffset(self, dt):
if self._isdst(dt):
return datetime.timedelta(minutes=self._dstoffset)
else:
return datetime.timedelta(minutes=self._stdoffset)
def dst(self, dt):
if self._isdst(dt):
minutes = self._dstoffset - self._stdoffset
return datetime.timedelta(minutes=minutes)
else:
return datetime.timedelta(0)
@tzname_in_python2
def tzname(self, dt):
if self._isdst(dt):
return self._dstname
else:
return self._stdname
def list():
"""Return a list of all time zones known to the system."""
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
tzkey = winreg.OpenKey(handle, TZKEYNAME)
result = [winreg.EnumKey(tzkey, i)
for i in range(winreg.QueryInfoKey(tzkey)[0])]
tzkey.Close()
handle.Close()
return result
list = staticmethod(list)
def display(self):
return self._display
def _isdst(self, dt):
if not self._dstmonth:
# dstmonth == 0 signals the zone has no daylight saving time
return False
dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek,
self._dsthour, self._dstminute,
self._dstweeknumber)
dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek,
self._stdhour, self._stdminute,
self._stdweeknumber)
if dston < dstoff:
return dston <= dt.replace(tzinfo=None) < dstoff
else:
return not dstoff <= dt.replace(tzinfo=None) < dston
class tzwin(tzwinbase):
def __init__(self, name):
self._name = name
# multiple contexts only possible in 2.7 and 3.1, we still support 2.6
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle,
"%s\%s" % (TZKEYNAME, name)) as tzkey:
keydict = valuestodict(tzkey)
self._stdname = keydict["Std"]
self._dstname = keydict["Dlt"]
self._display = keydict["Display"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=3l16h", keydict["TZI"])
self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1
# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[4:9]
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[12:17]
def __repr__(self):
return "tzwin(%s)" % repr(self._name)
def __reduce__(self):
return (self.__class__, (self._name,))
class tzwinlocal(tzwinbase):
def __init__(self):
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
keydict = valuestodict(tzlocalkey)
self._stdname = keydict["StandardName"]
self._dstname = keydict["DaylightName"]
try:
with winreg.OpenKey(
handle, "%s\%s" % (TZKEYNAME, self._stdname)) as tzkey:
_keydict = valuestodict(tzkey)
self._display = _keydict["Display"]
except OSError:
self._display = None
self._stdoffset = -keydict["Bias"]-keydict["StandardBias"]
self._dstoffset = self._stdoffset-keydict["DaylightBias"]
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
tup = struct.unpack("=8h", keydict["StandardStart"])
(self._stdmonth,
self._stddayofweek, # Sunday = 0
self._stdweeknumber, # Last = 5
self._stdhour,
self._stdminute) = tup[1:6]
tup = struct.unpack("=8h", keydict["DaylightStart"])
(self._dstmonth,
self._dstdayofweek, # Sunday = 0
self._dstweeknumber, # Last = 5
self._dsthour,
self._dstminute) = tup[1:6]
def __reduce__(self):
return (self.__class__, ())
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
first = datetime.datetime(year, month, 1, hour, minute)
weekdayone = first.replace(day=((dayofweek-first.isoweekday()) % 7+1))
for n in range(whichweek):
dt = weekdayone+(whichweek-n)*ONEWEEK
if dt.month == month:
return dt
def valuestodict(key):
"""Convert a registry key's values to a dictionary."""
dict = {}
size = winreg.QueryInfoKey(key)[1]
for i in range(size):
data = winreg.EnumValue(key, i)
dict[data[0]] = data[1]
return dict

View file

@ -25,12 +25,8 @@ def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
try: try:
check_call(["zic", "-d", zonedir] + filepaths) check_call(["zic", "-d", zonedir] + filepaths)
except OSError as e: except OSError as e:
if e.errno == 2: _print_on_nosuchfile(e)
logging.error( raise
"Could not find zic. Perhaps you need to install "
"libc-bin or some other package that provides it, "
"or it's not in your PATH?")
raise
# write metadata file # write metadata file
with open(os.path.join(zonedir, METADATA_FN), 'w') as f: with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
json.dump(metadata, f, indent=4, sort_keys=True) json.dump(metadata, f, indent=4, sort_keys=True)
@ -41,3 +37,15 @@ def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
tf.add(entrypath, entry) tf.add(entrypath, entry)
finally: finally:
shutil.rmtree(tmpdir) shutil.rmtree(tmpdir)
def _print_on_nosuchfile(e):
"""Print helpful troubleshooting message
e is an exception raised by subprocess.check_call()
"""
if e.errno == 2:
logging.error(
"Could not find zic. Perhaps you need to install "
"libc-bin or some other package that provides it, "
"or it's not in your PATH?")