mirror of
https://github.com/moparisthebest/SickRage
synced 2024-11-15 22:05:02 -05:00
Fix for incorrect date being set inside SickRage due to date not probally being converted back to local timezone.
This commit is contained in:
parent
c1360717fd
commit
79b239bbce
@ -1,9 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
||||||
__license__ = "PSF License"
|
__license__ = "Simplified BSD"
|
||||||
__version__ = "1.5"
|
__version__ = "2.2"
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ def easter(year, method=EASTER_WESTERN):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not (1 <= method <= 3):
|
if not (1 <= method <= 3):
|
||||||
raise ValueError, "invalid method"
|
raise ValueError("invalid method")
|
||||||
|
|
||||||
# g - Golden year - 1
|
# g - Golden year - 1
|
||||||
# c - Century
|
# c - Century
|
||||||
@ -88,5 +87,5 @@ def easter(year, method=EASTER_WESTERN):
|
|||||||
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))
|
||||||
|
|
||||||
|
@ -2,25 +2,29 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
from __future__ import unicode_literals
|
||||||
__license__ = "PSF License"
|
__license__ = "Simplified BSD"
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import string
|
import string
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import collections
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from io import StringIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from StringIO import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
import relativedelta
|
from six import text_type, binary_type, integer_types
|
||||||
import tz
|
|
||||||
|
from . import relativedelta
|
||||||
|
from . import tz
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["parse", "parserinfo"]
|
__all__ = ["parse", "parserinfo"]
|
||||||
@ -39,7 +43,7 @@ __all__ = ["parse", "parserinfo"]
|
|||||||
class _timelex(object):
|
class _timelex(object):
|
||||||
|
|
||||||
def __init__(self, instream):
|
def __init__(self, instream):
|
||||||
if isinstance(instream, basestring):
|
if isinstance(instream, text_type):
|
||||||
instream = StringIO(instream)
|
instream = StringIO(instream)
|
||||||
self.instream = instream
|
self.instream = instream
|
||||||
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
|
self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
|
||||||
@ -133,12 +137,15 @@ class _timelex(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
token = self.get_token()
|
token = self.get_token()
|
||||||
if token is None:
|
if token is None:
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return self.__next__() # Python 2.x support
|
||||||
|
|
||||||
def split(cls, s):
|
def split(cls, s):
|
||||||
return list(cls(s))
|
return list(cls(s))
|
||||||
split = classmethod(split)
|
split = classmethod(split)
|
||||||
@ -155,7 +162,7 @@ class _resultbase(object):
|
|||||||
for attr in self.__slots__:
|
for attr in self.__slots__:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (classname, ", ".join(l))
|
return "%s(%s)" % (classname, ", ".join(l))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -184,7 +191,7 @@ class parserinfo(object):
|
|||||||
("Jun", "June"),
|
("Jun", "June"),
|
||||||
("Jul", "July"),
|
("Jul", "July"),
|
||||||
("Aug", "August"),
|
("Aug", "August"),
|
||||||
("Sep", "September"),
|
("Sep", "Sept", "September"),
|
||||||
("Oct", "October"),
|
("Oct", "October"),
|
||||||
("Nov", "November"),
|
("Nov", "November"),
|
||||||
("Dec", "December")]
|
("Dec", "December")]
|
||||||
@ -298,9 +305,12 @@ class parser(object):
|
|||||||
if not default:
|
if not default:
|
||||||
default = datetime.datetime.now().replace(hour=0, minute=0,
|
default = datetime.datetime.now().replace(hour=0, minute=0,
|
||||||
second=0, microsecond=0)
|
second=0, microsecond=0)
|
||||||
res = self._parse(timestr, **kwargs)
|
|
||||||
|
|
||||||
|
res, skipped_tokens = self._parse(timestr, **kwargs)
|
||||||
|
|
||||||
if res is None:
|
if res is None:
|
||||||
raise ValueError, "unknown string format"
|
raise ValueError("unknown string format")
|
||||||
repl = {}
|
repl = {}
|
||||||
for attr in ["year", "month", "day", "hour",
|
for attr in ["year", "month", "day", "hour",
|
||||||
"minute", "second", "microsecond"]:
|
"minute", "second", "microsecond"]:
|
||||||
@ -311,20 +321,20 @@ class parser(object):
|
|||||||
if res.weekday is not None and not res.day:
|
if res.weekday is not None and not res.day:
|
||||||
ret = ret+relativedelta.relativedelta(weekday=res.weekday)
|
ret = ret+relativedelta.relativedelta(weekday=res.weekday)
|
||||||
if not ignoretz:
|
if not ignoretz:
|
||||||
if callable(tzinfos) or tzinfos and res.tzname in tzinfos:
|
if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos:
|
||||||
if callable(tzinfos):
|
if isinstance(tzinfos, collections.Callable):
|
||||||
tzdata = tzinfos(res.tzname, res.tzoffset)
|
tzdata = tzinfos(res.tzname, res.tzoffset)
|
||||||
else:
|
else:
|
||||||
tzdata = tzinfos.get(res.tzname)
|
tzdata = tzinfos.get(res.tzname)
|
||||||
if isinstance(tzdata, datetime.tzinfo):
|
if isinstance(tzdata, datetime.tzinfo):
|
||||||
tzinfo = tzdata
|
tzinfo = tzdata
|
||||||
elif isinstance(tzdata, basestring):
|
elif isinstance(tzdata, text_type):
|
||||||
tzinfo = tz.tzstr(tzdata)
|
tzinfo = tz.tzstr(tzdata)
|
||||||
elif isinstance(tzdata, int):
|
elif isinstance(tzdata, integer_types):
|
||||||
tzinfo = tz.tzoffset(res.tzname, tzdata)
|
tzinfo = tz.tzoffset(res.tzname, tzdata)
|
||||||
else:
|
else:
|
||||||
raise ValueError, "offset must be tzinfo subclass, " \
|
raise ValueError("offset must be tzinfo subclass, " \
|
||||||
"tz string, or int offset"
|
"tz string, or int offset")
|
||||||
ret = ret.replace(tzinfo=tzinfo)
|
ret = ret.replace(tzinfo=tzinfo)
|
||||||
elif res.tzname and res.tzname in time.tzname:
|
elif res.tzname and res.tzname in time.tzname:
|
||||||
ret = ret.replace(tzinfo=tz.tzlocal())
|
ret = ret.replace(tzinfo=tz.tzlocal())
|
||||||
@ -332,6 +342,10 @@ class parser(object):
|
|||||||
ret = ret.replace(tzinfo=tz.tzutc())
|
ret = ret.replace(tzinfo=tz.tzutc())
|
||||||
elif res.tzoffset:
|
elif res.tzoffset:
|
||||||
ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
|
ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
|
||||||
|
|
||||||
|
if skipped_tokens:
|
||||||
|
return ret, skipped_tokens
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
class _result(_resultbase):
|
class _result(_resultbase):
|
||||||
@ -339,7 +353,10 @@ class parser(object):
|
|||||||
"hour", "minute", "second", "microsecond",
|
"hour", "minute", "second", "microsecond",
|
||||||
"tzname", "tzoffset"]
|
"tzname", "tzoffset"]
|
||||||
|
|
||||||
def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False):
|
def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False, fuzzy_with_tokens=False):
|
||||||
|
if fuzzy_with_tokens:
|
||||||
|
fuzzy = True
|
||||||
|
|
||||||
info = self.info
|
info = self.info
|
||||||
if dayfirst is None:
|
if dayfirst is None:
|
||||||
dayfirst = info.dayfirst
|
dayfirst = info.dayfirst
|
||||||
@ -347,6 +364,13 @@ class parser(object):
|
|||||||
yearfirst = info.yearfirst
|
yearfirst = info.yearfirst
|
||||||
res = self._result()
|
res = self._result()
|
||||||
l = _timelex.split(timestr)
|
l = _timelex.split(timestr)
|
||||||
|
|
||||||
|
|
||||||
|
# keep up with the last token skipped so we can recombine
|
||||||
|
# consecutively skipped tokens (-2 for when i begins at 0).
|
||||||
|
last_skipped_token_i = -2
|
||||||
|
skipped_tokens = list()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# year/month/day list
|
# year/month/day list
|
||||||
@ -441,6 +465,17 @@ class parser(object):
|
|||||||
newidx = info.hms(l[i])
|
newidx = info.hms(l[i])
|
||||||
if newidx is not None:
|
if newidx is not None:
|
||||||
idx = newidx
|
idx = newidx
|
||||||
|
elif i == len_l and l[i-2] == ' ' and info.hms(l[i-3]) is not None:
|
||||||
|
# X h MM or X m SS
|
||||||
|
idx = info.hms(l[i-3]) + 1
|
||||||
|
if idx == 1:
|
||||||
|
res.minute = int(value)
|
||||||
|
if value%1:
|
||||||
|
res.second = int(60*(value%1))
|
||||||
|
elif idx == 2:
|
||||||
|
res.second, res.microsecond = \
|
||||||
|
_parsems(value_repr)
|
||||||
|
i += 1
|
||||||
elif i+1 < len_l and l[i] == ':':
|
elif i+1 < len_l and l[i] == ':':
|
||||||
# HH:MM[:SS[.ss]]
|
# HH:MM[:SS[.ss]]
|
||||||
res.hour = int(value)
|
res.hour = int(value)
|
||||||
@ -585,7 +620,7 @@ class parser(object):
|
|||||||
|
|
||||||
# Check for a numbered timezone
|
# Check for a numbered timezone
|
||||||
if res.hour is not None and l[i] in ('+', '-'):
|
if res.hour is not None and l[i] in ('+', '-'):
|
||||||
signal = (-1,1)[l[i] == '+']
|
signal = (-1, 1)[l[i] == '+']
|
||||||
i += 1
|
i += 1
|
||||||
len_li = len(l[i])
|
len_li = len(l[i])
|
||||||
if len_li == 4:
|
if len_li == 4:
|
||||||
@ -618,6 +653,13 @@ class parser(object):
|
|||||||
if not (info.jump(l[i]) or fuzzy):
|
if not (info.jump(l[i]) or fuzzy):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if last_skipped_token_i == i - 1:
|
||||||
|
# recombine the tokens
|
||||||
|
skipped_tokens[-1] += l[i]
|
||||||
|
else:
|
||||||
|
# just append
|
||||||
|
skipped_tokens.append(l[i])
|
||||||
|
last_skipped_token_i = i
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Process year/month/day
|
# Process year/month/day
|
||||||
@ -687,10 +729,19 @@ class parser(object):
|
|||||||
|
|
||||||
if not info.validate(res):
|
if not info.validate(res):
|
||||||
return None
|
return None
|
||||||
return res
|
|
||||||
|
if fuzzy_with_tokens:
|
||||||
|
return res, tuple(skipped_tokens)
|
||||||
|
|
||||||
|
return res, None
|
||||||
|
|
||||||
DEFAULTPARSER = parser()
|
DEFAULTPARSER = parser()
|
||||||
def parse(timestr, parserinfo=None, **kwargs):
|
def parse(timestr, parserinfo=None, **kwargs):
|
||||||
|
# Python 2.x support: datetimes return their string presentation as
|
||||||
|
# bytes in 2.x and unicode in 3.x, so it's reasonable to expect that
|
||||||
|
# the parser will get both kinds. Internally we use unicode only.
|
||||||
|
if isinstance(timestr, binary_type):
|
||||||
|
timestr = timestr.decode()
|
||||||
if parserinfo:
|
if parserinfo:
|
||||||
return parser(parserinfo).parse(timestr, **kwargs)
|
return parser(parserinfo).parse(timestr, **kwargs)
|
||||||
else:
|
else:
|
||||||
@ -743,7 +794,7 @@ class _tzparser(object):
|
|||||||
if l[i] in ('+', '-'):
|
if l[i] in ('+', '-'):
|
||||||
# Yes, that's right. See the TZ variable
|
# Yes, that's right. See the TZ variable
|
||||||
# documentation.
|
# documentation.
|
||||||
signal = (1,-1)[l[i] == '+']
|
signal = (1, -1)[l[i] == '+']
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
signal = -1
|
signal = -1
|
||||||
@ -801,15 +852,15 @@ class _tzparser(object):
|
|||||||
x.time = int(l[i])
|
x.time = int(l[i])
|
||||||
i += 2
|
i += 2
|
||||||
if i < len_l:
|
if i < len_l:
|
||||||
if l[i] in ('-','+'):
|
if l[i] in ('-', '+'):
|
||||||
signal = (-1,1)[l[i] == "+"]
|
signal = (-1, 1)[l[i] == "+"]
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
signal = 1
|
signal = 1
|
||||||
res.dstoffset = (res.stdoffset+int(l[i]))*signal
|
res.dstoffset = (res.stdoffset+int(l[i]))*signal
|
||||||
elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
|
elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
|
||||||
not [y for x in l[i:] if x not in (',','/','J','M',
|
not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
|
||||||
'.','-',':')
|
'.', '-', ':')
|
||||||
for y in x if y not in "0123456789"]):
|
for y in x if y not in "0123456789"]):
|
||||||
for x in (res.start, res.end):
|
for x in (res.start, res.end):
|
||||||
if l[i] == 'J':
|
if l[i] == 'J':
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
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):
|
||||||
@ -42,7 +43,7 @@ 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:
|
class relativedelta(object):
|
||||||
"""
|
"""
|
||||||
The relativedelta type is based on the specification of the excelent
|
The relativedelta type is based on the specification of the excelent
|
||||||
work done by M.-A. Lemburg in his mx.DateTime extension. However,
|
work done by M.-A. Lemburg in his mx.DateTime extension. However,
|
||||||
@ -113,10 +114,9 @@ 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 \
|
if (not isinstance(dt1, datetime.date)) or (not isinstance(dt2, datetime.date)):
|
||||||
not 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)):
|
||||||
if type(dt1) is not type(dt2):
|
|
||||||
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):
|
||||||
@ -172,7 +172,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
self.second = second
|
self.second = second
|
||||||
self.microsecond = microsecond
|
self.microsecond = microsecond
|
||||||
|
|
||||||
if type(weekday) is int:
|
if isinstance(weekday, integer_types):
|
||||||
self.weekday = weekdays[weekday]
|
self.weekday = weekdays[weekday]
|
||||||
else:
|
else:
|
||||||
self.weekday = weekday
|
self.weekday = weekday
|
||||||
@ -185,7 +185,7 @@ 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
|
||||||
@ -195,7 +195,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
self.day = yday-ydayidx[idx-1]
|
self.day = yday-ydayidx[idx-1]
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError, "invalid year day (%d)" % yday
|
raise ValueError("invalid year day (%d)" % yday)
|
||||||
|
|
||||||
self._fix()
|
self._fix()
|
||||||
|
|
||||||
@ -242,9 +242,26 @@ Here is the behavior of operations with relativedelta:
|
|||||||
else:
|
else:
|
||||||
self.years = 0
|
self.years = 0
|
||||||
|
|
||||||
def __radd__(self, other):
|
def __add__(self, other):
|
||||||
|
if isinstance(other, relativedelta):
|
||||||
|
return relativedelta(years=other.years+self.years,
|
||||||
|
months=other.months+self.months,
|
||||||
|
days=other.days+self.days,
|
||||||
|
hours=other.hours+self.hours,
|
||||||
|
minutes=other.minutes+self.minutes,
|
||||||
|
seconds=other.seconds+self.seconds,
|
||||||
|
microseconds=other.microseconds+self.microseconds,
|
||||||
|
leapdays=other.leapdays or self.leapdays,
|
||||||
|
year=other.year or self.year,
|
||||||
|
month=other.month or self.month,
|
||||||
|
day=other.day or self.day,
|
||||||
|
weekday=other.weekday or self.weekday,
|
||||||
|
hour=other.hour or self.hour,
|
||||||
|
minute=other.minute or self.minute,
|
||||||
|
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):
|
||||||
other = datetime.datetime.fromordinal(other.toordinal())
|
other = datetime.datetime.fromordinal(other.toordinal())
|
||||||
year = (self.year or other.year)+self.years
|
year = (self.year or other.year)+self.years
|
||||||
@ -285,48 +302,31 @@ Here is the behavior of operations with relativedelta:
|
|||||||
ret += datetime.timedelta(days=jumpdays)
|
ret += datetime.timedelta(days=jumpdays)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
return self.__add__(other)
|
||||||
|
|
||||||
def __rsub__(self, other):
|
def __rsub__(self, other):
|
||||||
return self.__neg__().__radd__(other)
|
return self.__neg__().__radd__(other)
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
if not isinstance(other, relativedelta):
|
|
||||||
raise TypeError, "unsupported type for add operation"
|
|
||||||
return relativedelta(years=other.years+self.years,
|
|
||||||
months=other.months+self.months,
|
|
||||||
days=other.days+self.days,
|
|
||||||
hours=other.hours+self.hours,
|
|
||||||
minutes=other.minutes+self.minutes,
|
|
||||||
seconds=other.seconds+self.seconds,
|
|
||||||
microseconds=other.microseconds+self.microseconds,
|
|
||||||
leapdays=other.leapdays or self.leapdays,
|
|
||||||
year=other.year or self.year,
|
|
||||||
month=other.month or self.month,
|
|
||||||
day=other.day or self.day,
|
|
||||||
weekday=other.weekday or self.weekday,
|
|
||||||
hour=other.hour or self.hour,
|
|
||||||
minute=other.minute or self.minute,
|
|
||||||
second=other.second or self.second,
|
|
||||||
microsecond=other.second or self.microsecond)
|
|
||||||
|
|
||||||
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=other.years-self.years,
|
return relativedelta(years=self.years-other.years,
|
||||||
months=other.months-self.months,
|
months=self.months-other.months,
|
||||||
days=other.days-self.days,
|
days=self.days-other.days,
|
||||||
hours=other.hours-self.hours,
|
hours=self.hours-other.hours,
|
||||||
minutes=other.minutes-self.minutes,
|
minutes=self.minutes-other.minutes,
|
||||||
seconds=other.seconds-self.seconds,
|
seconds=self.seconds-other.seconds,
|
||||||
microseconds=other.microseconds-self.microseconds,
|
microseconds=self.microseconds-other.microseconds,
|
||||||
leapdays=other.leapdays or self.leapdays,
|
leapdays=self.leapdays or other.leapdays,
|
||||||
year=other.year or self.year,
|
year=self.year or other.year,
|
||||||
month=other.month or self.month,
|
month=self.month or other.month,
|
||||||
day=other.day or self.day,
|
day=self.day or other.day,
|
||||||
weekday=other.weekday or self.weekday,
|
weekday=self.weekday or other.weekday,
|
||||||
hour=other.hour or self.hour,
|
hour=self.hour or other.hour,
|
||||||
minute=other.minute or self.minute,
|
minute=self.minute or other.minute,
|
||||||
second=other.second or self.second,
|
second=self.second or other.second,
|
||||||
microsecond=other.second or self.microsecond)
|
microsecond=self.microsecond or other.microsecond)
|
||||||
|
|
||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
return relativedelta(years=-self.years,
|
return relativedelta(years=-self.years,
|
||||||
@ -346,7 +346,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
second=self.second,
|
second=self.second,
|
||||||
microsecond=self.microsecond)
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return not (not self.years and
|
return not (not self.years and
|
||||||
not self.months and
|
not self.months and
|
||||||
not self.days and
|
not self.days and
|
||||||
@ -366,13 +366,13 @@ Here is the behavior of operations with relativedelta:
|
|||||||
|
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
f = float(other)
|
f = float(other)
|
||||||
return relativedelta(years=self.years*f,
|
return relativedelta(years=int(self.years*f),
|
||||||
months=self.months*f,
|
months=int(self.months*f),
|
||||||
days=self.days*f,
|
days=int(self.days*f),
|
||||||
hours=self.hours*f,
|
hours=int(self.hours*f),
|
||||||
minutes=self.minutes*f,
|
minutes=int(self.minutes*f),
|
||||||
seconds=self.seconds*f,
|
seconds=int(self.seconds*f),
|
||||||
microseconds=self.microseconds*f,
|
microseconds=int(self.microseconds*f),
|
||||||
leapdays=self.leapdays,
|
leapdays=self.leapdays,
|
||||||
year=self.year,
|
year=self.year,
|
||||||
month=self.month,
|
month=self.month,
|
||||||
@ -383,6 +383,8 @@ Here is the behavior of operations with relativedelta:
|
|||||||
second=self.second,
|
second=self.second,
|
||||||
microsecond=self.microsecond)
|
microsecond=self.microsecond)
|
||||||
|
|
||||||
|
__rmul__ = __mul__
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, relativedelta):
|
if not isinstance(other, relativedelta):
|
||||||
return False
|
return False
|
||||||
@ -415,6 +417,8 @@ Here is the behavior of operations with relativedelta:
|
|||||||
def __div__(self, other):
|
def __div__(self, other):
|
||||||
return self.__mul__(1/float(other))
|
return self.__mul__(1/float(other))
|
||||||
|
|
||||||
|
__truediv__ = __div__
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
l = []
|
l = []
|
||||||
for attr in ["years", "months", "days", "leapdays",
|
for attr in ["years", "months", "days", "leapdays",
|
||||||
@ -426,7 +430,7 @@ Here is the behavior of operations with relativedelta:
|
|||||||
"hour", "minute", "second", "microsecond"]:
|
"hour", "minute", "second", "microsecond"]:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
||||||
|
|
||||||
# vim:ts=4:sw=4:et
|
# vim:ts=4:sw=4:et
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
import thread
|
try:
|
||||||
|
import _thread
|
||||||
|
except ImportError:
|
||||||
|
import thread as _thread
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from six import advance_iterator, integer_types
|
||||||
|
|
||||||
__all__ = ["rrule", "rruleset", "rrulestr",
|
__all__ = ["rrule", "rruleset", "rrulestr",
|
||||||
"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
|
"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
|
||||||
"HOURLY", "MINUTELY", "SECONDLY",
|
"HOURLY", "MINUTELY", "SECONDLY",
|
||||||
@ -22,15 +26,15 @@ __all__ = ["rrule", "rruleset", "rrulestr",
|
|||||||
M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+
|
M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+
|
||||||
[7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7)
|
[7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7)
|
||||||
M365MASK = list(M366MASK)
|
M365MASK = list(M366MASK)
|
||||||
M29, M30, M31 = range(1,30), range(1,31), range(1,32)
|
M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32))
|
||||||
MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
||||||
MDAY365MASK = list(MDAY366MASK)
|
MDAY365MASK = list(MDAY366MASK)
|
||||||
M29, M30, M31 = range(-29,0), range(-30,0), range(-31,0)
|
M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0))
|
||||||
NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
|
||||||
NMDAY365MASK = list(NMDAY366MASK)
|
NMDAY365MASK = list(NMDAY366MASK)
|
||||||
M366RANGE = (0,31,60,91,121,152,182,213,244,274,305,335,366)
|
M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366)
|
||||||
M365RANGE = (0,31,59,90,120,151,181,212,243,273,304,334,365)
|
M365RANGE = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
|
||||||
WDAYMASK = [0,1,2,3,4,5,6]*55
|
WDAYMASK = [0, 1, 2, 3, 4, 5, 6]*55
|
||||||
del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31]
|
del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31]
|
||||||
MDAY365MASK = tuple(MDAY365MASK)
|
MDAY365MASK = tuple(MDAY365MASK)
|
||||||
M365MASK = tuple(M365MASK)
|
M365MASK = tuple(M365MASK)
|
||||||
@ -41,7 +45,7 @@ M365MASK = tuple(M365MASK)
|
|||||||
DAILY,
|
DAILY,
|
||||||
HOURLY,
|
HOURLY,
|
||||||
MINUTELY,
|
MINUTELY,
|
||||||
SECONDLY) = range(7)
|
SECONDLY) = list(range(7))
|
||||||
|
|
||||||
# Imported on demand.
|
# Imported on demand.
|
||||||
easter = None
|
easter = None
|
||||||
@ -52,7 +56,7 @@ class weekday(object):
|
|||||||
|
|
||||||
def __init__(self, weekday, n=None):
|
def __init__(self, weekday, n=None):
|
||||||
if n == 0:
|
if n == 0:
|
||||||
raise ValueError, "Can't create weekday with n == 0"
|
raise ValueError("Can't create weekday with n == 0")
|
||||||
self.weekday = weekday
|
self.weekday = weekday
|
||||||
self.n = n
|
self.n = n
|
||||||
|
|
||||||
@ -79,11 +83,11 @@ 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 rrulebase:
|
class rrulebase(object):
|
||||||
def __init__(self, cache=False):
|
def __init__(self, cache=False):
|
||||||
if cache:
|
if cache:
|
||||||
self._cache = []
|
self._cache = []
|
||||||
self._cache_lock = thread.allocate_lock()
|
self._cache_lock = _thread.allocate_lock()
|
||||||
self._cache_gen = self._iter()
|
self._cache_gen = self._iter()
|
||||||
self._cache_complete = False
|
self._cache_complete = False
|
||||||
else:
|
else:
|
||||||
@ -112,7 +116,7 @@ class rrulebase:
|
|||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
for j in range(10):
|
for j in range(10):
|
||||||
cache.append(gen.next())
|
cache.append(advance_iterator(gen))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self._cache_gen = gen = None
|
self._cache_gen = gen = None
|
||||||
self._cache_complete = True
|
self._cache_complete = True
|
||||||
@ -133,13 +137,13 @@ class rrulebase:
|
|||||||
else:
|
else:
|
||||||
return list(itertools.islice(self,
|
return list(itertools.islice(self,
|
||||||
item.start or 0,
|
item.start or 0,
|
||||||
item.stop or sys.maxint,
|
item.stop or sys.maxsize,
|
||||||
item.step or 1))
|
item.step or 1))
|
||||||
elif item >= 0:
|
elif item >= 0:
|
||||||
gen = iter(self)
|
gen = iter(self)
|
||||||
try:
|
try:
|
||||||
for i in range(item+1):
|
for i in range(item+1):
|
||||||
res = gen.next()
|
res = advance_iterator(gen)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise IndexError
|
raise IndexError
|
||||||
return res
|
return res
|
||||||
@ -232,7 +236,7 @@ class rrule(rrulebase):
|
|||||||
byweekno=None, byweekday=None,
|
byweekno=None, byweekday=None,
|
||||||
byhour=None, byminute=None, bysecond=None,
|
byhour=None, byminute=None, bysecond=None,
|
||||||
cache=False):
|
cache=False):
|
||||||
rrulebase.__init__(self, cache)
|
super(rrule, self).__init__(cache)
|
||||||
global easter
|
global easter
|
||||||
if not dtstart:
|
if not dtstart:
|
||||||
dtstart = datetime.datetime.now().replace(microsecond=0)
|
dtstart = datetime.datetime.now().replace(microsecond=0)
|
||||||
@ -250,13 +254,13 @@ class rrule(rrulebase):
|
|||||||
self._until = until
|
self._until = until
|
||||||
if wkst is None:
|
if wkst is None:
|
||||||
self._wkst = calendar.firstweekday()
|
self._wkst = calendar.firstweekday()
|
||||||
elif type(wkst) is int:
|
elif isinstance(wkst, integer_types):
|
||||||
self._wkst = wkst
|
self._wkst = wkst
|
||||||
else:
|
else:
|
||||||
self._wkst = wkst.weekday
|
self._wkst = wkst.weekday
|
||||||
if bysetpos is None:
|
if bysetpos is None:
|
||||||
self._bysetpos = None
|
self._bysetpos = None
|
||||||
elif type(bysetpos) is int:
|
elif isinstance(bysetpos, integer_types):
|
||||||
if bysetpos == 0 or not (-366 <= bysetpos <= 366):
|
if bysetpos == 0 or not (-366 <= bysetpos <= 366):
|
||||||
raise ValueError("bysetpos must be between 1 and 366, "
|
raise ValueError("bysetpos must be between 1 and 366, "
|
||||||
"or between -366 and -1")
|
"or between -366 and -1")
|
||||||
@ -280,14 +284,14 @@ class rrule(rrulebase):
|
|||||||
# bymonth
|
# bymonth
|
||||||
if not bymonth:
|
if not bymonth:
|
||||||
self._bymonth = None
|
self._bymonth = None
|
||||||
elif type(bymonth) is int:
|
elif isinstance(bymonth, integer_types):
|
||||||
self._bymonth = (bymonth,)
|
self._bymonth = (bymonth,)
|
||||||
else:
|
else:
|
||||||
self._bymonth = tuple(bymonth)
|
self._bymonth = tuple(bymonth)
|
||||||
# byyearday
|
# byyearday
|
||||||
if not byyearday:
|
if not byyearday:
|
||||||
self._byyearday = None
|
self._byyearday = None
|
||||||
elif type(byyearday) is int:
|
elif isinstance(byyearday, integer_types):
|
||||||
self._byyearday = (byyearday,)
|
self._byyearday = (byyearday,)
|
||||||
else:
|
else:
|
||||||
self._byyearday = tuple(byyearday)
|
self._byyearday = tuple(byyearday)
|
||||||
@ -295,7 +299,7 @@ class rrule(rrulebase):
|
|||||||
if byeaster is not None:
|
if byeaster is not None:
|
||||||
if not easter:
|
if not easter:
|
||||||
from dateutil import easter
|
from dateutil import easter
|
||||||
if type(byeaster) is int:
|
if isinstance(byeaster, integer_types):
|
||||||
self._byeaster = (byeaster,)
|
self._byeaster = (byeaster,)
|
||||||
else:
|
else:
|
||||||
self._byeaster = tuple(byeaster)
|
self._byeaster = tuple(byeaster)
|
||||||
@ -305,7 +309,7 @@ class rrule(rrulebase):
|
|||||||
if not bymonthday:
|
if not bymonthday:
|
||||||
self._bymonthday = ()
|
self._bymonthday = ()
|
||||||
self._bynmonthday = ()
|
self._bynmonthday = ()
|
||||||
elif type(bymonthday) is int:
|
elif isinstance(bymonthday, integer_types):
|
||||||
if bymonthday < 0:
|
if bymonthday < 0:
|
||||||
self._bynmonthday = (bymonthday,)
|
self._bynmonthday = (bymonthday,)
|
||||||
self._bymonthday = ()
|
self._bymonthday = ()
|
||||||
@ -318,7 +322,7 @@ class rrule(rrulebase):
|
|||||||
# byweekno
|
# byweekno
|
||||||
if byweekno is None:
|
if byweekno is None:
|
||||||
self._byweekno = None
|
self._byweekno = None
|
||||||
elif type(byweekno) is int:
|
elif isinstance(byweekno, integer_types):
|
||||||
self._byweekno = (byweekno,)
|
self._byweekno = (byweekno,)
|
||||||
else:
|
else:
|
||||||
self._byweekno = tuple(byweekno)
|
self._byweekno = tuple(byweekno)
|
||||||
@ -326,7 +330,7 @@ class rrule(rrulebase):
|
|||||||
if byweekday is None:
|
if byweekday is None:
|
||||||
self._byweekday = None
|
self._byweekday = None
|
||||||
self._bynweekday = None
|
self._bynweekday = None
|
||||||
elif type(byweekday) is int:
|
elif isinstance(byweekday, integer_types):
|
||||||
self._byweekday = (byweekday,)
|
self._byweekday = (byweekday,)
|
||||||
self._bynweekday = None
|
self._bynweekday = None
|
||||||
elif hasattr(byweekday, "n"):
|
elif hasattr(byweekday, "n"):
|
||||||
@ -340,7 +344,7 @@ class rrule(rrulebase):
|
|||||||
self._byweekday = []
|
self._byweekday = []
|
||||||
self._bynweekday = []
|
self._bynweekday = []
|
||||||
for wday in byweekday:
|
for wday in byweekday:
|
||||||
if type(wday) is int:
|
if isinstance(wday, integer_types):
|
||||||
self._byweekday.append(wday)
|
self._byweekday.append(wday)
|
||||||
elif not wday.n or freq > MONTHLY:
|
elif not wday.n or freq > MONTHLY:
|
||||||
self._byweekday.append(wday.weekday)
|
self._byweekday.append(wday.weekday)
|
||||||
@ -358,7 +362,7 @@ class rrule(rrulebase):
|
|||||||
self._byhour = (dtstart.hour,)
|
self._byhour = (dtstart.hour,)
|
||||||
else:
|
else:
|
||||||
self._byhour = None
|
self._byhour = None
|
||||||
elif type(byhour) is int:
|
elif isinstance(byhour, integer_types):
|
||||||
self._byhour = (byhour,)
|
self._byhour = (byhour,)
|
||||||
else:
|
else:
|
||||||
self._byhour = tuple(byhour)
|
self._byhour = tuple(byhour)
|
||||||
@ -368,7 +372,7 @@ class rrule(rrulebase):
|
|||||||
self._byminute = (dtstart.minute,)
|
self._byminute = (dtstart.minute,)
|
||||||
else:
|
else:
|
||||||
self._byminute = None
|
self._byminute = None
|
||||||
elif type(byminute) is int:
|
elif isinstance(byminute, integer_types):
|
||||||
self._byminute = (byminute,)
|
self._byminute = (byminute,)
|
||||||
else:
|
else:
|
||||||
self._byminute = tuple(byminute)
|
self._byminute = tuple(byminute)
|
||||||
@ -378,7 +382,7 @@ class rrule(rrulebase):
|
|||||||
self._bysecond = (dtstart.second,)
|
self._bysecond = (dtstart.second,)
|
||||||
else:
|
else:
|
||||||
self._bysecond = None
|
self._bysecond = None
|
||||||
elif type(bysecond) is int:
|
elif isinstance(bysecond, integer_types):
|
||||||
self._bysecond = (bysecond,)
|
self._bysecond = (bysecond,)
|
||||||
else:
|
else:
|
||||||
self._bysecond = tuple(bysecond)
|
self._bysecond = tuple(bysecond)
|
||||||
@ -716,7 +720,7 @@ class _iterinfo(object):
|
|||||||
# days from last year's last week number in
|
# days from last year's last week number in
|
||||||
# this year.
|
# this year.
|
||||||
if -1 not in rr._byweekno:
|
if -1 not in rr._byweekno:
|
||||||
lyearweekday = datetime.date(year-1,1,1).weekday()
|
lyearweekday = datetime.date(year-1, 1, 1).weekday()
|
||||||
lno1wkst = (7-lyearweekday+rr._wkst)%7
|
lno1wkst = (7-lyearweekday+rr._wkst)%7
|
||||||
lyearlen = 365+calendar.isleap(year-1)
|
lyearlen = 365+calendar.isleap(year-1)
|
||||||
if lno1wkst >= 4:
|
if lno1wkst >= 4:
|
||||||
@ -768,7 +772,7 @@ class _iterinfo(object):
|
|||||||
self.lastmonth = month
|
self.lastmonth = month
|
||||||
|
|
||||||
def ydayset(self, year, month, day):
|
def ydayset(self, year, month, day):
|
||||||
return range(self.yearlen), 0, self.yearlen
|
return list(range(self.yearlen)), 0, self.yearlen
|
||||||
|
|
||||||
def mdayset(self, year, month, day):
|
def mdayset(self, year, month, day):
|
||||||
set = [None]*self.yearlen
|
set = [None]*self.yearlen
|
||||||
@ -823,27 +827,38 @@ class _iterinfo(object):
|
|||||||
|
|
||||||
class rruleset(rrulebase):
|
class rruleset(rrulebase):
|
||||||
|
|
||||||
class _genitem:
|
class _genitem(object):
|
||||||
def __init__(self, genlist, gen):
|
def __init__(self, genlist, gen):
|
||||||
try:
|
try:
|
||||||
self.dt = gen()
|
self.dt = advance_iterator(gen)
|
||||||
genlist.append(self)
|
genlist.append(self)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
self.genlist = genlist
|
self.genlist = genlist
|
||||||
self.gen = gen
|
self.gen = gen
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
try:
|
try:
|
||||||
self.dt = self.gen()
|
self.dt = advance_iterator(self.gen)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self.genlist.remove(self)
|
self.genlist.remove(self)
|
||||||
|
|
||||||
def __cmp__(self, other):
|
next = __next__
|
||||||
return cmp(self.dt, other.dt)
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.dt < other.dt
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.dt > other.dt
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.dt == other.dt
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return self.dt != other.dt
|
||||||
|
|
||||||
def __init__(self, cache=False):
|
def __init__(self, cache=False):
|
||||||
rrulebase.__init__(self, cache)
|
super(rruleset, self).__init__(cache)
|
||||||
self._rrule = []
|
self._rrule = []
|
||||||
self._rdate = []
|
self._rdate = []
|
||||||
self._exrule = []
|
self._exrule = []
|
||||||
@ -864,14 +879,14 @@ class rruleset(rrulebase):
|
|||||||
def _iter(self):
|
def _iter(self):
|
||||||
rlist = []
|
rlist = []
|
||||||
self._rdate.sort()
|
self._rdate.sort()
|
||||||
self._genitem(rlist, iter(self._rdate).next)
|
self._genitem(rlist, iter(self._rdate))
|
||||||
for gen in [iter(x).next for x in self._rrule]:
|
for gen in [iter(x) for x in self._rrule]:
|
||||||
self._genitem(rlist, gen)
|
self._genitem(rlist, gen)
|
||||||
rlist.sort()
|
rlist.sort()
|
||||||
exlist = []
|
exlist = []
|
||||||
self._exdate.sort()
|
self._exdate.sort()
|
||||||
self._genitem(exlist, iter(self._exdate).next)
|
self._genitem(exlist, iter(self._exdate))
|
||||||
for gen in [iter(x).next for x in self._exrule]:
|
for gen in [iter(x) for x in self._exrule]:
|
||||||
self._genitem(exlist, gen)
|
self._genitem(exlist, gen)
|
||||||
exlist.sort()
|
exlist.sort()
|
||||||
lastdt = None
|
lastdt = None
|
||||||
@ -880,17 +895,17 @@ class rruleset(rrulebase):
|
|||||||
ritem = rlist[0]
|
ritem = rlist[0]
|
||||||
if not lastdt or lastdt != ritem.dt:
|
if not lastdt or lastdt != ritem.dt:
|
||||||
while exlist and exlist[0] < ritem:
|
while exlist and exlist[0] < ritem:
|
||||||
exlist[0].next()
|
advance_iterator(exlist[0])
|
||||||
exlist.sort()
|
exlist.sort()
|
||||||
if not exlist or ritem != exlist[0]:
|
if not exlist or ritem != exlist[0]:
|
||||||
total += 1
|
total += 1
|
||||||
yield ritem.dt
|
yield ritem.dt
|
||||||
lastdt = ritem.dt
|
lastdt = ritem.dt
|
||||||
ritem.next()
|
advance_iterator(ritem)
|
||||||
rlist.sort()
|
rlist.sort()
|
||||||
self._len = total
|
self._len = total
|
||||||
|
|
||||||
class _rrulestr:
|
class _rrulestr(object):
|
||||||
|
|
||||||
_freq_map = {"YEARLY": YEARLY,
|
_freq_map = {"YEARLY": YEARLY,
|
||||||
"MONTHLY": MONTHLY,
|
"MONTHLY": MONTHLY,
|
||||||
@ -932,7 +947,7 @@ class _rrulestr:
|
|||||||
ignoretz=kwargs.get("ignoretz"),
|
ignoretz=kwargs.get("ignoretz"),
|
||||||
tzinfos=kwargs.get("tzinfos"))
|
tzinfos=kwargs.get("tzinfos"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError, "invalid until date"
|
raise ValueError("invalid until date")
|
||||||
|
|
||||||
def _handle_WKST(self, rrkwargs, name, value, **kwargs):
|
def _handle_WKST(self, rrkwargs, name, value, **kwargs):
|
||||||
rrkwargs["wkst"] = self._weekday_map[value]
|
rrkwargs["wkst"] = self._weekday_map[value]
|
||||||
@ -959,7 +974,7 @@ class _rrulestr:
|
|||||||
if line.find(':') != -1:
|
if line.find(':') != -1:
|
||||||
name, value = line.split(':')
|
name, value = line.split(':')
|
||||||
if name != "RRULE":
|
if name != "RRULE":
|
||||||
raise ValueError, "unknown parameter name"
|
raise ValueError("unknown parameter name")
|
||||||
else:
|
else:
|
||||||
value = line
|
value = line
|
||||||
rrkwargs = {}
|
rrkwargs = {}
|
||||||
@ -972,9 +987,9 @@ class _rrulestr:
|
|||||||
ignoretz=ignoretz,
|
ignoretz=ignoretz,
|
||||||
tzinfos=tzinfos)
|
tzinfos=tzinfos)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError, "unknown parameter '%s'" % name
|
raise ValueError("unknown parameter '%s'" % name)
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
raise ValueError, "invalid '%s': %s" % (name, value)
|
raise ValueError("invalid '%s': %s" % (name, value))
|
||||||
return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
|
return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
|
||||||
|
|
||||||
def _parse_rfc(self, s,
|
def _parse_rfc(self, s,
|
||||||
@ -991,7 +1006,7 @@ class _rrulestr:
|
|||||||
unfold = True
|
unfold = True
|
||||||
s = s.upper()
|
s = s.upper()
|
||||||
if not s.strip():
|
if not s.strip():
|
||||||
raise ValueError, "empty string"
|
raise ValueError("empty string")
|
||||||
if unfold:
|
if unfold:
|
||||||
lines = s.splitlines()
|
lines = s.splitlines()
|
||||||
i = 0
|
i = 0
|
||||||
@ -1026,36 +1041,36 @@ class _rrulestr:
|
|||||||
name, value = line.split(':', 1)
|
name, value = line.split(':', 1)
|
||||||
parms = name.split(';')
|
parms = name.split(';')
|
||||||
if not parms:
|
if not parms:
|
||||||
raise ValueError, "empty property name"
|
raise ValueError("empty property name")
|
||||||
name = parms[0]
|
name = parms[0]
|
||||||
parms = parms[1:]
|
parms = parms[1:]
|
||||||
if name == "RRULE":
|
if name == "RRULE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported RRULE parm: "+parm
|
raise ValueError("unsupported RRULE parm: "+parm)
|
||||||
rrulevals.append(value)
|
rrulevals.append(value)
|
||||||
elif name == "RDATE":
|
elif name == "RDATE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
if parm != "VALUE=DATE-TIME":
|
if parm != "VALUE=DATE-TIME":
|
||||||
raise ValueError, "unsupported RDATE parm: "+parm
|
raise ValueError("unsupported RDATE parm: "+parm)
|
||||||
rdatevals.append(value)
|
rdatevals.append(value)
|
||||||
elif name == "EXRULE":
|
elif name == "EXRULE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported EXRULE parm: "+parm
|
raise ValueError("unsupported EXRULE parm: "+parm)
|
||||||
exrulevals.append(value)
|
exrulevals.append(value)
|
||||||
elif name == "EXDATE":
|
elif name == "EXDATE":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
if parm != "VALUE=DATE-TIME":
|
if parm != "VALUE=DATE-TIME":
|
||||||
raise ValueError, "unsupported RDATE parm: "+parm
|
raise ValueError("unsupported RDATE parm: "+parm)
|
||||||
exdatevals.append(value)
|
exdatevals.append(value)
|
||||||
elif name == "DTSTART":
|
elif name == "DTSTART":
|
||||||
for parm in parms:
|
for parm in parms:
|
||||||
raise ValueError, "unsupported DTSTART parm: "+parm
|
raise ValueError("unsupported DTSTART parm: "+parm)
|
||||||
if not parser:
|
if not parser:
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
dtstart = parser.parse(value, ignoretz=ignoretz,
|
dtstart = parser.parse(value, ignoretz=ignoretz,
|
||||||
tzinfos=tzinfos)
|
tzinfos=tzinfos)
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
if (forceset or len(rrulevals) > 1 or
|
if (forceset or len(rrulevals) > 1 or
|
||||||
rdatevals or exrulevals or exdatevals):
|
rdatevals or exrulevals or exdatevals):
|
||||||
if not parser and (rdatevals or exdatevals):
|
if not parser and (rdatevals or exdatevals):
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
__license__ = "Simplified BSD"
|
||||||
__license__ = "PSF License"
|
|
||||||
|
from six import string_types, PY3
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import struct
|
import struct
|
||||||
@ -25,6 +26,19 @@ try:
|
|||||||
except (ImportError, OSError):
|
except (ImportError, OSError):
|
||||||
tzwin, tzwinlocal = None, None
|
tzwin, tzwinlocal = None, None
|
||||||
|
|
||||||
|
def tzname_in_python2(myfunc):
|
||||||
|
"""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 inner_func(*args, **kwargs):
|
||||||
|
if PY3:
|
||||||
|
return myfunc(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
return myfunc(*args, **kwargs).encode()
|
||||||
|
return inner_func
|
||||||
|
|
||||||
ZERO = datetime.timedelta(0)
|
ZERO = datetime.timedelta(0)
|
||||||
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
|
EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal()
|
||||||
|
|
||||||
@ -36,6 +50,7 @@ class tzutc(datetime.tzinfo):
|
|||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return "UTC"
|
return "UTC"
|
||||||
|
|
||||||
@ -63,6 +78,7 @@ class tzoffset(datetime.tzinfo):
|
|||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@ -75,7 +91,7 @@ class tzoffset(datetime.tzinfo):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s, %s)" % (self.__class__.__name__,
|
return "%s(%s, %s)" % (self.__class__.__name__,
|
||||||
`self._name`,
|
repr(self._name),
|
||||||
self._offset.days*86400+self._offset.seconds)
|
self._offset.days*86400+self._offset.seconds)
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
@ -100,6 +116,7 @@ class tzlocal(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return time.tzname[self._isdst(dt)]
|
return time.tzname[self._isdst(dt)]
|
||||||
|
|
||||||
@ -161,7 +178,7 @@ class _ttinfo(object):
|
|||||||
for attr in self.__slots__:
|
for attr in self.__slots__:
|
||||||
value = getattr(self, attr)
|
value = getattr(self, attr)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
l.append("%s=%s" % (attr, `value`))
|
l.append("%s=%s" % (attr, repr(value)))
|
||||||
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@ -191,16 +208,16 @@ class _ttinfo(object):
|
|||||||
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://elsie.nci.nih.gov/pub/tz*.tar.gz
|
# ftp://ftp.iana.org/tz/tz*.tar.gz
|
||||||
|
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
if isinstance(fileobj, basestring):
|
if isinstance(fileobj, string_types):
|
||||||
self._filename = fileobj
|
self._filename = fileobj
|
||||||
fileobj = open(fileobj)
|
fileobj = open(fileobj, 'rb')
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._filename = fileobj.name
|
self._filename = fileobj.name
|
||||||
else:
|
else:
|
||||||
self._filename = `fileobj`
|
self._filename = repr(fileobj)
|
||||||
|
|
||||||
# From tzfile(5):
|
# From tzfile(5):
|
||||||
#
|
#
|
||||||
@ -212,8 +229,8 @@ class tzfile(datetime.tzinfo):
|
|||||||
# ``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).
|
||||||
|
|
||||||
if fileobj.read(4) != "TZif":
|
if fileobj.read(4).decode() != "TZif":
|
||||||
raise ValueError, "magic not found"
|
raise ValueError("magic not found")
|
||||||
|
|
||||||
fileobj.read(16)
|
fileobj.read(16)
|
||||||
|
|
||||||
@ -284,7 +301,7 @@ class tzfile(datetime.tzinfo):
|
|||||||
for i in range(typecnt):
|
for i in range(typecnt):
|
||||||
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
||||||
|
|
||||||
abbr = fileobj.read(charcnt)
|
abbr = fileobj.read(charcnt).decode()
|
||||||
|
|
||||||
# Then there are tzh_leapcnt pairs of four-byte
|
# Then there are tzh_leapcnt pairs of four-byte
|
||||||
# values, written in standard byte order; the
|
# values, written in standard byte order; the
|
||||||
@ -360,7 +377,7 @@ class tzfile(datetime.tzinfo):
|
|||||||
if not self._trans_list:
|
if not self._trans_list:
|
||||||
self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0]
|
self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0]
|
||||||
else:
|
else:
|
||||||
for i in range(timecnt-1,-1,-1):
|
for i in range(timecnt-1, -1, -1):
|
||||||
tti = self._trans_idx[i]
|
tti = self._trans_idx[i]
|
||||||
if not self._ttinfo_std and not tti.isdst:
|
if not self._ttinfo_std and not tti.isdst:
|
||||||
self._ttinfo_std = tti
|
self._ttinfo_std = tti
|
||||||
@ -448,6 +465,7 @@ class tzfile(datetime.tzinfo):
|
|||||||
# 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
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if not self._ttinfo_std:
|
if not self._ttinfo_std:
|
||||||
return None
|
return None
|
||||||
@ -465,11 +483,11 @@ class tzfile(datetime.tzinfo):
|
|||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._filename`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
if not os.path.isfile(self._filename):
|
if not os.path.isfile(self._filename):
|
||||||
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):
|
||||||
@ -515,6 +533,7 @@ class tzrange(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
if self._isdst(dt):
|
if self._isdst(dt):
|
||||||
return self._dst_abbr
|
return self._dst_abbr
|
||||||
@ -524,7 +543,7 @@ class tzrange(datetime.tzinfo):
|
|||||||
def _isdst(self, dt):
|
def _isdst(self, dt):
|
||||||
if not self._start_delta:
|
if not self._start_delta:
|
||||||
return False
|
return False
|
||||||
year = datetime.datetime(dt.year,1,1)
|
year = datetime.datetime(dt.year, 1, 1)
|
||||||
start = year+self._start_delta
|
start = year+self._start_delta
|
||||||
end = year+self._end_delta
|
end = year+self._end_delta
|
||||||
dt = dt.replace(tzinfo=None)
|
dt = dt.replace(tzinfo=None)
|
||||||
@ -561,7 +580,7 @@ class tzstr(tzrange):
|
|||||||
|
|
||||||
res = parser._parsetz(s)
|
res = parser._parsetz(s)
|
||||||
if res is None:
|
if res is None:
|
||||||
raise ValueError, "unknown string format"
|
raise ValueError("unknown string format")
|
||||||
|
|
||||||
# Here we break the compatibility with the TZ variable handling.
|
# Here we break the compatibility with the TZ variable handling.
|
||||||
# GMT-3 actually *means* the timezone -3.
|
# GMT-3 actually *means* the timezone -3.
|
||||||
@ -624,9 +643,9 @@ class tzstr(tzrange):
|
|||||||
return relativedelta.relativedelta(**kwargs)
|
return relativedelta.relativedelta(**kwargs)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._s`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
||||||
|
|
||||||
class _tzicalvtzcomp:
|
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)
|
||||||
@ -690,51 +709,52 @@ class _tzicalvtz(datetime.tzinfo):
|
|||||||
else:
|
else:
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
@tzname_in_python2
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
return self._find_comp(dt).tzname
|
return self._find_comp(dt).tzname
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<tzicalvtz %s>" % `self._tzid`
|
return "<tzicalvtz %s>" % repr(self._tzid)
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
__reduce__ = object.__reduce__
|
||||||
|
|
||||||
class tzical:
|
class tzical(object):
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
global rrule
|
global rrule
|
||||||
if not rrule:
|
if not rrule:
|
||||||
from dateutil import rrule
|
from dateutil import rrule
|
||||||
|
|
||||||
if isinstance(fileobj, basestring):
|
if isinstance(fileobj, string_types):
|
||||||
self._s = fileobj
|
self._s = fileobj
|
||||||
fileobj = open(fileobj)
|
fileobj = open(fileobj, 'r') # ical should be encoded in UTF-8 with CRLF
|
||||||
elif hasattr(fileobj, "name"):
|
elif hasattr(fileobj, "name"):
|
||||||
self._s = fileobj.name
|
self._s = fileobj.name
|
||||||
else:
|
else:
|
||||||
self._s = `fileobj`
|
self._s = repr(fileobj)
|
||||||
|
|
||||||
self._vtz = {}
|
self._vtz = {}
|
||||||
|
|
||||||
self._parse_rfc(fileobj.read())
|
self._parse_rfc(fileobj.read())
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self._vtz.keys()
|
return list(self._vtz.keys())
|
||||||
|
|
||||||
def get(self, tzid=None):
|
def get(self, tzid=None):
|
||||||
if tzid is None:
|
if tzid is None:
|
||||||
keys = self._vtz.keys()
|
keys = list(self._vtz.keys())
|
||||||
if len(keys) == 0:
|
if len(keys) == 0:
|
||||||
raise ValueError, "no timezones defined"
|
raise ValueError("no timezones defined")
|
||||||
elif len(keys) > 1:
|
elif len(keys) > 1:
|
||||||
raise ValueError, "more than one timezone available"
|
raise ValueError("more than one timezone available")
|
||||||
tzid = keys[0]
|
tzid = keys[0]
|
||||||
return self._vtz.get(tzid)
|
return self._vtz.get(tzid)
|
||||||
|
|
||||||
def _parse_offset(self, s):
|
def _parse_offset(self, s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
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
|
||||||
@ -743,12 +763,12 @@ class tzical:
|
|||||||
elif len(s) == 6:
|
elif len(s) == 6:
|
||||||
return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal
|
return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal
|
||||||
else:
|
else:
|
||||||
raise ValueError, "invalid offset: "+s
|
raise ValueError("invalid offset: "+s)
|
||||||
|
|
||||||
def _parse_rfc(self, s):
|
def _parse_rfc(self, s):
|
||||||
lines = s.splitlines()
|
lines = s.splitlines()
|
||||||
if not lines:
|
if not lines:
|
||||||
raise ValueError, "empty string"
|
raise ValueError("empty string")
|
||||||
|
|
||||||
# Unfold
|
# Unfold
|
||||||
i = 0
|
i = 0
|
||||||
@ -772,7 +792,7 @@ class tzical:
|
|||||||
name, value = line.split(':', 1)
|
name, value = line.split(':', 1)
|
||||||
parms = name.split(';')
|
parms = name.split(';')
|
||||||
if not parms:
|
if not parms:
|
||||||
raise ValueError, "empty property name"
|
raise ValueError("empty property name")
|
||||||
name = parms[0].upper()
|
name = parms[0].upper()
|
||||||
parms = parms[1:]
|
parms = parms[1:]
|
||||||
if invtz:
|
if invtz:
|
||||||
@ -781,7 +801,7 @@ class tzical:
|
|||||||
# Process component
|
# Process component
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unknown component: "+value
|
raise ValueError("unknown component: "+value)
|
||||||
comptype = value
|
comptype = value
|
||||||
founddtstart = False
|
founddtstart = False
|
||||||
tzoffsetfrom = None
|
tzoffsetfrom = None
|
||||||
@ -791,27 +811,21 @@ class tzical:
|
|||||||
elif name == "END":
|
elif name == "END":
|
||||||
if value == "VTIMEZONE":
|
if value == "VTIMEZONE":
|
||||||
if comptype:
|
if comptype:
|
||||||
raise ValueError, \
|
raise ValueError("component not closed: "+comptype)
|
||||||
"component not closed: "+comptype
|
|
||||||
if not tzid:
|
if not tzid:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZID not found")
|
||||||
"mandatory TZID not found"
|
|
||||||
if not comps:
|
if not comps:
|
||||||
raise ValueError, \
|
raise ValueError("at least one component is needed")
|
||||||
"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
|
||||||
elif value == comptype:
|
elif value == comptype:
|
||||||
if not founddtstart:
|
if not founddtstart:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory DTSTART not found")
|
||||||
"mandatory DTSTART not found"
|
|
||||||
if tzoffsetfrom is None:
|
if tzoffsetfrom is None:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZOFFSETFROM not found")
|
||||||
"mandatory TZOFFSETFROM not found"
|
|
||||||
if tzoffsetto is None:
|
if tzoffsetto is None:
|
||||||
raise ValueError, \
|
raise ValueError("mandatory TZOFFSETFROM not found")
|
||||||
"mandatory TZOFFSETFROM not found"
|
|
||||||
# Process component
|
# Process component
|
||||||
rr = None
|
rr = None
|
||||||
if rrulelines:
|
if rrulelines:
|
||||||
@ -825,8 +839,7 @@ class tzical:
|
|||||||
comps.append(comp)
|
comps.append(comp)
|
||||||
comptype = None
|
comptype = None
|
||||||
else:
|
else:
|
||||||
raise ValueError, \
|
raise ValueError("invalid component end: "+value)
|
||||||
"invalid component end: "+value
|
|
||||||
elif comptype:
|
elif comptype:
|
||||||
if name == "DTSTART":
|
if name == "DTSTART":
|
||||||
rrulelines.append(line)
|
rrulelines.append(line)
|
||||||
@ -835,40 +848,36 @@ class tzical:
|
|||||||
rrulelines.append(line)
|
rrulelines.append(line)
|
||||||
elif name == "TZOFFSETFROM":
|
elif name == "TZOFFSETFROM":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported %s parm: %s "%(name, parms[0]))
|
||||||
"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, \
|
raise ValueError("unsupported TZOFFSETTO parm: "+parms[0])
|
||||||
"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, \
|
raise ValueError("unsupported TZNAME parm: "+parms[0])
|
||||||
"unsupported TZNAME parm: "+parms[0]
|
|
||||||
tzname = value
|
tzname = value
|
||||||
elif name == "COMMENT":
|
elif name == "COMMENT":
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
else:
|
else:
|
||||||
if name == "TZID":
|
if name == "TZID":
|
||||||
if parms:
|
if parms:
|
||||||
raise ValueError, \
|
raise ValueError("unsupported TZID parm: "+parms[0])
|
||||||
"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
|
||||||
else:
|
else:
|
||||||
raise ValueError, "unsupported property: "+name
|
raise ValueError("unsupported property: "+name)
|
||||||
elif name == "BEGIN" and value == "VTIMEZONE":
|
elif name == "BEGIN" and value == "VTIMEZONE":
|
||||||
tzid = None
|
tzid = None
|
||||||
comps = []
|
comps = []
|
||||||
invtz = True
|
invtz = True
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (self.__class__.__name__, `self._s`)
|
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
||||||
|
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
TZFILES = ["/etc/localtime", "localtime"]
|
TZFILES = ["/etc/localtime", "localtime"]
|
||||||
@ -914,7 +923,7 @@ def gettz(name=None):
|
|||||||
for path in TZPATHS:
|
for path in TZPATHS:
|
||||||
filepath = os.path.join(path, name)
|
filepath = os.path.join(path, name)
|
||||||
if not os.path.isfile(filepath):
|
if not os.path.isfile(filepath):
|
||||||
filepath = filepath.replace(' ','_')
|
filepath = filepath.replace(' ', '_')
|
||||||
if not os.path.isfile(filepath):
|
if not os.path.isfile(filepath):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
@ -930,7 +939,7 @@ def gettz(name=None):
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
if not tz:
|
if not tz:
|
||||||
from lib.dateutil.zoneinfo import gettz
|
from dateutil.zoneinfo import gettz
|
||||||
tz = gettz(name)
|
tz = gettz(name)
|
||||||
if not tz:
|
if not tz:
|
||||||
for c in name:
|
for c in name:
|
||||||
|
@ -1,9 +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
|
import winreg
|
||||||
|
|
||||||
__author__ = "Jeffrey Harris & Gustavo Niemeyer <gustavo@niemeyer.net>"
|
|
||||||
|
|
||||||
__all__ = ["tzwin", "tzwinlocal"]
|
__all__ = ["tzwin", "tzwinlocal"]
|
||||||
|
|
||||||
@ -15,9 +14,9 @@ TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
|||||||
|
|
||||||
def _settzkeyname():
|
def _settzkeyname():
|
||||||
global TZKEYNAME
|
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()
|
||||||
TZKEYNAME = TZKEYNAMENT
|
TZKEYNAME = TZKEYNAMENT
|
||||||
except WindowsError:
|
except WindowsError:
|
||||||
TZKEYNAME = TZKEYNAME9X
|
TZKEYNAME = TZKEYNAME9X
|
||||||
@ -49,10 +48,10 @@ class tzwinbase(datetime.tzinfo):
|
|||||||
|
|
||||||
def list():
|
def list():
|
||||||
"""Return a list of all time zones known to the system."""
|
"""Return a list of all time zones known to the system."""
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
tzkey = _winreg.OpenKey(handle, TZKEYNAME)
|
tzkey = winreg.OpenKey(handle, TZKEYNAME)
|
||||||
result = [_winreg.EnumKey(tzkey, i)
|
result = [winreg.EnumKey(tzkey, i)
|
||||||
for i in range(_winreg.QueryInfoKey(tzkey)[0])]
|
for i in range(winreg.QueryInfoKey(tzkey)[0])]
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
handle.Close()
|
handle.Close()
|
||||||
return result
|
return result
|
||||||
@ -79,8 +78,8 @@ 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)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name))
|
tzkey = winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name))
|
||||||
keydict = valuestodict(tzkey)
|
keydict = valuestodict(tzkey)
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
handle.Close()
|
handle.Close()
|
||||||
@ -118,9 +117,9 @@ class tzwinlocal(tzwinbase):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
||||||
|
|
||||||
tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME)
|
tzlocalkey = winreg.OpenKey(handle, TZLOCALKEYNAME)
|
||||||
keydict = valuestodict(tzlocalkey)
|
keydict = valuestodict(tzlocalkey)
|
||||||
tzlocalkey.Close()
|
tzlocalkey.Close()
|
||||||
|
|
||||||
@ -128,7 +127,7 @@ class tzwinlocal(tzwinbase):
|
|||||||
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))
|
tzkey = winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname))
|
||||||
_keydict = valuestodict(tzkey)
|
_keydict = valuestodict(tzkey)
|
||||||
self._display = _keydict["Display"]
|
self._display = _keydict["Display"]
|
||||||
tzkey.Close()
|
tzkey.Close()
|
||||||
@ -165,7 +164,7 @@ 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 xrange(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
|
||||||
@ -173,8 +172,8 @@ def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
|||||||
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 = {}
|
||||||
size = _winreg.QueryInfoKey(key)[1]
|
size = winreg.QueryInfoKey(key)[1]
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
data = _winreg.EnumValue(key, i)
|
data = winreg.EnumValue(key, i)
|
||||||
dict[data[0]] = data[1]
|
dict[data[0]] = data[1]
|
||||||
return dict
|
return dict
|
||||||
|
1
lib/dateutil/zoneinfo/.gitignore
vendored
1
lib/dateutil/zoneinfo/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
*.tar.gz
|
|
@ -1,15 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net>
|
Copyright (c) 2003-2005 Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
This module offers extensions to the standard python 2.3+
|
This module offers extensions to the standard Python
|
||||||
datetime module.
|
datetime module.
|
||||||
"""
|
"""
|
||||||
from lib.dateutil.tz import tzfile
|
import logging
|
||||||
from tarfile import TarFile
|
|
||||||
import os
|
import os
|
||||||
|
from subprocess import call
|
||||||
|
from tarfile import TarFile
|
||||||
|
|
||||||
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
|
from dateutil.tz import tzfile
|
||||||
__license__ = "PSF License"
|
|
||||||
|
__author__ = "Tomi Pieviläinen <tomi.pievilainen@iki.fi>"
|
||||||
|
__license__ = "Simplified BSD"
|
||||||
|
|
||||||
__all__ = ["setcachesize", "gettz", "rebuild"]
|
__all__ = ["setcachesize", "gettz", "rebuild"]
|
||||||
|
|
||||||
@ -21,8 +25,7 @@ class tzfile(tzfile):
|
|||||||
return (gettz, (self._filename,))
|
return (gettz, (self._filename,))
|
||||||
|
|
||||||
def getzoneinfofile():
|
def getzoneinfofile():
|
||||||
filenames = os.listdir(os.path.join(os.path.dirname(__file__)))
|
filenames = sorted(os.listdir(os.path.join(os.path.dirname(__file__))))
|
||||||
filenames.sort()
|
|
||||||
filenames.reverse()
|
filenames.reverse()
|
||||||
for entry in filenames:
|
for entry in filenames:
|
||||||
if entry.startswith("zoneinfo") and ".tar." in entry:
|
if entry.startswith("zoneinfo") and ".tar." in entry:
|
||||||
@ -58,6 +61,11 @@ def gettz(name):
|
|||||||
return tzinfo
|
return tzinfo
|
||||||
|
|
||||||
def rebuild(filename, tag=None, format="gz"):
|
def rebuild(filename, tag=None, format="gz"):
|
||||||
|
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
|
||||||
|
|
||||||
|
filename is the timezone tarball from ftp.iana.org/tz.
|
||||||
|
|
||||||
|
"""
|
||||||
import tempfile, shutil
|
import tempfile, shutil
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
zonedir = os.path.join(tmpdir, "zoneinfo")
|
zonedir = os.path.join(tmpdir, "zoneinfo")
|
||||||
@ -66,13 +74,27 @@ def rebuild(filename, tag=None, format="gz"):
|
|||||||
targetname = "zoneinfo%s.tar.%s" % (tag, format)
|
targetname = "zoneinfo%s.tar.%s" % (tag, format)
|
||||||
try:
|
try:
|
||||||
tf = TarFile.open(filename)
|
tf = TarFile.open(filename)
|
||||||
for name in tf.getnames():
|
# The "backwards" zone file contains links to other files, so must be
|
||||||
|
# processed as last
|
||||||
|
for name in sorted(tf.getnames(),
|
||||||
|
key=lambda k: k != "backward" and k or "z"):
|
||||||
if not (name.endswith(".sh") or
|
if not (name.endswith(".sh") or
|
||||||
name.endswith(".tab") or
|
name.endswith(".tab") or
|
||||||
name == "leapseconds"):
|
name == "leapseconds"):
|
||||||
tf.extract(name, tmpdir)
|
tf.extract(name, tmpdir)
|
||||||
filepath = os.path.join(tmpdir, name)
|
filepath = os.path.join(tmpdir, name)
|
||||||
os.system("zic -d %s %s" % (zonedir, filepath))
|
try:
|
||||||
|
# zic will return errors for nontz files in the package
|
||||||
|
# such as the Makefile or README, so check_call cannot
|
||||||
|
# be used (or at least extra checks would be needed)
|
||||||
|
call(["zic", "-d", zonedir, filepath])
|
||||||
|
except OSError as e:
|
||||||
|
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?")
|
||||||
|
raise
|
||||||
tf.close()
|
tf.close()
|
||||||
target = os.path.join(moduledir, targetname)
|
target = os.path.join(moduledir, targetname)
|
||||||
for entry in os.listdir(moduledir):
|
for entry in os.listdir(moduledir):
|
||||||
|
@ -261,7 +261,7 @@ def parse_date_time(d, t, network):
|
|||||||
foreign_timezone = get_network_timezone(network, network_dict)
|
foreign_timezone = get_network_timezone(network, network_dict)
|
||||||
foreign_naive = datetime.datetime(te.year, te.month, te.day, hr, m, tzinfo=foreign_timezone)
|
foreign_naive = datetime.datetime(te.year, te.month, te.day, hr, m, tzinfo=foreign_timezone)
|
||||||
try:
|
try:
|
||||||
return foreign_naive.astimezone(sb_timezone)
|
return foreign_naive.replace(tzinfo=sb_timezone).astimezone(sb_timezone)
|
||||||
except (ValueError):
|
except (ValueError):
|
||||||
return foreign_naive
|
return foreign_naive
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user