mirror of
https://github.com/SickGear/SickGear.git
synced 2025-01-07 10:33:38 +00:00
Merge pull request #413 from JackDandy/feature/UpdateDateutil
Update dateutil library 2.2 to 2.4.2 (a6b8925).
This commit is contained in:
commit
6f77328bc1
10 changed files with 1531 additions and 651 deletions
|
@ -42,6 +42,7 @@
|
||||||
* Update Six compatibility library 1.5.2 to 1.9.0 (8a545f4)
|
* Update Six compatibility library 1.5.2 to 1.9.0 (8a545f4)
|
||||||
* Update SimpleJSON library 2.0.9 to 3.7.3 (0bcdf20)
|
* Update SimpleJSON library 2.0.9 to 3.7.3 (0bcdf20)
|
||||||
* Update xmltodict library 0.9.0 to 0.9.2 (579a005)
|
* Update xmltodict library 0.9.0 to 0.9.2 (579a005)
|
||||||
|
* Update dateutil library 2.2 to 2.4.2 (a6b8925)
|
||||||
|
|
||||||
[develop changelog]
|
[develop changelog]
|
||||||
* Update Requests library 2.7.0 (ab1f493) to 2.7.0 (8b5e457)
|
* Update Requests library 2.7.0 (ab1f493) to 2.7.0 (8b5e457)
|
||||||
|
|
|
@ -1,10 +1,2 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
__version__ = "2.4.2"
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
|
||||||
|
|
||||||
This module offers extensions to the standard Python
|
|
||||||
datetime module.
|
|
||||||
"""
|
|
||||||
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
|
||||||
__license__ = "Simplified BSD"
|
|
||||||
__version__ = "2.2"
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
This module offers a generic easter computing method for any given year, using
|
||||||
|
Western, Orthodox or Julian algorithms.
|
||||||
This module offers extensions to the standard Python
|
|
||||||
datetime module.
|
|
||||||
"""
|
"""
|
||||||
__license__ = "Simplified BSD"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]
|
__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]
|
||||||
|
|
||||||
EASTER_JULIAN = 1
|
EASTER_JULIAN = 1
|
||||||
EASTER_ORTHODOX = 2
|
EASTER_ORTHODOX = 2
|
||||||
EASTER_WESTERN = 3
|
EASTER_WESTERN = 3
|
||||||
|
|
||||||
|
|
||||||
def easter(year, method=EASTER_WESTERN):
|
def easter(year, method=EASTER_WESTERN):
|
||||||
"""
|
"""
|
||||||
|
@ -24,7 +23,7 @@ def easter(year, method=EASTER_WESTERN):
|
||||||
|
|
||||||
This algorithm implements three different easter
|
This algorithm implements three different easter
|
||||||
calculation methods:
|
calculation methods:
|
||||||
|
|
||||||
1 - Original calculation in Julian calendar, valid in
|
1 - Original calculation in Julian calendar, valid in
|
||||||
dates after 326 AD
|
dates after 326 AD
|
||||||
2 - Original method, with date converted to Gregorian
|
2 - Original method, with date converted to Gregorian
|
||||||
|
@ -39,7 +38,7 @@ def easter(year, method=EASTER_WESTERN):
|
||||||
EASTER_WESTERN = 3
|
EASTER_WESTERN = 3
|
||||||
|
|
||||||
The default method is method 3.
|
The default method is method 3.
|
||||||
|
|
||||||
More about the algorithm may be found at:
|
More about the algorithm may be found at:
|
||||||
|
|
||||||
http://users.chariot.net.au/~gmarts/eastalg.htm
|
http://users.chariot.net.au/~gmarts/eastalg.htm
|
||||||
|
@ -68,24 +67,23 @@ def easter(year, method=EASTER_WESTERN):
|
||||||
e = 0
|
e = 0
|
||||||
if method < 3:
|
if method < 3:
|
||||||
# Old method
|
# Old method
|
||||||
i = (19*g+15)%30
|
i = (19*g + 15) % 30
|
||||||
j = (y+y//4+i)%7
|
j = (y + y//4 + i) % 7
|
||||||
if method == 2:
|
if method == 2:
|
||||||
# Extra dates to convert Julian to Gregorian date
|
# Extra dates to convert Julian to Gregorian date
|
||||||
e = 10
|
e = 10
|
||||||
if y > 1600:
|
if y > 1600:
|
||||||
e = e+y//100-16-(y//100-16)//4
|
e = e + y//100 - 16 - (y//100 - 16)//4
|
||||||
else:
|
else:
|
||||||
# New method
|
# New method
|
||||||
c = y//100
|
c = y//100
|
||||||
h = (c-c//4-(8*c+13)//25+19*g+15)%30
|
h = (c - c//4 - (8*c + 13)//25 + 19*g + 15) % 30
|
||||||
i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11))
|
i = h - (h//28)*(1 - (h//28)*(29//(h + 1))*((21 - g)//11))
|
||||||
j = (y+y//4+i+2-c+c//4)%7
|
j = (y + y//4 + i + 2 - c + c//4) % 7
|
||||||
|
|
||||||
# p can be from -6 to 56 corresponding to dates 22 March to 23 May
|
# p can be from -6 to 56 corresponding to dates 22 March to 23 May
|
||||||
# (later dates apply to method 2, although 23 May never actually occurs)
|
# (later dates apply to method 2, although 23 May never actually occurs)
|
||||||
p = i-j+e
|
p = i - j + e
|
||||||
d = 1+(p+27+(p+6)//40)%31
|
d = 1 + (p + 27 + (p + 6)//40) % 31
|
||||||
m = 3+(p+26)//30
|
m = 3 + (p + 26)//30
|
||||||
return datetime.date(int(y), int(m), int(d))
|
return datetime.date(int(y), int(m), int(d))
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +1,4 @@
|
||||||
"""
|
# -*- coding: utf-8 -*-
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
|
||||||
|
|
||||||
This module offers extensions to the standard Python
|
|
||||||
datetime module.
|
|
||||||
"""
|
|
||||||
__license__ = "Simplified BSD"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
@ -13,6 +6,7 @@ from six import integer_types
|
||||||
|
|
||||||
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
|
||||||
|
|
||||||
|
|
||||||
class weekday(object):
|
class weekday(object):
|
||||||
__slots__ = ["weekday", "n"]
|
__slots__ = ["weekday", "n"]
|
||||||
|
|
||||||
|
@ -43,25 +37,35 @@ class weekday(object):
|
||||||
|
|
||||||
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
|
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 excelent
|
The relativedelta type is based on the specification of the excellent
|
||||||
work done by M.-A. Lemburg in his mx.DateTime extension. However,
|
work done by M.-A. Lemburg in his
|
||||||
notice that this type does *NOT* implement the same algorithm as
|
`mx.DateTime <http://www.egenix.com/files/python/mxDateTime.html>`_ extension.
|
||||||
|
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's 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)
|
||||||
|
|
||||||
And the other way is to use the following keyword arguments:
|
The second one is passing it any number of the following keyword arguments::
|
||||||
|
|
||||||
|
relativedelta(arg1=x,arg2=y,arg3=z...)
|
||||||
|
|
||||||
year, month, day, hour, minute, second, microsecond:
|
year, month, day, hour, minute, second, microsecond:
|
||||||
Absolute information.
|
Absolute information (argument is singular); adding or subtracting a
|
||||||
|
relativedelta with absolute information does not perform an aritmetic
|
||||||
|
operation, but rather REPLACES the corresponding value in the
|
||||||
|
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.
|
Relative information, may be negative (argument is plural); adding
|
||||||
|
or subtracting a relativedelta with relative information performs
|
||||||
|
the corresponding aritmetic operation on the original datetime value
|
||||||
|
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
|
||||||
|
@ -80,26 +84,26 @@ And the other way is to use the following keyword arguments:
|
||||||
|
|
||||||
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
|
||||||
|
@ -114,9 +118,14 @@ Here is the behavior of operations with relativedelta:
|
||||||
yearday=None, nlyearday=None,
|
yearday=None, nlyearday=None,
|
||||||
hour=None, minute=None, second=None, microsecond=None):
|
hour=None, minute=None, second=None, microsecond=None):
|
||||||
if dt1 and dt2:
|
if dt1 and dt2:
|
||||||
if (not isinstance(dt1, datetime.date)) or (not isinstance(dt2, datetime.date)):
|
# datetime is a subclass of date. So both must be date
|
||||||
|
if not (isinstance(dt1, datetime.date) and
|
||||||
|
isinstance(dt2, datetime.date)):
|
||||||
raise TypeError("relativedelta only diffs datetime/date")
|
raise TypeError("relativedelta only diffs datetime/date")
|
||||||
if not type(dt1) == type(dt2): #isinstance(dt1, type(dt2)):
|
# We allow two dates, or two datetimes, so we coerce them to be
|
||||||
|
# of the same type
|
||||||
|
if (isinstance(dt1, datetime.datetime) !=
|
||||||
|
isinstance(dt2, datetime.datetime)):
|
||||||
if not isinstance(dt1, datetime.datetime):
|
if not isinstance(dt1, datetime.datetime):
|
||||||
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
|
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
|
||||||
elif not isinstance(dt2, datetime.datetime):
|
elif not isinstance(dt2, datetime.datetime):
|
||||||
|
@ -158,7 +167,7 @@ Here is the behavior of operations with relativedelta:
|
||||||
else:
|
else:
|
||||||
self.years = years
|
self.years = years
|
||||||
self.months = months
|
self.months = months
|
||||||
self.days = days+weeks*7
|
self.days = days + weeks * 7
|
||||||
self.leapdays = leapdays
|
self.leapdays = leapdays
|
||||||
self.hours = hours
|
self.hours = hours
|
||||||
self.minutes = minutes
|
self.minutes = minutes
|
||||||
|
@ -185,7 +194,8 @@ Here is the behavior of operations with relativedelta:
|
||||||
if yearday > 59:
|
if yearday > 59:
|
||||||
self.leapdays = -1
|
self.leapdays = -1
|
||||||
if yday:
|
if yday:
|
||||||
ydayidx = [31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 366]
|
ydayidx = [31, 59, 90, 120, 151, 181, 212,
|
||||||
|
243, 273, 304, 334, 366]
|
||||||
for idx, ydays in enumerate(ydayidx):
|
for idx, ydays in enumerate(ydayidx):
|
||||||
if yday <= ydays:
|
if yday <= ydays:
|
||||||
self.month = idx+1
|
self.month = idx+1
|
||||||
|
@ -225,13 +235,20 @@ Here is the behavior of operations with relativedelta:
|
||||||
div, mod = divmod(self.months*s, 12)
|
div, mod = divmod(self.months*s, 12)
|
||||||
self.months = mod*s
|
self.months = mod*s
|
||||||
self.years += div*s
|
self.years += div*s
|
||||||
if (self.hours or self.minutes or self.seconds or self.microseconds or
|
if (self.hours or self.minutes or self.seconds or self.microseconds
|
||||||
self.hour is not None or self.minute is not None or
|
or self.hour is not None or self.minute is not None or
|
||||||
self.second is not None or self.microsecond is not None):
|
self.second is not None or self.microsecond is not None):
|
||||||
self._has_time = 1
|
self._has_time = 1
|
||||||
else:
|
else:
|
||||||
self._has_time = 0
|
self._has_time = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def weeks(self):
|
||||||
|
return self.days // 7
|
||||||
|
@weeks.setter
|
||||||
|
def weeks(self, value):
|
||||||
|
self.days = self.days - (self.weeks * 7) + value*7
|
||||||
|
|
||||||
def _set_months(self, months):
|
def _set_months(self, months):
|
||||||
self.months = months
|
self.months = months
|
||||||
if abs(self.months) > 11:
|
if abs(self.months) > 11:
|
||||||
|
@ -244,22 +261,24 @@ Here is the behavior of operations with relativedelta:
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
if isinstance(other, relativedelta):
|
if isinstance(other, relativedelta):
|
||||||
return relativedelta(years=other.years+self.years,
|
return self.__class__(years=other.years+self.years,
|
||||||
months=other.months+self.months,
|
months=other.months+self.months,
|
||||||
days=other.days+self.days,
|
days=other.days+self.days,
|
||||||
hours=other.hours+self.hours,
|
hours=other.hours+self.hours,
|
||||||
minutes=other.minutes+self.minutes,
|
minutes=other.minutes+self.minutes,
|
||||||
seconds=other.seconds+self.seconds,
|
seconds=other.seconds+self.seconds,
|
||||||
microseconds=other.microseconds+self.microseconds,
|
microseconds=(other.microseconds +
|
||||||
leapdays=other.leapdays or self.leapdays,
|
self.microseconds),
|
||||||
year=other.year or self.year,
|
leapdays=other.leapdays or self.leapdays,
|
||||||
month=other.month or self.month,
|
year=other.year or self.year,
|
||||||
day=other.day or self.day,
|
month=other.month or self.month,
|
||||||
weekday=other.weekday or self.weekday,
|
day=other.day or self.day,
|
||||||
hour=other.hour or self.hour,
|
weekday=other.weekday or self.weekday,
|
||||||
minute=other.minute or self.minute,
|
hour=other.hour or self.hour,
|
||||||
second=other.second or self.second,
|
minute=other.minute or self.minute,
|
||||||
microsecond=other.microsecond or self.microsecond)
|
second=other.second or self.second,
|
||||||
|
microsecond=(other.microsecond or
|
||||||
|
self.microsecond))
|
||||||
if not isinstance(other, datetime.date):
|
if not isinstance(other, datetime.date):
|
||||||
raise TypeError("unsupported type for add operation")
|
raise TypeError("unsupported type for add operation")
|
||||||
elif self._has_time and not isinstance(other, datetime.datetime):
|
elif self._has_time and not isinstance(other, datetime.datetime):
|
||||||
|
@ -295,9 +314,9 @@ Here is the behavior of operations with relativedelta:
|
||||||
weekday, nth = self.weekday.weekday, self.weekday.n or 1
|
weekday, nth = self.weekday.weekday, self.weekday.n or 1
|
||||||
jumpdays = (abs(nth)-1)*7
|
jumpdays = (abs(nth)-1)*7
|
||||||
if nth > 0:
|
if nth > 0:
|
||||||
jumpdays += (7-ret.weekday()+weekday)%7
|
jumpdays += (7-ret.weekday()+weekday) % 7
|
||||||
else:
|
else:
|
||||||
jumpdays += (ret.weekday()-weekday)%7
|
jumpdays += (ret.weekday()-weekday) % 7
|
||||||
jumpdays *= -1
|
jumpdays *= -1
|
||||||
ret += datetime.timedelta(days=jumpdays)
|
ret += datetime.timedelta(days=jumpdays)
|
||||||
return ret
|
return ret
|
||||||
|
@ -311,7 +330,7 @@ Here is the behavior of operations with relativedelta:
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
if not isinstance(other, relativedelta):
|
if not isinstance(other, relativedelta):
|
||||||
raise TypeError("unsupported type for sub operation")
|
raise TypeError("unsupported type for sub operation")
|
||||||
return relativedelta(years=self.years-other.years,
|
return self.__class__(years=self.years-other.years,
|
||||||
months=self.months-other.months,
|
months=self.months-other.months,
|
||||||
days=self.days-other.days,
|
days=self.days-other.days,
|
||||||
hours=self.hours-other.hours,
|
hours=self.hours-other.hours,
|
||||||
|
@ -329,7 +348,7 @@ Here is the behavior of operations with relativedelta:
|
||||||
microsecond=self.microsecond or other.microsecond)
|
microsecond=self.microsecond or other.microsecond)
|
||||||
|
|
||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
return relativedelta(years=-self.years,
|
return self.__class__(years=-self.years,
|
||||||
months=-self.months,
|
months=-self.months,
|
||||||
days=-self.days,
|
days=-self.days,
|
||||||
hours=-self.hours,
|
hours=-self.hours,
|
||||||
|
@ -363,10 +382,12 @@ Here is the behavior of operations with relativedelta:
|
||||||
self.minute is None and
|
self.minute is None and
|
||||||
self.second is None and
|
self.second is None and
|
||||||
self.microsecond is None)
|
self.microsecond is None)
|
||||||
|
# Compatibility with Python 2.x
|
||||||
|
__nonzero__ = __bool__
|
||||||
|
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
f = float(other)
|
f = float(other)
|
||||||
return relativedelta(years=int(self.years*f),
|
return self.__class__(years=int(self.years*f),
|
||||||
months=int(self.months*f),
|
months=int(self.months*f),
|
||||||
days=int(self.days*f),
|
days=int(self.days*f),
|
||||||
hours=int(self.hours*f),
|
hours=int(self.hours*f),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
This module offers timezone implementations subclassing the abstract
|
||||||
|
:py:`datetime.tzinfo` type. There are classes to handle tzfile format files
|
||||||
This module offers extensions to the standard Python
|
(usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`, etc), TZ
|
||||||
datetime module.
|
environment string (in all known formats), given ranges (with help from
|
||||||
|
relative deltas), local machine timezone, fixed offset timezone, and UTC
|
||||||
|
timezone.
|
||||||
"""
|
"""
|
||||||
__license__ = "Simplified BSD"
|
|
||||||
|
|
||||||
from six import string_types, PY3
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from six import string_types, PY3
|
||||||
|
|
||||||
|
try:
|
||||||
|
from dateutil.tzwin import tzwin, tzwinlocal
|
||||||
|
except ImportError:
|
||||||
|
tzwin = tzwinlocal = None
|
||||||
|
|
||||||
relativedelta = None
|
relativedelta = None
|
||||||
parser = None
|
parser = None
|
||||||
rrule = None
|
rrule = None
|
||||||
|
@ -21,32 +27,31 @@ rrule = None
|
||||||
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
|
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
|
||||||
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"]
|
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"]
|
||||||
|
|
||||||
try:
|
|
||||||
from dateutil.tzwin import tzwin, tzwinlocal
|
|
||||||
except (ImportError, OSError):
|
|
||||||
tzwin, tzwinlocal = None, None
|
|
||||||
|
|
||||||
def tzname_in_python2(myfunc):
|
def tzname_in_python2(namefunc):
|
||||||
"""Change unicode output into bytestrings in Python 2
|
"""Change unicode output into bytestrings in Python 2
|
||||||
|
|
||||||
tzname() API changed in Python 3. It used to return bytes, but was changed
|
tzname() API changed in Python 3. It used to return bytes, but was changed
|
||||||
to unicode strings
|
to unicode strings
|
||||||
"""
|
"""
|
||||||
def inner_func(*args, **kwargs):
|
def adjust_encoding(*args, **kwargs):
|
||||||
if PY3:
|
name = namefunc(*args, **kwargs)
|
||||||
return myfunc(*args, **kwargs)
|
if name is not None and not PY3:
|
||||||
else:
|
name = name.encode()
|
||||||
return myfunc(*args, **kwargs).encode()
|
|
||||||
return inner_func
|
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):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@ -66,6 +71,7 @@ class tzutc(datetime.tzinfo):
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
|
|
||||||
class tzoffset(datetime.tzinfo):
|
class tzoffset(datetime.tzinfo):
|
||||||
|
|
||||||
def __init__(self, name, offset):
|
def __init__(self, name, offset):
|
||||||
|
@ -96,6 +102,7 @@ class tzoffset(datetime.tzinfo):
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
|
|
||||||
class tzlocal(datetime.tzinfo):
|
class tzlocal(datetime.tzinfo):
|
||||||
|
|
||||||
_std_offset = datetime.timedelta(seconds=-time.timezone)
|
_std_offset = datetime.timedelta(seconds=-time.timezone)
|
||||||
|
@ -123,25 +130,25 @@ class tzlocal(datetime.tzinfo):
|
||||||
def _isdst(self, dt):
|
def _isdst(self, dt):
|
||||||
# We can't use mktime here. It is unstable when deciding if
|
# We can't use mktime here. It is unstable when deciding if
|
||||||
# the hour near to a change is DST or not.
|
# the hour near to a change is DST or not.
|
||||||
#
|
#
|
||||||
# timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,
|
# timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,
|
||||||
# dt.minute, dt.second, dt.weekday(), 0, -1))
|
# dt.minute, dt.second, dt.weekday(), 0, -1))
|
||||||
# return time.localtime(timestamp).tm_isdst
|
# return time.localtime(timestamp).tm_isdst
|
||||||
#
|
#
|
||||||
# The code above yields the following result:
|
# The code above yields the following result:
|
||||||
#
|
#
|
||||||
#>>> import tz, datetime
|
# >>> import tz, datetime
|
||||||
#>>> t = tz.tzlocal()
|
# >>> t = tz.tzlocal()
|
||||||
#>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
||||||
#'BRDT'
|
# 'BRDT'
|
||||||
#>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
|
# >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
|
||||||
#'BRST'
|
# 'BRST'
|
||||||
#>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
||||||
#'BRST'
|
# 'BRST'
|
||||||
#>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()
|
# >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()
|
||||||
#'BRDT'
|
# 'BRDT'
|
||||||
#>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
||||||
#'BRDT'
|
# 'BRDT'
|
||||||
#
|
#
|
||||||
# Here is a more stable implementation:
|
# Here is a more stable implementation:
|
||||||
#
|
#
|
||||||
|
@ -166,6 +173,7 @@ class tzlocal(datetime.tzinfo):
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
|
|
||||||
class _ttinfo(object):
|
class _ttinfo(object):
|
||||||
__slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"]
|
__slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"]
|
||||||
|
|
||||||
|
@ -205,15 +213,20 @@ class _ttinfo(object):
|
||||||
if name in state:
|
if name in state:
|
||||||
setattr(self, name, state[name])
|
setattr(self, name, state[name])
|
||||||
|
|
||||||
|
|
||||||
class tzfile(datetime.tzinfo):
|
class tzfile(datetime.tzinfo):
|
||||||
|
|
||||||
# http://www.twinsun.com/tz/tz-link.htm
|
# http://www.twinsun.com/tz/tz-link.htm
|
||||||
# ftp://ftp.iana.org/tz/tz*.tar.gz
|
# ftp://ftp.iana.org/tz/tz*.tar.gz
|
||||||
|
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj, filename=None):
|
||||||
|
file_opened_here = False
|
||||||
if isinstance(fileobj, string_types):
|
if isinstance(fileobj, string_types):
|
||||||
self._filename = fileobj
|
self._filename = fileobj
|
||||||
fileobj = open(fileobj, 'rb')
|
fileobj = open(fileobj, 'rb')
|
||||||
|
file_opened_here = True
|
||||||
|
elif filename is not None:
|
||||||
|
self._filename = filename
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._filename = fileobj.name
|
self._filename = fileobj.name
|
||||||
else:
|
else:
|
||||||
|
@ -228,125 +241,128 @@ class tzfile(datetime.tzinfo):
|
||||||
# six four-byte values of type long, written in a
|
# six four-byte values of type long, written in a
|
||||||
# ``standard'' byte order (the high-order byte
|
# ``standard'' byte order (the high-order byte
|
||||||
# of the value is written first).
|
# of the value is written first).
|
||||||
|
try:
|
||||||
|
if fileobj.read(4).decode() != "TZif":
|
||||||
|
raise ValueError("magic not found")
|
||||||
|
|
||||||
if fileobj.read(4).decode() != "TZif":
|
fileobj.read(16)
|
||||||
raise ValueError("magic not found")
|
|
||||||
|
|
||||||
fileobj.read(16)
|
(
|
||||||
|
# The number of UTC/local indicators stored in the file.
|
||||||
|
ttisgmtcnt,
|
||||||
|
|
||||||
(
|
# The number of standard/wall indicators stored in the file.
|
||||||
# The number of UTC/local indicators stored in the file.
|
ttisstdcnt,
|
||||||
ttisgmtcnt,
|
|
||||||
|
|
||||||
# The number of standard/wall indicators stored in the file.
|
# The number of leap seconds for which data is
|
||||||
ttisstdcnt,
|
# stored in the file.
|
||||||
|
leapcnt,
|
||||||
# The number of leap seconds for which data is
|
|
||||||
# stored in the file.
|
|
||||||
leapcnt,
|
|
||||||
|
|
||||||
# The number of "transition times" for which data
|
# The number of "transition times" for which data
|
||||||
# is stored in the file.
|
# is stored in the file.
|
||||||
timecnt,
|
timecnt,
|
||||||
|
|
||||||
# The number of "local time types" for which data
|
# The number of "local time types" for which data
|
||||||
# is stored in the file (must not be zero).
|
# is stored in the file (must not be zero).
|
||||||
typecnt,
|
typecnt,
|
||||||
|
|
||||||
# The number of characters of "time zone
|
# The number of characters of "time zone
|
||||||
# abbreviation strings" stored in the file.
|
# abbreviation strings" stored in the file.
|
||||||
charcnt,
|
charcnt,
|
||||||
|
|
||||||
) = struct.unpack(">6l", fileobj.read(24))
|
) = struct.unpack(">6l", fileobj.read(24))
|
||||||
|
|
||||||
# The above header is followed by tzh_timecnt four-byte
|
# The above header is followed by tzh_timecnt four-byte
|
||||||
# values of type long, sorted in ascending order.
|
# values of type long, sorted in ascending order.
|
||||||
# These values are written in ``standard'' byte order.
|
# These values are written in ``standard'' byte order.
|
||||||
# Each is used as a transition time (as returned by
|
# Each is used as a transition time (as returned by
|
||||||
# time(2)) at which the rules for computing local time
|
# time(2)) at which the rules for computing local time
|
||||||
# change.
|
# change.
|
||||||
|
|
||||||
if timecnt:
|
if timecnt:
|
||||||
self._trans_list = struct.unpack(">%dl" % timecnt,
|
self._trans_list = struct.unpack(">%dl" % timecnt,
|
||||||
fileobj.read(timecnt*4))
|
fileobj.read(timecnt*4))
|
||||||
else:
|
else:
|
||||||
self._trans_list = []
|
self._trans_list = []
|
||||||
|
|
||||||
# Next come tzh_timecnt one-byte values of type unsigned
|
# Next come tzh_timecnt one-byte values of type unsigned
|
||||||
# char; each one tells which of the different types of
|
# char; each one tells which of the different types of
|
||||||
# ``local time'' types described in the file is associated
|
# ``local time'' types described in the file is associated
|
||||||
# with the same-indexed transition time. These values
|
# with the same-indexed transition time. These values
|
||||||
# serve as indices into an array of ttinfo structures that
|
# serve as indices into an array of ttinfo structures that
|
||||||
# appears next in the file.
|
# appears next in the file.
|
||||||
|
|
||||||
if timecnt:
|
|
||||||
self._trans_idx = struct.unpack(">%dB" % timecnt,
|
|
||||||
fileobj.read(timecnt))
|
|
||||||
else:
|
|
||||||
self._trans_idx = []
|
|
||||||
|
|
||||||
# Each ttinfo structure is written as a four-byte value
|
|
||||||
# for tt_gmtoff of type long, in a standard byte
|
|
||||||
# order, followed by a one-byte value for tt_isdst
|
|
||||||
# and a one-byte value for tt_abbrind. In each
|
|
||||||
# structure, tt_gmtoff gives the number of
|
|
||||||
# seconds to be added to UTC, tt_isdst tells whether
|
|
||||||
# tm_isdst should be set by localtime(3), and
|
|
||||||
# tt_abbrind serves as an index into the array of
|
|
||||||
# time zone abbreviation characters that follow the
|
|
||||||
# ttinfo structure(s) in the file.
|
|
||||||
|
|
||||||
ttinfo = []
|
if timecnt:
|
||||||
|
self._trans_idx = struct.unpack(">%dB" % timecnt,
|
||||||
|
fileobj.read(timecnt))
|
||||||
|
else:
|
||||||
|
self._trans_idx = []
|
||||||
|
|
||||||
for i in range(typecnt):
|
# Each ttinfo structure is written as a four-byte value
|
||||||
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
# for tt_gmtoff of type long, in a standard byte
|
||||||
|
# order, followed by a one-byte value for tt_isdst
|
||||||
|
# and a one-byte value for tt_abbrind. In each
|
||||||
|
# structure, tt_gmtoff gives the number of
|
||||||
|
# seconds to be added to UTC, tt_isdst tells whether
|
||||||
|
# tm_isdst should be set by localtime(3), and
|
||||||
|
# tt_abbrind serves as an index into the array of
|
||||||
|
# time zone abbreviation characters that follow the
|
||||||
|
# ttinfo structure(s) in the file.
|
||||||
|
|
||||||
abbr = fileobj.read(charcnt).decode()
|
ttinfo = []
|
||||||
|
|
||||||
# Then there are tzh_leapcnt pairs of four-byte
|
for i in range(typecnt):
|
||||||
# values, written in standard byte order; the
|
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
||||||
# first value of each pair gives the time (as
|
|
||||||
# returned by time(2)) at which a leap second
|
|
||||||
# occurs; the second gives the total number of
|
|
||||||
# leap seconds to be applied after the given time.
|
|
||||||
# The pairs of values are sorted in ascending order
|
|
||||||
# by time.
|
|
||||||
|
|
||||||
# Not used, for now
|
abbr = fileobj.read(charcnt).decode()
|
||||||
if leapcnt:
|
|
||||||
leap = struct.unpack(">%dl" % (leapcnt*2),
|
|
||||||
fileobj.read(leapcnt*8))
|
|
||||||
|
|
||||||
# Then there are tzh_ttisstdcnt standard/wall
|
# Then there are tzh_leapcnt pairs of four-byte
|
||||||
# indicators, each stored as a one-byte value;
|
# values, written in standard byte order; the
|
||||||
# they tell whether the transition times associated
|
# first value of each pair gives the time (as
|
||||||
# with local time types were specified as standard
|
# returned by time(2)) at which a leap second
|
||||||
# time or wall clock time, and are used when
|
# occurs; the second gives the total number of
|
||||||
# a time zone file is used in handling POSIX-style
|
# leap seconds to be applied after the given time.
|
||||||
# time zone environment variables.
|
# The pairs of values are sorted in ascending order
|
||||||
|
# by time.
|
||||||
|
|
||||||
if ttisstdcnt:
|
# Not used, for now
|
||||||
isstd = struct.unpack(">%db" % ttisstdcnt,
|
# if leapcnt:
|
||||||
fileobj.read(ttisstdcnt))
|
# leap = struct.unpack(">%dl" % (leapcnt*2),
|
||||||
|
# fileobj.read(leapcnt*8))
|
||||||
|
|
||||||
# Finally, there are tzh_ttisgmtcnt UTC/local
|
# Then there are tzh_ttisstdcnt standard/wall
|
||||||
# indicators, each stored as a one-byte value;
|
# indicators, each stored as a one-byte value;
|
||||||
# they tell whether the transition times associated
|
# they tell whether the transition times associated
|
||||||
# with local time types were specified as UTC or
|
# with local time types were specified as standard
|
||||||
# local time, and are used when a time zone file
|
# time or wall clock time, and are used when
|
||||||
# is used in handling POSIX-style time zone envi-
|
# a time zone file is used in handling POSIX-style
|
||||||
# ronment variables.
|
# time zone environment variables.
|
||||||
|
|
||||||
if ttisgmtcnt:
|
if ttisstdcnt:
|
||||||
isgmt = struct.unpack(">%db" % ttisgmtcnt,
|
isstd = struct.unpack(">%db" % ttisstdcnt,
|
||||||
fileobj.read(ttisgmtcnt))
|
fileobj.read(ttisstdcnt))
|
||||||
|
|
||||||
# ** Everything has been read **
|
# Finally, there are tzh_ttisgmtcnt UTC/local
|
||||||
|
# indicators, each stored as a one-byte value;
|
||||||
|
# they tell whether the transition times associated
|
||||||
|
# with local time types were specified as UTC or
|
||||||
|
# local time, and are used when a time zone file
|
||||||
|
# is used in handling POSIX-style time zone envi-
|
||||||
|
# ronment variables.
|
||||||
|
|
||||||
|
if ttisgmtcnt:
|
||||||
|
isgmt = struct.unpack(">%db" % ttisgmtcnt,
|
||||||
|
fileobj.read(ttisgmtcnt))
|
||||||
|
|
||||||
|
# ** Everything has been read **
|
||||||
|
finally:
|
||||||
|
if file_opened_here:
|
||||||
|
fileobj.close()
|
||||||
|
|
||||||
# Build ttinfo list
|
# Build ttinfo list
|
||||||
self._ttinfo_list = []
|
self._ttinfo_list = []
|
||||||
for i in range(typecnt):
|
for i in range(typecnt):
|
||||||
gmtoff, isdst, abbrind = ttinfo[i]
|
gmtoff, isdst, abbrind = ttinfo[i]
|
||||||
# Round to full-minutes if that's not the case. Python's
|
# Round to full-minutes if that's not the case. Python's
|
||||||
# datetime doesn't accept sub-minute timezones. Check
|
# datetime doesn't accept sub-minute timezones. Check
|
||||||
# http://python.org/sf/1447945 for some information.
|
# http://python.org/sf/1447945 for some information.
|
||||||
|
@ -464,7 +480,7 @@ class tzfile(datetime.tzinfo):
|
||||||
# However, this class stores historical changes in the
|
# However, this class stores historical changes in the
|
||||||
# dst offset, so I belive that this wouldn't be the right
|
# dst offset, so I belive that this wouldn't be the right
|
||||||
# way to implement this.
|
# way to implement this.
|
||||||
|
|
||||||
@tzname_in_python2
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if not self._ttinfo_std:
|
if not self._ttinfo_std:
|
||||||
|
@ -481,7 +497,6 @@ class tzfile(datetime.tzinfo):
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
|
return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
|
||||||
|
|
||||||
|
@ -490,8 +505,8 @@ class tzfile(datetime.tzinfo):
|
||||||
raise ValueError("Unpickable %s class" % self.__class__.__name__)
|
raise ValueError("Unpickable %s class" % self.__class__.__name__)
|
||||||
return (self.__class__, (self._filename,))
|
return (self.__class__, (self._filename,))
|
||||||
|
|
||||||
class tzrange(datetime.tzinfo):
|
|
||||||
|
|
||||||
|
class tzrange(datetime.tzinfo):
|
||||||
def __init__(self, stdabbr, stdoffset=None,
|
def __init__(self, stdabbr, stdoffset=None,
|
||||||
dstabbr=None, dstoffset=None,
|
dstabbr=None, dstoffset=None,
|
||||||
start=None, end=None):
|
start=None, end=None):
|
||||||
|
@ -512,12 +527,12 @@ class tzrange(datetime.tzinfo):
|
||||||
self._dst_offset = ZERO
|
self._dst_offset = ZERO
|
||||||
if dstabbr and start is None:
|
if dstabbr and start is None:
|
||||||
self._start_delta = relativedelta.relativedelta(
|
self._start_delta = relativedelta.relativedelta(
|
||||||
hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
|
hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
|
||||||
else:
|
else:
|
||||||
self._start_delta = start
|
self._start_delta = start
|
||||||
if dstabbr and end is None:
|
if dstabbr and end is None:
|
||||||
self._end_delta = relativedelta.relativedelta(
|
self._end_delta = relativedelta.relativedelta(
|
||||||
hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
|
hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
|
||||||
else:
|
else:
|
||||||
self._end_delta = end
|
self._end_delta = end
|
||||||
|
|
||||||
|
@ -570,8 +585,9 @@ class tzrange(datetime.tzinfo):
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
|
|
||||||
class tzstr(tzrange):
|
class tzstr(tzrange):
|
||||||
|
|
||||||
def __init__(self, s):
|
def __init__(self, s):
|
||||||
global parser
|
global parser
|
||||||
if not parser:
|
if not parser:
|
||||||
|
@ -645,9 +661,10 @@ class tzstr(tzrange):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
||||||
|
|
||||||
|
|
||||||
class _tzicalvtzcomp(object):
|
class _tzicalvtzcomp(object):
|
||||||
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
|
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
|
||||||
tzname=None, rrule=None):
|
tzname=None, rrule=None):
|
||||||
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
|
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
|
||||||
self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)
|
self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)
|
||||||
self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom
|
self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom
|
||||||
|
@ -655,6 +672,7 @@ class _tzicalvtzcomp(object):
|
||||||
self.tzname = tzname
|
self.tzname = tzname
|
||||||
self.rrule = rrule
|
self.rrule = rrule
|
||||||
|
|
||||||
|
|
||||||
class _tzicalvtz(datetime.tzinfo):
|
class _tzicalvtz(datetime.tzinfo):
|
||||||
def __init__(self, tzid, comps=[]):
|
def __init__(self, tzid, comps=[]):
|
||||||
self._tzid = tzid
|
self._tzid = tzid
|
||||||
|
@ -718,6 +736,7 @@ class _tzicalvtz(datetime.tzinfo):
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
|
|
||||||
class tzical(object):
|
class tzical(object):
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
global rrule
|
global rrule
|
||||||
|
@ -726,7 +745,8 @@ class tzical(object):
|
||||||
|
|
||||||
if isinstance(fileobj, string_types):
|
if isinstance(fileobj, string_types):
|
||||||
self._s = fileobj
|
self._s = fileobj
|
||||||
fileobj = open(fileobj, 'r') # ical should be encoded in UTF-8 with CRLF
|
# ical should be encoded in UTF-8 with CRLF
|
||||||
|
fileobj = open(fileobj, 'r')
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._s = fileobj.name
|
self._s = fileobj.name
|
||||||
else:
|
else:
|
||||||
|
@ -754,7 +774,7 @@ class tzical(object):
|
||||||
if not s:
|
if not s:
|
||||||
raise ValueError("empty offset")
|
raise ValueError("empty offset")
|
||||||
if s[0] in ('+', '-'):
|
if s[0] in ('+', '-'):
|
||||||
signal = (-1, +1)[s[0]=='+']
|
signal = (-1, +1)[s[0] == '+']
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
else:
|
else:
|
||||||
signal = +1
|
signal = +1
|
||||||
|
@ -815,7 +835,8 @@ class tzical(object):
|
||||||
if not tzid:
|
if not tzid:
|
||||||
raise ValueError("mandatory TZID not found")
|
raise ValueError("mandatory TZID not found")
|
||||||
if not comps:
|
if not comps:
|
||||||
raise ValueError("at least one component is needed")
|
raise ValueError(
|
||||||
|
"at least one component is needed")
|
||||||
# Process vtimezone
|
# Process vtimezone
|
||||||
self._vtz[tzid] = _tzicalvtz(tzid, comps)
|
self._vtz[tzid] = _tzicalvtz(tzid, comps)
|
||||||
invtz = False
|
invtz = False
|
||||||
|
@ -823,9 +844,11 @@ class tzical(object):
|
||||||
if not founddtstart:
|
if not founddtstart:
|
||||||
raise ValueError("mandatory DTSTART not found")
|
raise ValueError("mandatory DTSTART not found")
|
||||||
if tzoffsetfrom is None:
|
if tzoffsetfrom is None:
|
||||||
raise ValueError("mandatory TZOFFSETFROM not found")
|
raise ValueError(
|
||||||
|
"mandatory TZOFFSETFROM not found")
|
||||||
if tzoffsetto is None:
|
if tzoffsetto is None:
|
||||||
raise ValueError("mandatory TZOFFSETFROM not found")
|
raise ValueError(
|
||||||
|
"mandatory TZOFFSETFROM not found")
|
||||||
# Process component
|
# Process component
|
||||||
rr = None
|
rr = None
|
||||||
if rrulelines:
|
if rrulelines:
|
||||||
|
@ -848,15 +871,18 @@ class tzical(object):
|
||||||
rrulelines.append(line)
|
rrulelines.append(line)
|
||||||
elif name == "TZOFFSETFROM":
|
elif name == "TZOFFSETFROM":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError("unsupported %s parm: %s "%(name, parms[0]))
|
raise ValueError(
|
||||||
|
"unsupported %s parm: %s " % (name, parms[0]))
|
||||||
tzoffsetfrom = self._parse_offset(value)
|
tzoffsetfrom = self._parse_offset(value)
|
||||||
elif name == "TZOFFSETTO":
|
elif name == "TZOFFSETTO":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError("unsupported TZOFFSETTO parm: "+parms[0])
|
raise ValueError(
|
||||||
|
"unsupported TZOFFSETTO parm: "+parms[0])
|
||||||
tzoffsetto = self._parse_offset(value)
|
tzoffsetto = self._parse_offset(value)
|
||||||
elif name == "TZNAME":
|
elif name == "TZNAME":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError("unsupported TZNAME parm: "+parms[0])
|
raise ValueError(
|
||||||
|
"unsupported TZNAME parm: "+parms[0])
|
||||||
tzname = value
|
tzname = value
|
||||||
elif name == "COMMENT":
|
elif name == "COMMENT":
|
||||||
pass
|
pass
|
||||||
|
@ -865,7 +891,8 @@ class tzical(object):
|
||||||
else:
|
else:
|
||||||
if name == "TZID":
|
if name == "TZID":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError("unsupported TZID parm: "+parms[0])
|
raise ValueError(
|
||||||
|
"unsupported TZID parm: "+parms[0])
|
||||||
tzid = value
|
tzid = value
|
||||||
elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
|
elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
|
||||||
pass
|
pass
|
||||||
|
@ -886,6 +913,7 @@ else:
|
||||||
TZFILES = []
|
TZFILES = []
|
||||||
TZPATHS = []
|
TZPATHS = []
|
||||||
|
|
||||||
|
|
||||||
def gettz(name=None):
|
def gettz(name=None):
|
||||||
tz = None
|
tz = None
|
||||||
if not name:
|
if not name:
|
||||||
|
@ -933,11 +961,11 @@ def gettz(name=None):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
tz = None
|
tz = None
|
||||||
if tzwin:
|
if tzwin is not None:
|
||||||
try:
|
try:
|
||||||
tz = tzwin(name)
|
tz = tzwin(name)
|
||||||
except OSError:
|
except WindowsError:
|
||||||
pass
|
tz = None
|
||||||
if not tz:
|
if not tz:
|
||||||
from dateutil.zoneinfo import gettz
|
from dateutil.zoneinfo import gettz
|
||||||
tz = gettz(name)
|
tz = gettz(name)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# This code was originally contributed by Jeffrey Harris.
|
# This code was originally contributed by Jeffrey Harris.
|
||||||
import datetime
|
import datetime
|
||||||
import struct
|
import struct
|
||||||
import winreg
|
|
||||||
|
|
||||||
|
from six.moves import winreg
|
||||||
|
|
||||||
__all__ = ["tzwin", "tzwinlocal"]
|
__all__ = ["tzwin", "tzwinlocal"]
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
|
||||||
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
|
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
|
||||||
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
||||||
|
|
||||||
|
|
||||||
def _settzkeyname():
|
def _settzkeyname():
|
||||||
global TZKEYNAME
|
|
||||||
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
try:
|
try:
|
||||||
winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
||||||
|
@ -21,8 +21,10 @@ def _settzkeyname():
|
||||||
except WindowsError:
|
except WindowsError:
|
||||||
TZKEYNAME = TZKEYNAME9X
|
TZKEYNAME = TZKEYNAME9X
|
||||||
handle.Close()
|
handle.Close()
|
||||||
|
return TZKEYNAME
|
||||||
|
|
||||||
|
TZKEYNAME = _settzkeyname()
|
||||||
|
|
||||||
_settzkeyname()
|
|
||||||
|
|
||||||
class tzwinbase(datetime.tzinfo):
|
class tzwinbase(datetime.tzinfo):
|
||||||
"""tzinfo class based on win32's timezones available in the registry."""
|
"""tzinfo class based on win32's timezones available in the registry."""
|
||||||
|
@ -39,7 +41,7 @@ class tzwinbase(datetime.tzinfo):
|
||||||
return datetime.timedelta(minutes=minutes)
|
return datetime.timedelta(minutes=minutes)
|
||||||
else:
|
else:
|
||||||
return datetime.timedelta(0)
|
return datetime.timedelta(0)
|
||||||
|
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if self._isdst(dt):
|
if self._isdst(dt):
|
||||||
return self._dstname
|
return self._dstname
|
||||||
|
@ -59,8 +61,11 @@ class tzwinbase(datetime.tzinfo):
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
return self._display
|
return self._display
|
||||||
|
|
||||||
def _isdst(self, dt):
|
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,
|
dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek,
|
||||||
self._dsthour, self._dstminute,
|
self._dsthour, self._dstminute,
|
||||||
self._dstweeknumber)
|
self._dstweeknumber)
|
||||||
|
@ -78,31 +83,33 @@ class tzwin(tzwinbase):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
# multiple contexts only possible in 2.7 and 3.1, we still support 2.6
|
||||||
tzkey = winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name))
|
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
||||||
keydict = valuestodict(tzkey)
|
with winreg.OpenKey(handle,
|
||||||
tzkey.Close()
|
"%s\%s" % (TZKEYNAME, name)) as tzkey:
|
||||||
handle.Close()
|
keydict = valuestodict(tzkey)
|
||||||
|
|
||||||
self._stdname = keydict["Std"].encode("iso-8859-1")
|
self._stdname = keydict["Std"].encode("iso-8859-1")
|
||||||
self._dstname = keydict["Dlt"].encode("iso-8859-1")
|
self._dstname = keydict["Dlt"].encode("iso-8859-1")
|
||||||
|
|
||||||
self._display = keydict["Display"]
|
self._display = keydict["Display"]
|
||||||
|
|
||||||
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
||||||
tup = struct.unpack("=3l16h", keydict["TZI"])
|
tup = struct.unpack("=3l16h", keydict["TZI"])
|
||||||
self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
|
self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
|
||||||
self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -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._stdmonth,
|
||||||
self._stddayofweek, # Sunday = 0
|
self._stddayofweek, # Sunday = 0
|
||||||
self._stdweeknumber, # Last = 5
|
self._stdweeknumber, # Last = 5
|
||||||
self._stdhour,
|
self._stdhour,
|
||||||
self._stdminute) = tup[4:9]
|
self._stdminute) = tup[4:9]
|
||||||
|
|
||||||
(self._dstmonth,
|
(self._dstmonth,
|
||||||
self._dstdayofweek, # Sunday = 0
|
self._dstdayofweek, # Sunday = 0
|
||||||
self._dstweeknumber, # Last = 5
|
self._dstweeknumber, # Last = 5
|
||||||
self._dsthour,
|
self._dsthour,
|
||||||
self._dstminute) = tup[12:17]
|
self._dstminute) = tup[12:17]
|
||||||
|
|
||||||
|
@ -114,61 +121,59 @@ class tzwin(tzwinbase):
|
||||||
|
|
||||||
|
|
||||||
class tzwinlocal(tzwinbase):
|
class tzwinlocal(tzwinbase):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
||||||
|
|
||||||
tzlocalkey = winreg.OpenKey(handle, TZLOCALKEYNAME)
|
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
|
||||||
keydict = valuestodict(tzlocalkey)
|
keydict = valuestodict(tzlocalkey)
|
||||||
tzlocalkey.Close()
|
|
||||||
|
|
||||||
self._stdname = keydict["StandardName"].encode("iso-8859-1")
|
self._stdname = keydict["StandardName"].encode("iso-8859-1")
|
||||||
self._dstname = keydict["DaylightName"].encode("iso-8859-1")
|
self._dstname = keydict["DaylightName"].encode("iso-8859-1")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tzkey = winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname))
|
with winreg.OpenKey(
|
||||||
_keydict = valuestodict(tzkey)
|
handle, "%s\%s" % (TZKEYNAME, self._stdname)) as tzkey:
|
||||||
self._display = _keydict["Display"]
|
_keydict = valuestodict(tzkey)
|
||||||
tzkey.Close()
|
self._display = _keydict["Display"]
|
||||||
except OSError:
|
except OSError:
|
||||||
self._display = None
|
self._display = None
|
||||||
|
|
||||||
handle.Close()
|
|
||||||
|
|
||||||
self._stdoffset = -keydict["Bias"]-keydict["StandardBias"]
|
self._stdoffset = -keydict["Bias"]-keydict["StandardBias"]
|
||||||
self._dstoffset = self._stdoffset-keydict["DaylightBias"]
|
self._dstoffset = self._stdoffset-keydict["DaylightBias"]
|
||||||
|
|
||||||
|
|
||||||
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
||||||
tup = struct.unpack("=8h", keydict["StandardStart"])
|
tup = struct.unpack("=8h", keydict["StandardStart"])
|
||||||
|
|
||||||
(self._stdmonth,
|
(self._stdmonth,
|
||||||
self._stddayofweek, # Sunday = 0
|
self._stddayofweek, # Sunday = 0
|
||||||
self._stdweeknumber, # Last = 5
|
self._stdweeknumber, # Last = 5
|
||||||
self._stdhour,
|
self._stdhour,
|
||||||
self._stdminute) = tup[1:6]
|
self._stdminute) = tup[1:6]
|
||||||
|
|
||||||
tup = struct.unpack("=8h", keydict["DaylightStart"])
|
tup = struct.unpack("=8h", keydict["DaylightStart"])
|
||||||
|
|
||||||
(self._dstmonth,
|
(self._dstmonth,
|
||||||
self._dstdayofweek, # Sunday = 0
|
self._dstdayofweek, # Sunday = 0
|
||||||
self._dstweeknumber, # Last = 5
|
self._dstweeknumber, # Last = 5
|
||||||
self._dsthour,
|
self._dsthour,
|
||||||
self._dstminute) = tup[1:6]
|
self._dstminute) = tup[1:6]
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return (self.__class__, ())
|
return (self.__class__, ())
|
||||||
|
|
||||||
|
|
||||||
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
||||||
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
|
"""dayofweek == 0 means Sunday, whichweek 5 means last instance"""
|
||||||
first = datetime.datetime(year, month, 1, hour, minute)
|
first = datetime.datetime(year, month, 1, hour, minute)
|
||||||
weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1))
|
weekdayone = first.replace(day=((dayofweek-first.isoweekday()) % 7+1))
|
||||||
for n in range(whichweek):
|
for n in range(whichweek):
|
||||||
dt = weekdayone+(whichweek-n)*ONEWEEK
|
dt = weekdayone+(whichweek-n)*ONEWEEK
|
||||||
if dt.month == month:
|
if dt.month == month:
|
||||||
return dt
|
return dt
|
||||||
|
|
||||||
|
|
||||||
def valuestodict(key):
|
def valuestodict(key):
|
||||||
"""Convert a registry key's values to a dictionary."""
|
"""Convert a registry key's values to a dictionary."""
|
||||||
dict = {}
|
dict = {}
|
||||||
|
|
1
lib/dateutil/zoneinfo/.gitignore
vendored
1
lib/dateutil/zoneinfo/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
*.tar.gz
|
|
|
@ -1,109 +1,135 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
|
||||||
Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net>
|
|
||||||
|
|
||||||
This module offers extensions to the standard Python
|
|
||||||
datetime module.
|
|
||||||
"""
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from subprocess import call
|
import warnings
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import json
|
||||||
|
|
||||||
|
from subprocess import check_call
|
||||||
from tarfile import TarFile
|
from tarfile import TarFile
|
||||||
|
from pkgutil import get_data
|
||||||
|
from io import BytesIO
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
from dateutil.tz import tzfile
|
from dateutil.tz import tzfile
|
||||||
|
|
||||||
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
__all__ = ["gettz", "gettz_db_metadata", "rebuild"]
|
||||||
__license__ = "Simplified BSD"
|
|
||||||
|
|
||||||
__all__ = ["setcachesize", "gettz", "rebuild"]
|
_ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
|
||||||
|
_METADATA_FN = 'METADATA'
|
||||||
|
|
||||||
|
# python2.6 compatability. Note that TarFile.__exit__ != TarFile.close, but
|
||||||
|
# it's close enough for python2.6
|
||||||
|
_tar_open = TarFile.open
|
||||||
|
if not hasattr(TarFile, '__exit__'):
|
||||||
|
def _tar_open(*args, **kwargs):
|
||||||
|
return closing(TarFile.open(*args, **kwargs))
|
||||||
|
|
||||||
CACHE = []
|
|
||||||
CACHESIZE = 10
|
|
||||||
|
|
||||||
class tzfile(tzfile):
|
class tzfile(tzfile):
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return (gettz, (self._filename,))
|
return (gettz, (self._filename,))
|
||||||
|
|
||||||
def getzoneinfofile():
|
|
||||||
filenames = sorted(os.listdir(os.path.join(os.path.dirname(__file__))))
|
|
||||||
filenames.reverse()
|
|
||||||
for entry in filenames:
|
|
||||||
if entry.startswith("zoneinfo") and ".tar." in entry:
|
|
||||||
return os.path.join(os.path.dirname(__file__), entry)
|
|
||||||
return None
|
|
||||||
|
|
||||||
ZONEINFOFILE = getzoneinfofile()
|
def getzoneinfofile_stream():
|
||||||
|
try:
|
||||||
|
return BytesIO(get_data(__name__, _ZONEFILENAME))
|
||||||
|
except IOError as e: # TODO switch to FileNotFoundError?
|
||||||
|
warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror))
|
||||||
|
return None
|
||||||
|
|
||||||
del getzoneinfofile
|
|
||||||
|
|
||||||
def setcachesize(size):
|
class ZoneInfoFile(object):
|
||||||
global CACHESIZE, CACHE
|
def __init__(self, zonefile_stream=None):
|
||||||
CACHESIZE = size
|
if zonefile_stream is not None:
|
||||||
del CACHE[size:]
|
with _tar_open(fileobj=zonefile_stream, mode='r') as tf:
|
||||||
|
# dict comprehension does not work on python2.6
|
||||||
|
# TODO: get back to the nicer syntax when we ditch python2.6
|
||||||
|
# self.zones = {zf.name: tzfile(tf.extractfile(zf),
|
||||||
|
# filename = zf.name)
|
||||||
|
# for zf in tf.getmembers() if zf.isfile()}
|
||||||
|
self.zones = dict((zf.name, tzfile(tf.extractfile(zf),
|
||||||
|
filename=zf.name))
|
||||||
|
for zf in tf.getmembers()
|
||||||
|
if zf.isfile() and zf.name != _METADATA_FN)
|
||||||
|
# deal with links: They'll point to their parent object. Less
|
||||||
|
# waste of memory
|
||||||
|
# links = {zl.name: self.zones[zl.linkname]
|
||||||
|
# for zl in tf.getmembers() if zl.islnk() or zl.issym()}
|
||||||
|
links = dict((zl.name, self.zones[zl.linkname])
|
||||||
|
for zl in tf.getmembers() if
|
||||||
|
zl.islnk() or zl.issym())
|
||||||
|
self.zones.update(links)
|
||||||
|
try:
|
||||||
|
metadata_json = tf.extractfile(tf.getmember(_METADATA_FN))
|
||||||
|
metadata_str = metadata_json.read().decode('UTF-8')
|
||||||
|
self.metadata = json.loads(metadata_str)
|
||||||
|
except KeyError:
|
||||||
|
# no metadata in tar file
|
||||||
|
self.metadata = None
|
||||||
|
else:
|
||||||
|
self.zones = dict()
|
||||||
|
self.metadata = None
|
||||||
|
|
||||||
|
|
||||||
|
# The current API has gettz as a module function, although in fact it taps into
|
||||||
|
# a stateful class. So as a workaround for now, without changing the API, we
|
||||||
|
# will create a new "global" class instance the first time a user requests a
|
||||||
|
# timezone. Ugly, but adheres to the api.
|
||||||
|
#
|
||||||
|
# TODO: deprecate this.
|
||||||
|
_CLASS_ZONE_INSTANCE = list()
|
||||||
|
|
||||||
|
|
||||||
def gettz(name):
|
def gettz(name):
|
||||||
tzinfo = None
|
if len(_CLASS_ZONE_INSTANCE) == 0:
|
||||||
if ZONEINFOFILE:
|
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
||||||
for cachedname, tzinfo in CACHE:
|
return _CLASS_ZONE_INSTANCE[0].zones.get(name)
|
||||||
if cachedname == name:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
tf = TarFile.open(ZONEINFOFILE)
|
|
||||||
try:
|
|
||||||
zonefile = tf.extractfile(name)
|
|
||||||
except KeyError:
|
|
||||||
tzinfo = None
|
|
||||||
else:
|
|
||||||
tzinfo = tzfile(zonefile)
|
|
||||||
tf.close()
|
|
||||||
CACHE.insert(0, (name, tzinfo))
|
|
||||||
del CACHE[CACHESIZE:]
|
|
||||||
return tzinfo
|
|
||||||
|
|
||||||
def rebuild(filename, tag=None, format="gz"):
|
|
||||||
|
def gettz_db_metadata():
|
||||||
|
""" Get the zonefile metadata
|
||||||
|
|
||||||
|
See `zonefile_metadata`_
|
||||||
|
|
||||||
|
:returns: A dictionary with the database metadata
|
||||||
|
"""
|
||||||
|
if len(_CLASS_ZONE_INSTANCE) == 0:
|
||||||
|
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
||||||
|
return _CLASS_ZONE_INSTANCE[0].metadata
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
|
||||||
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
|
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
|
||||||
|
|
||||||
filename is the timezone tarball from ftp.iana.org/tz.
|
filename is the timezone tarball from ftp.iana.org/tz.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import tempfile, shutil
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
zonedir = os.path.join(tmpdir, "zoneinfo")
|
zonedir = os.path.join(tmpdir, "zoneinfo")
|
||||||
moduledir = os.path.dirname(__file__)
|
moduledir = os.path.dirname(__file__)
|
||||||
if tag: tag = "-"+tag
|
|
||||||
targetname = "zoneinfo%s.tar.%s" % (tag, format)
|
|
||||||
try:
|
try:
|
||||||
tf = TarFile.open(filename)
|
with _tar_open(filename) as tf:
|
||||||
# The "backwards" zone file contains links to other files, so must be
|
for name in zonegroups:
|
||||||
# processed as last
|
|
||||||
for name in sorted(tf.getnames(),
|
|
||||||
key=lambda k: k != "backward" and k or "z"):
|
|
||||||
if not (name.endswith(".sh") or
|
|
||||||
name.endswith(".tab") or
|
|
||||||
name == "leapseconds"):
|
|
||||||
tf.extract(name, tmpdir)
|
tf.extract(name, tmpdir)
|
||||||
filepath = os.path.join(tmpdir, name)
|
filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
|
||||||
try:
|
try:
|
||||||
# zic will return errors for nontz files in the package
|
check_call(["zic", "-d", zonedir] + filepaths)
|
||||||
# such as the Makefile or README, so check_call cannot
|
except OSError as e:
|
||||||
# be used (or at least extra checks would be needed)
|
if e.errno == 2:
|
||||||
call(["zic", "-d", zonedir, filepath])
|
logging.error(
|
||||||
except OSError as e:
|
"Could not find zic. Perhaps you need to install "
|
||||||
if e.errno == 2:
|
"libc-bin or some other package that provides it, "
|
||||||
logging.error(
|
"or it's not in your PATH?")
|
||||||
"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
|
raise
|
||||||
tf.close()
|
# write metadata file
|
||||||
target = os.path.join(moduledir, targetname)
|
with open(os.path.join(zonedir, _METADATA_FN), 'w') as f:
|
||||||
for entry in os.listdir(moduledir):
|
json.dump(metadata, f, indent=4, sort_keys=True)
|
||||||
if entry.startswith("zoneinfo") and ".tar." in entry:
|
target = os.path.join(moduledir, _ZONEFILENAME)
|
||||||
os.unlink(os.path.join(moduledir, entry))
|
with _tar_open(target, "w:%s" % format) as tf:
|
||||||
tf = TarFile.open(target, "w:%s" % format)
|
for entry in os.listdir(zonedir):
|
||||||
for entry in os.listdir(zonedir):
|
entrypath = os.path.join(zonedir, entry)
|
||||||
entrypath = os.path.join(zonedir, entry)
|
tf.add(entrypath, entry)
|
||||||
tf.add(entrypath, entry)
|
|
||||||
tf.close()
|
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
|
|
Loading…
Reference in a new issue