Codebase list isodate / c0d611c
Import Upstream version 0.6.0 Sandro Tosi 4 years ago
23 changed file(s) with 224 addition(s) and 148 deletion(s). Raw diff Collapse all Expand all
00
11 CHANGES
22 =======
3
4 0.6.0 (2017-10-13)
5 ------------------
6
7 - support incomplete month date (Fabien Loffredo)
8 - rely on duck typing when doing duration maths
9 - support ':' as separator in fractional time zones (usrenmae)
10
311
412 0.5.4 (2015-08-06)
513 ------------------
00 Metadata-Version: 1.1
11 Name: isodate
2 Version: 0.5.4
2 Version: 0.6.0
33 Summary: An ISO 8601 date/time/duration parser and formatter
4 Home-page: http://cheeseshop.python.org/pypi/isodate
4 Home-page: https://github.com/gweis/isodate/
55 Author: Gerhard Weis
66 Author-email: gerhard.weis@proclos.com
77 License: BSD
1515 .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master
1616 :target: https://coveralls.io/r/gweis/isodate?branch=master
1717 :alt: Coveralls
18 .. image:: https://pypip.in/version/isodate/badge.svg
19 :target: https://pypi.python.org/pypi/isodate/
18 .. image:: https://img.shields.io/pypi/v/isodate.svg
19 :target: https://pypi.python.org/pypi/isodate/
2020 :alt: Latest Version
21 .. image:: https://pypip.in/download/isodate/badge.svg
22 :target: https://pypi.python.org/pypi/isodate/
23 :alt: Downloads
24 .. image:: https://pypip.in/license/isodate/badge.svg
25 :target: https://pypi.python.org/pypi/isodate/
21 .. image:: https://img.shields.io/pypi/l/isodate.svg
22 :target: https://pypi.python.org/pypi/isodate/
2623 :alt: License
2724
2825
120117 The doc strings and unit tests should provide rather detailed information about
121118 the methods and their limitations.
122119
123 The source release provides a *setup.py* script and a *buildout.cfg*. Both can
124 be used to run the unit tests included.
120 The source release provides a *setup.py* script,
121 which can be used to run the unit tests included.
125122
126123 Source code is available at `<http://github.com/gweis/isodate>`_.
127124
128125 CHANGES
129126 =======
127
128 0.6.0 (2017-10-13)
129 ------------------
130
131 - support incomplete month date (Fabien Loffredo)
132 - rely on duck typing when doing duration maths
133 - support ':' as separator in fractional time zones (usrenmae)
134
130135
131136 0.5.4 (2015-08-06)
132137 ------------------
264269 Classifier: Programming Language :: Python
265270 Classifier: Programming Language :: Python :: 2.6
266271 Classifier: Programming Language :: Python :: 2.7
267 Classifier: Programming Language :: Python :: 3.2
268272 Classifier: Programming Language :: Python :: 3.3
269273 Classifier: Programming Language :: Python :: 3.4
274 Classifier: Programming Language :: Python :: 3.5
275 Classifier: Programming Language :: Python :: 3.6
270276 Classifier: Programming Language :: Python :: Implementation :: PyPy
271277 Classifier: Topic :: Internet
272278 Classifier: Topic :: Software Development :: Libraries :: Python Modules
77 .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master
88 :target: https://coveralls.io/r/gweis/isodate?branch=master
99 :alt: Coveralls
10 .. image:: https://pypip.in/version/isodate/badge.svg
11 :target: https://pypi.python.org/pypi/isodate/
10 .. image:: https://img.shields.io/pypi/v/isodate.svg
11 :target: https://pypi.python.org/pypi/isodate/
1212 :alt: Latest Version
13 .. image:: https://pypip.in/download/isodate/badge.svg
14 :target: https://pypi.python.org/pypi/isodate/
15 :alt: Downloads
16 .. image:: https://pypip.in/license/isodate/badge.svg
17 :target: https://pypi.python.org/pypi/isodate/
13 .. image:: https://img.shields.io/pypi/l/isodate.svg
14 :target: https://pypi.python.org/pypi/isodate/
1815 :alt: License
1916
2017
112109 The doc strings and unit tests should provide rather detailed information about
113110 the methods and their limitations.
114111
115 The source release provides a *setup.py* script and a *buildout.cfg*. Both can
116 be used to run the unit tests included.
112 The source release provides a *setup.py* script,
113 which can be used to run the unit tests included.
117114
118115 Source code is available at `<http://github.com/gweis/isodate>`_.
0 [bdist_wheel]
1 universal = 1
2
03 [egg_info]
14 tag_build =
2 tag_svn_revision = 0
35 tag_date = 0
46
2525 # CONTRACT, STRICT LIABILITY, OR TORT
2626 ##############################################################################
2727 import os
28 import sys
29
30 setupargs = {}
31
32 try:
33 from setuptools import setup
34 setupargs['test_suite'] = 'isodate.tests.test_suite'
35 if sys.version[0] == '3':
36 setupargs['use_2to3'] = True
37 except ImportError:
38 from distutils.core import setup
39 if sys.version[0] == '3':
40 from distutils.command.build_py import build_py_2to3
41 setupargs['cmdclass'] = {'build_py': build_py_2to3}
28 from setuptools import setup
4229
4330
4431 def read(*rnames):
4532 return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
4633
34
4735 setup(name='isodate',
48 version='0.5.4',
36 version='0.6.0',
4937 packages=['isodate', 'isodate.tests'],
5038 package_dir={'': 'src'},
5139
5240 # dependencies:
53 # install_requires = [],
41 install_requires=[
42 'six'
43 ],
5444
5545 # PyPI metadata
5646 author='Gerhard Weis',
5848 description='An ISO 8601 date/time/duration parser and formatter',
5949 license='BSD',
6050 # keywords = '',
61 url='http://cheeseshop.python.org/pypi/isodate',
51 url='https://github.com/gweis/isodate/',
6252
6353 long_description=(read('README.rst') +
6454 read('CHANGES.txt') +
7262 'Programming Language :: Python',
7363 'Programming Language :: Python :: 2.6',
7464 'Programming Language :: Python :: 2.7',
75 'Programming Language :: Python :: 3.2',
7665 'Programming Language :: Python :: 3.3',
7766 'Programming Language :: Python :: 3.4',
67 'Programming Language :: Python :: 3.5',
68 'Programming Language :: Python :: 3.6',
7869 'Programming Language :: Python :: Implementation :: PyPy',
7970 'Topic :: Internet',
8071 ('Topic :: Software Development :'
8172 ': Libraries :: Python Modules'),
8273 ],
83 **setupargs)
74 test_suite='isodate.tests.test_suite')
4242 from isodate.isostrf import DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE
4343 from isodate.isostrf import DATE_CENTURY, DATE_EXT_COMPLETE
4444 from isodate.isostrf import DATE_EXT_ORD_COMPLETE, DATE_EXT_WEEK
45 from isodate.isostrf import DATE_EXT_WEEK_COMPLETE, DATE_MONTH, DATE_YEAR
45 from isodate.isostrf import DATE_EXT_WEEK_COMPLETE, DATE_YEAR
46 from isodate.isostrf import DATE_BAS_MONTH, DATE_EXT_MONTH
4647 from isodate.isostrf import TIME_BAS_COMPLETE, TIME_BAS_MINUTE
4748 from isodate.isostrf import TIME_EXT_COMPLETE, TIME_EXT_MINUTE
4849 from isodate.isostrf import TIME_HOUR
6061 'strftime', 'DATE_BAS_COMPLETE', 'DATE_BAS_ORD_COMPLETE',
6162 'DATE_BAS_WEEK', 'DATE_BAS_WEEK_COMPLETE', 'DATE_CENTURY',
6263 'DATE_EXT_COMPLETE', 'DATE_EXT_ORD_COMPLETE', 'DATE_EXT_WEEK',
63 'DATE_EXT_WEEK_COMPLETE', 'DATE_MONTH', 'DATE_YEAR',
64 'DATE_EXT_WEEK_COMPLETE', 'DATE_YEAR',
65 'DATE_BAS_MONTH', 'DATE_EXT_MONTH',
6466 'TIME_BAS_COMPLETE', 'TIME_BAS_MINUTE', 'TIME_EXT_COMPLETE',
6567 'TIME_EXT_MINUTE', 'TIME_HOUR', 'TZ_BAS', 'TZ_EXT', 'TZ_HOUR',
6668 'DT_BAS_COMPLETE', 'DT_EXT_COMPLETE', 'DT_BAS_ORD_COMPLETE',
2929 The class Duration allows to define durations in years and months and can be
3030 used as limited replacement for timedelta objects.
3131 '''
32 from datetime import date, datetime, timedelta
32 from datetime import timedelta
3333 from decimal import Decimal, ROUND_FLOOR
3434
3535
120120 if self.years:
121121 params.append('%d years' % self.years)
122122 if self.months:
123 params.append('%d months' % self.months)
123 fmt = "%d months"
124 if self.months <= 1:
125 fmt = "%d month"
126 params.append(fmt % self.months)
124127 params.append(str(self.tdelta))
125128 return ', '.join(params)
126129
155158 Durations can be added with Duration, timedelta, date and datetime
156159 objects.
157160 '''
158 if isinstance(other, timedelta):
159 newduration = Duration(years=self.years, months=self.months)
160 newduration.tdelta = self.tdelta + other
161 return newduration
162161 if isinstance(other, Duration):
163162 newduration = Duration(years=self.years + other.years,
164163 months=self.months + other.months)
165164 newduration.tdelta = self.tdelta + other.tdelta
166165 return newduration
167 if isinstance(other, (date, datetime)):
166 try:
167 # try anything that looks like a date or datetime
168 # 'other' has attributes year, month, day
169 # and relies on 'timedelta + other' being implemented
168170 if (not(float(self.years).is_integer() and
169171 float(self.months).is_integer())):
170172 raise ValueError('fractional years or months not supported'
178180 else:
179181 newday = other.day
180182 newdt = other.replace(year=newyear, month=newmonth, day=newday)
183 # does a timedelta + date/datetime
181184 return self.tdelta + newdt
182 raise TypeError('unsupported operand type(s) for +: %s and %s' %
183 (self.__class__, other.__class__))
184
185 def __radd__(self, other):
186 '''
187 Add durations to timedelta, date and datetime objects.
188 '''
189 if isinstance(other, timedelta):
185 except AttributeError:
186 # other probably was not a date/datetime compatible object
187 pass
188 try:
189 # try if other is a timedelta
190 # relies on timedelta + timedelta supported
190191 newduration = Duration(years=self.years, months=self.months)
191192 newduration.tdelta = self.tdelta + other
192193 return newduration
193 if isinstance(other, (date, datetime)):
194 if (not(float(self.years).is_integer() and
195 float(self.months).is_integer())):
196 raise ValueError('fractional years or months not supported'
197 ' for date calculations')
198 newmonth = other.month + self.months
199 carry, newmonth = fquotmod(newmonth, 1, 13)
200 newyear = other.year + self.years + carry
201 maxdays = max_days_in_month(newyear, newmonth)
202 if other.day > maxdays:
203 newday = maxdays
204 else:
205 newday = other.day
206 newdt = other.replace(year=newyear, month=newmonth, day=newday)
207 return newdt + self.tdelta
208 raise TypeError('unsupported operand type(s) for +: %s and %s' %
209 (other.__class__, self.__class__))
194 except AttributeError:
195 # ignore ... other probably was not a timedelta compatible object
196 pass
197 # we have tried everything .... return a NotImplemented
198 return NotImplemented
199
200 __radd__ = __add__
210201
211202 def __mul__(self, other):
212203 if isinstance(other, int):
215206 months=self.months * other)
216207 newduration.tdelta = self.tdelta * other
217208 return newduration
218 raise TypeError('unsupported operand type(s) for +: %s and %s' %
219 (self.__class__, other.__class__))
220
221 def __rmul__(self, other):
222
223 if isinstance(other, int):
224 newduration = Duration(
225 years=self.years * other,
226 months=self.months * other)
227 newduration.tdelta = self.tdelta * other
228 return newduration
229 raise TypeError('unsupported operand type(s) for +: %s and %s' %
230 (other.__class__, self.__class__))
209 return NotImplemented
210
211 __rmul__ = __mul__
231212
232213 def __sub__(self, other):
233214 '''
239220 months=self.months - other.months)
240221 newduration.tdelta = self.tdelta - other.tdelta
241222 return newduration
242 if isinstance(other, timedelta):
223 try:
224 # do maths with our timedelta object ....
243225 newduration = Duration(years=self.years, months=self.months)
244226 newduration.tdelta = self.tdelta - other
245227 return newduration
246 raise TypeError('unsupported operand type(s) for -: %s and %s' %
247 (self.__class__, other.__class__))
228 except TypeError:
229 # looks like timedelta - other is not implemented
230 pass
231 return NotImplemented
248232
249233 def __rsub__(self, other):
250234 '''
251235 It is possible to subtract Duration objecs from date, datetime and
252236 timedelta objects.
253 '''
254 # print '__rsub__:', self, other
255 if isinstance(other, (date, datetime)):
237
238 TODO: there is some weird behaviour in date - timedelta ...
239 if timedelta has seconds or microseconds set, then
240 date - timedelta != date + (-timedelta)
241 for now we follow this behaviour to avoid surprises when mixing
242 timedeltas with Durations, but in case this ever changes in
243 the stdlib we can just do:
244 return -self + other
245 instead of all the current code
246 '''
247 if isinstance(other, timedelta):
248 tmpdur = Duration()
249 tmpdur.tdelta = other
250 return tmpdur - self
251 try:
252 # check if other behaves like a date/datetime object
253 # does it have year, month, day and replace?
256254 if (not(float(self.years).is_integer() and
257255 float(self.months).is_integer())):
258256 raise ValueError('fractional years or months not supported'
267265 newday = other.day
268266 newdt = other.replace(year=newyear, month=newmonth, day=newday)
269267 return newdt - self.tdelta
270 if isinstance(other, timedelta):
271 tmpdur = Duration()
272 tmpdur.tdelta = other
273 return tmpdur - self
274 raise TypeError('unsupported operand type(s) for -: %s and %s' %
275 (other.__class__, self.__class__))
268 except AttributeError:
269 # other probably was not compatible with data/datetime
270 pass
271 return NotImplemented
276272
277273 def __eq__(self, other):
278274 '''
279275 If the years, month part and the timedelta part are both equal, then
280276 the two Durations are considered equal.
281277 '''
282 if ((isinstance(other, timedelta) and
283 self.years == 0 and self.months == 0)):
278 if isinstance(other, Duration):
279 if (((self.years * 12 + self.months) ==
280 (other.years * 12 + other.months) and
281 self.tdelta == other.tdelta)):
282 return True
283 return False
284 # check if other con be compared against timedelta object
285 # will raise an AssertionError when optimisation is off
286 if self.years == 0 and self.months == 0:
284287 return self.tdelta == other
285 if not isinstance(other, Duration):
286 return NotImplemented
287 if (((self.years * 12 + self.months) ==
288 (other.years * 12 + other.months) and
289 self.tdelta == other.tdelta)):
290 return True
291288 return False
292289
293290 def __ne__(self, other):
295292 If the years, month part or the timedelta part is not equal, then
296293 the two Durations are considered not equal.
297294 '''
298 if ((isinstance(other, timedelta) and
299 self.years == 0 and
300 self.months == 0)):
295 if isinstance(other, Duration):
296 if (((self.years * 12 + self.months) !=
297 (other.years * 12 + other.months) or
298 self.tdelta != other.tdelta)):
299 return True
300 return False
301 # check if other can be compared against timedelta object
302 # will raise an AssertionError when optimisation is off
303 if self.years == 0 and self.months == 0:
301304 return self.tdelta != other
302 if not isinstance(other, Duration):
303 return NotImplemented
304 if (((self.years * 12 + self.months) !=
305 (other.years * 12 + other.months) or
306 self.tdelta != other.tdelta)):
307 return True
308 return False
305 return True
309306
310307 def totimedelta(self, start=None, end=None):
311308 '''
107107 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
108108 r"-(?P<month>[0-9]{2})"
109109 % (sign, yeardigits)))
110 # YYYMM or +-YYYYYYMM ... basic incomplete month date format
111 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
112 r"(?P<month>[0-9]{2})"
113 % (sign, yeardigits)))
110114 # 6. year dates:
111115 # YYYY or +-YYYYYY ... reduced accuracy specific year
112116 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
121125 return DATE_REGEX_CACHE[(yeardigits, expanded)]
122126
123127
124 def parse_date(datestring, yeardigits=4, expanded=False):
128 def parse_date(
129 datestring,
130 yeardigits=4, expanded=False, defaultmonth=1, defaultday=1):
125131 '''
126132 Parse an ISO 8601 date string into a datetime.date object.
127133
142148 YYYY-DDD +-YYYYYY-DDD extended ordinal date
143149 YYYYWww +-YYYYYYWww basic incomplete week date
144150 YYYY-Www +-YYYYYY-Www extended incomplete week date
151 YYYMM +-YYYYYYMM basic incomplete month date
145152 YYY-MM +-YYYYYY-MM incomplete month date
146153 YYYY +-YYYYYY incomplete year date
147154 YY +-YYYY incomplete century date
166173 # FIXME: negative dates not possible with python standard types
167174 sign = (groups['sign'] == '-' and -1) or 1
168175 if 'century' in groups:
169 return date(sign * (int(groups['century']) * 100 + 1), 1, 1)
176 return date(
177 sign * (int(groups['century']) * 100 + 1),
178 defaultmonth, defaultday)
170179 if 'month' not in groups: # weekdate or ordinal date
171180 ret = date(sign * int(groups['year']), 1, 1)
172181 if 'week' in groups:
180189 (((isotuple[1] == 1) and 1) or 0),
181190 days=-isotuple[2] + days)
182191 elif 'day' in groups: # ordinal date
183 return ret + timedelta(days=int(groups['day'])-1)
192 return ret + timedelta(days=int(groups['day']) - 1)
184193 else: # year date
185 return ret
194 return ret.replace(month=defaultmonth, day=defaultday)
186195 # year-, month-, or complete date
187196 if 'day' not in groups or groups['day'] is None:
188 day = 1
197 day = defaultday
189198 else:
190199 day = int(groups['day'])
191200 return date(sign * int(groups['year']),
192 int(groups['month']) or 1, day)
201 int(groups['month']) or defaultmonth, day)
193202 raise ISO8601Error('Unrecognised ISO 8601 date format: %r' % datestring)
194203
195204
3232 from datetime import timedelta
3333 from decimal import Decimal
3434 import re
35
36 from six import string_types
3537
3638 from isodate.duration import Duration
3739 from isodate.isoerror import ISO8601Error
7981 The alternative format does not support durations with years, months or
8082 days set to 0.
8183 """
82 if not isinstance(datestring, basestring):
84 if not isinstance(datestring, string_types):
8385 raise TypeError("Expecting a string %r" % datestring)
8486 match = ISO8601_PERIOD_REGEX.match(datestring)
8587 if not match:
4747 DATE_EXT_ORD_COMPLETE = '%Y-%j'
4848 DATE_BAS_WEEK = '%YW%W'
4949 DATE_EXT_WEEK = '%Y-W%W'
50 DATE_MONTH = '%Y-%m'
50 DATE_BAS_MONTH = '%Y%m'
51 DATE_EXT_MONTH = '%Y-%m'
5152 DATE_YEAR = '%Y'
5253 DATE_CENTURY = '%C'
5354
124124 if 'second' in groups:
125125 # round to microseconds if fractional seconds are more precise
126126 second = Decimal(groups['second']).quantize(Decimal('.000001'))
127 microsecond = (second - int(second)) * long(1e6)
127 microsecond = (second - int(second)) * int(1e6)
128128 # int(...) ... no rounding
129129 # to_integral() ... rounding
130130 return time(int(groups['hour']), int(groups['minute']),
133133 if 'minute' in groups:
134134 minute = Decimal(groups['minute'])
135135 second = (minute - int(minute)) * 60
136 microsecond = (second - int(second)) * long(1e6)
136 microsecond = (second - int(second)) * int(1e6)
137137 return time(int(groups['hour']), int(minute), int(second),
138138 int(microsecond.to_integral()), tzinfo)
139139 else:
141141 hour = Decimal(groups['hour'])
142142 minute = (hour - int(hour)) * 60
143143 second = (minute - int(minute)) * 60
144 microsecond = (second - int(second)) * long(1e6)
144 microsecond = (second - int(second)) * int(1e6)
145145 return time(int(hour), int(minute), int(second),
146146 int(microsecond.to_integral()), tzinfo)
147147 raise ISO8601Error('Unrecognised ISO 8601 time format: %r' % timestring)
3434 from isodate.tzinfo import UTC, FixedOffset, ZERO
3535
3636 TZ_REGEX = r"(?P<tzname>(Z|(?P<tzsign>[+-])"\
37 r"(?P<tzhour>[0-9]{2})(:(?P<tzmin>[0-9]{2}))?)?)"
37 r"(?P<tzhour>[0-9]{2})(:?(?P<tzmin>[0-9]{2}))?)?)"
3838
3939 TZ_RE = re.compile(TZ_REGEX)
4040
4545 test_pickle.test_suite(),
4646 ])
4747
48
4849 if __name__ == '__main__':
4950 unittest.main(defaultTest='test_suite')
2929 import unittest
3030 from datetime import date
3131 from isodate import parse_date, ISO8601Error, date_isoformat
32 from isodate import DATE_CENTURY, DATE_YEAR, DATE_MONTH
32 from isodate import DATE_CENTURY, DATE_YEAR
33 from isodate import DATE_BAS_MONTH, DATE_EXT_MONTH
3334 from isodate import DATE_EXT_COMPLETE, DATE_BAS_COMPLETE
3435 from isodate import DATE_BAS_ORD_COMPLETE, DATE_EXT_ORD_COMPLETE
3536 from isodate import DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE
4142 # and 6 digit years.
4243 TEST_CASES = {4: [('19', date(1901, 1, 1), DATE_CENTURY),
4344 ('1985', date(1985, 1, 1), DATE_YEAR),
44 ('1985-04', date(1985, 4, 1), DATE_MONTH),
45 ('1985-04', date(1985, 4, 1), DATE_EXT_MONTH),
46 ('198504', date(1985, 4, 1), DATE_BAS_MONTH),
4547 ('1985-04-12', date(1985, 4, 12), DATE_EXT_COMPLETE),
4648 ('19850412', date(1985, 4, 12), DATE_BAS_COMPLETE),
4749 ('1985102', date(1985, 4, 12), DATE_BAS_ORD_COMPLETE),
5557 ('1-W1-1', None, DATE_BAS_WEEK_COMPLETE)],
5658 6: [('+0019', date(1901, 1, 1), DATE_CENTURY),
5759 ('+001985', date(1985, 1, 1), DATE_YEAR),
58 ('+001985-04', date(1985, 4, 1), DATE_MONTH),
60 ('+001985-04', date(1985, 4, 1), DATE_EXT_MONTH),
5961 ('+001985-04-12', date(1985, 4, 12), DATE_EXT_COMPLETE),
6062 ('+0019850412', date(1985, 4, 12), DATE_BAS_COMPLETE),
6163 ('+001985102', date(1985, 4, 12), DATE_BAS_ORD_COMPLETE),
124126 def load_tests(loader, tests, pattern):
125127 return test_suite()
126128
129
127130 if __name__ == '__main__':
128131 unittest.main(defaultTest='test_suite')
6262 '+0400'),),
6363 DATE_EXT_WEEK_COMPLETE + 'T' + TIME_EXT_MINUTE + TZ_HOUR,
6464 '1985-W15-5T10:15+04'),
65 ('1985-W15-5T10:15-0430',
66 datetime(1985, 4, 12, 10, 15, tzinfo=FixedOffset(-4, -30,
67 '-0430'),),
68 DATE_EXT_WEEK_COMPLETE + 'T' + TIME_EXT_MINUTE + TZ_BAS,
69 '1985-W15-5T10:15-0430'),
70 ('1985-W15-5T10:15+04:45',
71 datetime(1985, 4, 12, 10, 15, tzinfo=FixedOffset(4, 45,
72 '+04:45'),),
73 DATE_EXT_WEEK_COMPLETE + 'T' + TIME_EXT_MINUTE + TZ_EXT,
74 '1985-W15-5T10:15+04:45'),
6575 ('20110410T101225.123000Z',
6676 datetime(2011, 4, 10, 10, 12, 25, 123000, tzinfo=UTC),
6777 DATE_BAS_COMPLETE + 'T' + TIME_BAS_COMPLETE + ".%f" + TZ_BAS,
141151 def load_tests(loader, tests, pattern):
142152 return test_suite()
143153
154
144155 if __name__ == '__main__':
145156 unittest.main(defaultTest='test_suite')
312312 self.assertEqual('10 years, 10 months, 10 days, 0:00:10', str(dur))
313313 self.assertEqual('isodate.duration.Duration(10, 10, 0,'
314314 ' years=10, months=10)', repr(dur))
315 dur = Duration(months=0)
316 self.assertEqual('0:00:00', str(dur))
317 dur = Duration(months=1)
318 self.assertEqual('1 month, 0:00:00', str(dur))
315319
316320 def test_hash(self):
317321 '''
596600 def load_tests(loader, tests, pattern):
597601 return test_suite()
598602
603
599604 if __name__ == '__main__':
600605 unittest.main(defaultTest='test_suite')
00 import unittest
1 import cPickle as pickle
1
2 from six.moves import cPickle as pickle
3
24 import isodate
35
46
3032 pikl = pickle.dumps(dur, proto)
3133 if dur != pickle.loads(pikl):
3234 raise Exception("not equal")
33 except Exception, e:
35 except Exception as e:
3436 failed.append("pickle proto %d failed (%s)" % (proto, repr(e)))
3537 self.assertEqual(len(failed), 0, "pickle protos failed: %s" %
3638 str(failed))
39
40 def test_pickle_utc(self):
41 '''
42 isodate.UTC objects remain the same after pickling.
43 '''
44 self.assertTrue(isodate.UTC is pickle.loads(pickle.dumps(isodate.UTC)))
3745
3846
3947 def test_suite():
4957 def load_tests(loader, tests, pattern):
5058 return test_suite()
5159
60
5261 if __name__ == '__main__':
5362 unittest.main(defaultTest='test_suite')
130130 def load_tests(loader, tests, pattern):
131131 return test_suite()
132132
133
133134 if __name__ == '__main__':
134135 unittest.main(defaultTest='test_suite')
8282 ('15:27:46-05', time(15, 27, 46,
8383 tzinfo=FixedOffset(-5, -0, '-05:00')),
8484 TIME_EXT_COMPLETE + TZ_HOUR),
85 ('15:27:46-05:30', time(15, 27, 46,
86 tzinfo=FixedOffset(-5, -30, '-05:30')),
87 TIME_EXT_COMPLETE + TZ_EXT),
88 ('15:27:46-0545', time(15, 27, 46,
89 tzinfo=FixedOffset(-5, -45, '-0545')),
90 TIME_EXT_COMPLETE + TZ_BAS),
8591 ('1:17:30', None, TIME_EXT_COMPLETE)]
8692
8793
138144 def load_tests(loader, tests, pattern):
139145 return test_suite()
140146
147
141148 if __name__ == '__main__':
142149 unittest.main(defaultTest='test_suite')
3535 '''
3636 return ZERO
3737
38 def __reduce__(self):
39 '''
40 When unpickling a Utc object, return the default instance below, UTC.
41 '''
42 return _Utc, ()
43
44
3845 UTC = Utc()
3946 # the default instance for UTC.
47
48
49 def _Utc():
50 '''
51 Helper function for unpickling a Utc object.
52 '''
53 return UTC
4054
4155
4256 class FixedOffset(tzinfo):
137151 tt = time.localtime(stamp)
138152 return tt.tm_isdst > 0
139153
154
155 # the default instance for local time zone.
140156 LOCAL = LocalTimezone()
141 # the default instance for local time zone.
00 Metadata-Version: 1.1
11 Name: isodate
2 Version: 0.5.4
2 Version: 0.6.0
33 Summary: An ISO 8601 date/time/duration parser and formatter
4 Home-page: http://cheeseshop.python.org/pypi/isodate
4 Home-page: https://github.com/gweis/isodate/
55 Author: Gerhard Weis
66 Author-email: gerhard.weis@proclos.com
77 License: BSD
1515 .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master
1616 :target: https://coveralls.io/r/gweis/isodate?branch=master
1717 :alt: Coveralls
18 .. image:: https://pypip.in/version/isodate/badge.svg
19 :target: https://pypi.python.org/pypi/isodate/
18 .. image:: https://img.shields.io/pypi/v/isodate.svg
19 :target: https://pypi.python.org/pypi/isodate/
2020 :alt: Latest Version
21 .. image:: https://pypip.in/download/isodate/badge.svg
22 :target: https://pypi.python.org/pypi/isodate/
23 :alt: Downloads
24 .. image:: https://pypip.in/license/isodate/badge.svg
25 :target: https://pypi.python.org/pypi/isodate/
21 .. image:: https://img.shields.io/pypi/l/isodate.svg
22 :target: https://pypi.python.org/pypi/isodate/
2623 :alt: License
2724
2825
120117 The doc strings and unit tests should provide rather detailed information about
121118 the methods and their limitations.
122119
123 The source release provides a *setup.py* script and a *buildout.cfg*. Both can
124 be used to run the unit tests included.
120 The source release provides a *setup.py* script,
121 which can be used to run the unit tests included.
125122
126123 Source code is available at `<http://github.com/gweis/isodate>`_.
127124
128125 CHANGES
129126 =======
127
128 0.6.0 (2017-10-13)
129 ------------------
130
131 - support incomplete month date (Fabien Loffredo)
132 - rely on duck typing when doing duration maths
133 - support ':' as separator in fractional time zones (usrenmae)
134
130135
131136 0.5.4 (2015-08-06)
132137 ------------------
264269 Classifier: Programming Language :: Python
265270 Classifier: Programming Language :: Python :: 2.6
266271 Classifier: Programming Language :: Python :: 2.7
267 Classifier: Programming Language :: Python :: 3.2
268272 Classifier: Programming Language :: Python :: 3.3
269273 Classifier: Programming Language :: Python :: 3.4
274 Classifier: Programming Language :: Python :: 3.5
275 Classifier: Programming Language :: Python :: 3.6
270276 Classifier: Programming Language :: Python :: Implementation :: PyPy
271277 Classifier: Topic :: Internet
272278 Classifier: Topic :: Software Development :: Libraries :: Python Modules
11 MANIFEST.in
22 README.rst
33 TODO.txt
4 setup.cfg
45 setup.py
56 src/isodate/__init__.py
67 src/isodate/duration.py
1516 src/isodate.egg-info/PKG-INFO
1617 src/isodate.egg-info/SOURCES.txt
1718 src/isodate.egg-info/dependency_links.txt
19 src/isodate.egg-info/requires.txt
1820 src/isodate.egg-info/top_level.txt
1921 src/isodate/tests/__init__.py
2022 src/isodate/tests/test_date.py