Import Upstream version 0.5.4
Sandro Tosi
4 years ago
0 | 0 | |
1 | 1 | CHANGES |
2 | 2 | ======= |
3 | ||
4 | 0.5.4 (2015-08-06) | |
5 | ------------------ | |
6 | ||
7 | - Fix parsing of Periods (Fabien Bochu) | |
8 | - Make Duration objects hashable (Geoffrey Fairchild) | |
9 | - Add multiplication to duration (Reinoud Elhorst) | |
10 | ||
3 | 11 | |
4 | 12 | 0.5.1 (2014-11-07) |
5 | 13 | ------------------ |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: isodate |
2 | Version: 0.5.1 | |
3 | Summary: An ISO 8601 date/time/duration parser and formater | |
2 | Version: 0.5.4 | |
3 | Summary: An ISO 8601 date/time/duration parser and formatter | |
4 | 4 | Home-page: http://cheeseshop.python.org/pypi/isodate |
5 | 5 | Author: Gerhard Weis |
6 | 6 | Author-email: gerhard.weis@proclos.com |
9 | 9 | ISO 8601 date/time parser |
10 | 10 | ========================= |
11 | 11 | |
12 | .. image:: https://travis-ci.org/gweis/isodate.png?branch=master | |
12 | .. image:: https://travis-ci.org/gweis/isodate.svg?branch=master | |
13 | 13 | :target: https://travis-ci.org/gweis/isodate |
14 | 14 | :alt: Travis-CI |
15 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master | |
15 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master | |
16 | 16 | :target: https://coveralls.io/r/gweis/isodate?branch=master |
17 | 17 | :alt: Coveralls |
18 | .. image:: https://pypip.in/v/isodate/badge.png | |
18 | .. image:: https://pypip.in/version/isodate/badge.svg | |
19 | 19 | :target: https://pypi.python.org/pypi/isodate/ |
20 | 20 | :alt: Latest Version |
21 | .. image:: https://pypip.in/d/isodate/badge.png | |
22 | :target: https://pypi.python.org/pypi//isodate/ | |
21 | .. image:: https://pypip.in/download/isodate/badge.svg | |
22 | :target: https://pypi.python.org/pypi/isodate/ | |
23 | 23 | :alt: Downloads |
24 | .. image:: https://pypip.in/license/isodate/badge.png | |
24 | .. image:: https://pypip.in/license/isodate/badge.svg | |
25 | 25 | :target: https://pypi.python.org/pypi/isodate/ |
26 | 26 | :alt: License |
27 | 27 | |
67 | 67 | which can be used almost like a *timedelta* object (with some limitations). |
68 | 68 | However, a *Duration* object can be converted into a *timedelta* object. |
69 | 69 | |
70 | There are also ISO formating methods for all supported data types. Each | |
70 | There are also ISO formatting methods for all supported data types. Each | |
71 | 71 | *xxx_isoformat* method accepts a format parameter. The default format is |
72 | 72 | always the ISO 8601 expanded format. This is the same format used by |
73 | 73 | *datetime.isoformat*: |
128 | 128 | CHANGES |
129 | 129 | ======= |
130 | 130 | |
131 | 0.5.4 (2015-08-06) | |
132 | ------------------ | |
133 | ||
134 | - Fix parsing of Periods (Fabien Bochu) | |
135 | - Make Duration objects hashable (Geoffrey Fairchild) | |
136 | - Add multiplication to duration (Reinoud Elhorst) | |
137 | ||
138 | ||
131 | 139 | 0.5.1 (2014-11-07) |
132 | 140 | ------------------ |
133 | 141 |
1 | 1 | ISO 8601 date/time parser |
2 | 2 | ========================= |
3 | 3 | |
4 | .. image:: https://travis-ci.org/gweis/isodate.png?branch=master | |
4 | .. image:: https://travis-ci.org/gweis/isodate.svg?branch=master | |
5 | 5 | :target: https://travis-ci.org/gweis/isodate |
6 | 6 | :alt: Travis-CI |
7 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master | |
7 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master | |
8 | 8 | :target: https://coveralls.io/r/gweis/isodate?branch=master |
9 | 9 | :alt: Coveralls |
10 | .. image:: https://pypip.in/v/isodate/badge.png | |
10 | .. image:: https://pypip.in/version/isodate/badge.svg | |
11 | 11 | :target: https://pypi.python.org/pypi/isodate/ |
12 | 12 | :alt: Latest Version |
13 | .. image:: https://pypip.in/d/isodate/badge.png | |
14 | :target: https://pypi.python.org/pypi//isodate/ | |
13 | .. image:: https://pypip.in/download/isodate/badge.svg | |
14 | :target: https://pypi.python.org/pypi/isodate/ | |
15 | 15 | :alt: Downloads |
16 | .. image:: https://pypip.in/license/isodate/badge.png | |
16 | .. image:: https://pypip.in/license/isodate/badge.svg | |
17 | 17 | :target: https://pypi.python.org/pypi/isodate/ |
18 | 18 | :alt: License |
19 | 19 | |
59 | 59 | which can be used almost like a *timedelta* object (with some limitations). |
60 | 60 | However, a *Duration* object can be converted into a *timedelta* object. |
61 | 61 | |
62 | There are also ISO formating methods for all supported data types. Each | |
62 | There are also ISO formatting methods for all supported data types. Each | |
63 | 63 | *xxx_isoformat* method accepts a format parameter. The default format is |
64 | 64 | always the ISO 8601 expanded format. This is the same format used by |
65 | 65 | *datetime.isoformat*: |
45 | 45 | return open(os.path.join(os.path.dirname(__file__), *rnames)).read() |
46 | 46 | |
47 | 47 | setup(name='isodate', |
48 | version='0.5.1', | |
48 | version='0.5.4', | |
49 | 49 | packages=['isodate', 'isodate.tests'], |
50 | 50 | package_dir={'': 'src'}, |
51 | 51 | |
55 | 55 | # PyPI metadata |
56 | 56 | author='Gerhard Weis', |
57 | 57 | author_email='gerhard.weis@proclos.com', |
58 | description='An ISO 8601 date/time/duration parser and formater', | |
58 | description='An ISO 8601 date/time/duration parser and formatter', | |
59 | 59 | license='BSD', |
60 | 60 | # keywords = '', |
61 | 61 | url='http://cheeseshop.python.org/pypi/isodate', |
53 | 53 | from isodate.isostrf import D_DEFAULT, D_WEEK, D_ALT_EXT, D_ALT_BAS |
54 | 54 | from isodate.isostrf import D_ALT_BAS_ORD, D_ALT_EXT_ORD |
55 | 55 | |
56 | __all__ = (parse_date, date_isoformat, parse_time, time_isoformat, | |
57 | parse_datetime, datetime_isoformat, parse_duration, | |
58 | duration_isoformat, ISO8601Error, parse_tzinfo, | |
59 | tz_isoformat, UTC, FixedOffset, LOCAL, Duration, | |
60 | strftime, DATE_BAS_COMPLETE, DATE_BAS_ORD_COMPLETE, | |
61 | DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE, DATE_CENTURY, | |
62 | DATE_EXT_COMPLETE, DATE_EXT_ORD_COMPLETE, DATE_EXT_WEEK, | |
63 | DATE_EXT_WEEK_COMPLETE, DATE_MONTH, DATE_YEAR, | |
64 | TIME_BAS_COMPLETE, TIME_BAS_MINUTE, TIME_EXT_COMPLETE, | |
65 | TIME_EXT_MINUTE, TIME_HOUR, TZ_BAS, TZ_EXT, TZ_HOUR, | |
66 | DT_BAS_COMPLETE, DT_EXT_COMPLETE, DT_BAS_ORD_COMPLETE, | |
67 | DT_EXT_ORD_COMPLETE, DT_BAS_WEEK_COMPLETE, | |
68 | DT_EXT_WEEK_COMPLETE, D_DEFAULT, D_WEEK, D_ALT_EXT, | |
69 | D_ALT_BAS, D_ALT_BAS_ORD, D_ALT_EXT_ORD) | |
56 | __all__ = ['parse_date', 'date_isoformat', 'parse_time', 'time_isoformat', | |
57 | 'parse_datetime', 'datetime_isoformat', 'parse_duration', | |
58 | 'duration_isoformat', 'ISO8601Error', 'parse_tzinfo', | |
59 | 'tz_isoformat', 'UTC', 'FixedOffset', 'LOCAL', 'Duration', | |
60 | 'strftime', 'DATE_BAS_COMPLETE', 'DATE_BAS_ORD_COMPLETE', | |
61 | 'DATE_BAS_WEEK', 'DATE_BAS_WEEK_COMPLETE', 'DATE_CENTURY', | |
62 | 'DATE_EXT_COMPLETE', 'DATE_EXT_ORD_COMPLETE', 'DATE_EXT_WEEK', | |
63 | 'DATE_EXT_WEEK_COMPLETE', 'DATE_MONTH', 'DATE_YEAR', | |
64 | 'TIME_BAS_COMPLETE', 'TIME_BAS_MINUTE', 'TIME_EXT_COMPLETE', | |
65 | 'TIME_EXT_MINUTE', 'TIME_HOUR', 'TZ_BAS', 'TZ_EXT', 'TZ_HOUR', | |
66 | 'DT_BAS_COMPLETE', 'DT_EXT_COMPLETE', 'DT_BAS_ORD_COMPLETE', | |
67 | 'DT_EXT_ORD_COMPLETE', 'DT_BAS_WEEK_COMPLETE', | |
68 | 'DT_EXT_WEEK_COMPLETE', 'D_DEFAULT', 'D_WEEK', 'D_ALT_EXT', | |
69 | 'D_ALT_BAS', 'D_ALT_BAS_ORD', 'D_ALT_EXT_ORD'] |
133 | 133 | self.tdelta.days, self.tdelta.seconds, |
134 | 134 | self.tdelta.microseconds, self.years, self.months) |
135 | 135 | |
136 | def __hash__(self): | |
137 | ''' | |
138 | Return a hash of this instance so that it can be used in, for | |
139 | example, dicts and sets. | |
140 | ''' | |
141 | return hash((self.tdelta, self.months, self.years)) | |
142 | ||
136 | 143 | def __neg__(self): |
137 | 144 | """ |
138 | 145 | A simple unary minus. |
158 | 165 | newduration.tdelta = self.tdelta + other.tdelta |
159 | 166 | return newduration |
160 | 167 | if isinstance(other, (date, datetime)): |
161 | if (not(float(self.years).is_integer() | |
162 | and float(self.months).is_integer())): | |
168 | if (not(float(self.years).is_integer() and | |
169 | float(self.months).is_integer())): | |
163 | 170 | raise ValueError('fractional years or months not supported' |
164 | 171 | ' for date calculations') |
165 | 172 | newmonth = other.month + self.months |
184 | 191 | newduration.tdelta = self.tdelta + other |
185 | 192 | return newduration |
186 | 193 | if isinstance(other, (date, datetime)): |
187 | if (not(float(self.years).is_integer() | |
188 | and float(self.months).is_integer())): | |
194 | if (not(float(self.years).is_integer() and | |
195 | float(self.months).is_integer())): | |
189 | 196 | raise ValueError('fractional years or months not supported' |
190 | 197 | ' for date calculations') |
191 | 198 | newmonth = other.month + self.months |
201 | 208 | raise TypeError('unsupported operand type(s) for +: %s and %s' % |
202 | 209 | (other.__class__, self.__class__)) |
203 | 210 | |
211 | def __mul__(self, other): | |
212 | if isinstance(other, int): | |
213 | newduration = Duration( | |
214 | years=self.years * other, | |
215 | months=self.months * other) | |
216 | newduration.tdelta = self.tdelta * other | |
217 | 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__)) | |
231 | ||
204 | 232 | def __sub__(self, other): |
205 | 233 | ''' |
206 | 234 | It is possible to subtract Duration and timedelta objects from Duration |
225 | 253 | ''' |
226 | 254 | # print '__rsub__:', self, other |
227 | 255 | if isinstance(other, (date, datetime)): |
228 | if (not(float(self.years).is_integer() | |
229 | and float(self.months).is_integer())): | |
256 | if (not(float(self.years).is_integer() and | |
257 | float(self.months).is_integer())): | |
230 | 258 | raise ValueError('fractional years or months not supported' |
231 | 259 | ' for date calculations') |
232 | 260 | newmonth = other.month - self.months |
257 | 285 | if not isinstance(other, Duration): |
258 | 286 | return NotImplemented |
259 | 287 | if (((self.years * 12 + self.months) == |
260 | (other.years * 12 + other.months) | |
261 | and self.tdelta == other.tdelta)): | |
288 | (other.years * 12 + other.months) and | |
289 | self.tdelta == other.tdelta)): | |
262 | 290 | return True |
263 | 291 | return False |
264 | 292 | |
267 | 295 | If the years, month part or the timedelta part is not equal, then |
268 | 296 | the two Durations are considered not equal. |
269 | 297 | ''' |
270 | if ((isinstance(other, timedelta) | |
271 | and self.years == 0 | |
272 | and self.months == 0)): | |
298 | if ((isinstance(other, timedelta) and | |
299 | self.years == 0 and | |
300 | self.months == 0)): | |
273 | 301 | return self.tdelta != other |
274 | 302 | if not isinstance(other, Duration): |
275 | 303 | return NotImplemented |
276 | 304 | if (((self.years * 12 + self.months) != |
277 | (other.years * 12 + other.months) | |
278 | or self.tdelta != other.tdelta)): | |
305 | (other.years * 12 + other.months) or | |
306 | self.tdelta != other.tdelta)): | |
279 | 307 | return True |
280 | 308 | return False |
281 | 309 |
40 | 40 | |
41 | 41 | ISO8601_PERIOD_REGEX = re.compile( |
42 | 42 | r"^(?P<sign>[+-])?" |
43 | r"P(?P<years>[0-9]+([,.][0-9]+)?Y)?" | |
43 | r"P(?!\b)" | |
44 | r"(?P<years>[0-9]+([,.][0-9]+)?Y)?" | |
44 | 45 | r"(?P<months>[0-9]+([,.][0-9]+)?M)?" |
45 | 46 | r"(?P<weeks>[0-9]+([,.][0-9]+)?W)?" |
46 | 47 | r"(?P<days>[0-9]+([,.][0-9]+)?D)?" |
135 | 136 | ''' |
136 | 137 | # TODO: implement better decision for negative Durations. |
137 | 138 | # should be done in Duration class in consistent way with timedelta. |
138 | if (((isinstance(tduration, Duration) | |
139 | and (tduration.years < 0 or tduration.months < 0 | |
140 | or tduration.tdelta < timedelta(0))) | |
141 | or (isinstance(tduration, timedelta) | |
142 | and (tduration < timedelta(0))))): | |
139 | if (((isinstance(tduration, Duration) and | |
140 | (tduration.years < 0 or tduration.months < 0 or | |
141 | tduration.tdelta < timedelta(0))) or | |
142 | (isinstance(tduration, timedelta) and | |
143 | (tduration < timedelta(0))))): | |
143 | 144 | ret = '-' |
144 | 145 | else: |
145 | 146 | ret = '' |
70 | 70 | # hh:mm:ss.ss ... extended format |
71 | 71 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}):" |
72 | 72 | r"(?P<minute>[0-9]{2}):" |
73 | r"(?P<second>[0-9]{2}([,.][0-9]+)?)" | |
74 | + TZ_REGEX)) | |
73 | r"(?P<second>[0-9]{2}" | |
74 | r"([,.][0-9]+)?)" + TZ_REGEX)) | |
75 | 75 | # hhmmss.ss ... basic format |
76 | 76 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2})" |
77 | 77 | r"(?P<minute>[0-9]{2})" |
78 | r"(?P<second>[0-9]{2}([,.][0-9]+)?)" | |
79 | + TZ_REGEX)) | |
78 | r"(?P<second>[0-9]{2}" | |
79 | r"([,.][0-9]+)?)" + TZ_REGEX)) | |
80 | 80 | # 2. reduced accuracy: |
81 | 81 | # hh:mm.mm ... extended format |
82 | 82 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}):" |
83 | r"(?P<minute>[0-9]{2}([,.][0-9]+)?)" | |
84 | + TZ_REGEX)) | |
83 | r"(?P<minute>[0-9]{2}" | |
84 | r"([,.][0-9]+)?)" + TZ_REGEX)) | |
85 | 85 | # hhmm.mm ... basic format |
86 | 86 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2})" |
87 | r"(?P<minute>[0-9]{2}([,.][0-9]+)?)" | |
88 | + TZ_REGEX)) | |
87 | r"(?P<minute>[0-9]{2}" | |
88 | r"([,.][0-9]+)?)" + TZ_REGEX)) | |
89 | 89 | # hh.hh ... basic format |
90 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}([,.][0-9]+)?)" | |
91 | + TZ_REGEX)) | |
90 | TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}" | |
91 | r"([,.][0-9]+)?)" + TZ_REGEX)) | |
92 | 92 | return TIME_REGEX_CACHE |
93 | 93 | |
94 | 94 |
230 | 230 | # date(2001, 2, 14)), |
231 | 231 | ) |
232 | 232 | |
233 | # A list of test cases of multiplications of durations | |
234 | # are compared against a given expected result. | |
235 | DATE_MUL_TEST_CASES = ( | |
236 | (Duration(years=1, months=1), | |
237 | 3, | |
238 | Duration(years=3, months=3)), | |
239 | (Duration(years=1, months=1), | |
240 | -3, | |
241 | Duration(years=-3, months=-3)), | |
242 | (3, | |
243 | Duration(years=1, months=1), | |
244 | Duration(years=3, months=3)), | |
245 | (-3, | |
246 | Duration(years=1, months=1), | |
247 | Duration(years=-3, months=-3)), | |
248 | (5, | |
249 | Duration(years=2, minutes=40), | |
250 | Duration(years=10, hours=3, minutes=20)), | |
251 | (-5, | |
252 | Duration(years=2, minutes=40), | |
253 | Duration(years=-10, hours=-3, minutes=-20)), | |
254 | (7, | |
255 | Duration(years=1, months=2, weeks=40), | |
256 | Duration(years=8, months=2, weeks=280))) | |
257 | ||
233 | 258 | |
234 | 259 | class DurationTest(unittest.TestCase): |
235 | 260 | ''' |
262 | 287 | 'raise exception') |
263 | 288 | self.assertRaises(TypeError, operator.add, 'raise exception', |
264 | 289 | Duration(years=1, months=1, weeks=5)) |
290 | self.assertRaises(TypeError, operator.mul, | |
291 | Duration(years=1, months=1, weeks=5), | |
292 | 'raise exception') | |
293 | self.assertRaises(TypeError, operator.mul, 'raise exception', | |
294 | Duration(years=1, months=1, weeks=5)) | |
295 | self.assertRaises(TypeError, operator.mul, | |
296 | Duration(years=1, months=1, weeks=5), | |
297 | 3.14) | |
298 | self.assertRaises(TypeError, operator.mul, 3.14, | |
299 | Duration(years=1, months=1, weeks=5)) | |
265 | 300 | |
266 | 301 | def test_parseerror(self): |
267 | 302 | ''' |
271 | 306 | |
272 | 307 | def test_repr(self): |
273 | 308 | ''' |
274 | Test __repr__ and __str__ for Duration obqects. | |
309 | Test __repr__ and __str__ for Duration objects. | |
275 | 310 | ''' |
276 | 311 | dur = Duration(10, 10, years=10, months=10) |
277 | 312 | self.assertEqual('10 years, 10 months, 10 days, 0:00:10', str(dur)) |
278 | 313 | self.assertEqual('isodate.duration.Duration(10, 10, 0,' |
279 | 314 | ' years=10, months=10)', repr(dur)) |
315 | ||
316 | def test_hash(self): | |
317 | ''' | |
318 | Test __hash__ for Duration objects. | |
319 | ''' | |
320 | dur1 = Duration(10, 10, years=10, months=10) | |
321 | dur2 = Duration(9, 9, years=9, months=9) | |
322 | dur3 = Duration(10, 10, years=10, months=10) | |
323 | self.assertNotEqual(hash(dur1), hash(dur2)) | |
324 | self.assertNotEqual(id(dur1), id(dur2)) | |
325 | self.assertEqual(hash(dur1), hash(dur3)) | |
326 | self.assertNotEqual(id(dur1), id(dur3)) | |
327 | durSet = set() | |
328 | durSet.add(dur1) | |
329 | durSet.add(dur2) | |
330 | durSet.add(dur3) | |
331 | self.assertEqual(len(durSet), 2) | |
280 | 332 | |
281 | 333 | def test_neg(self): |
282 | 334 | ''' |
497 | 549 | return unittest.TestLoader().loadTestsFromTestCase(TestDateCalc) |
498 | 550 | |
499 | 551 | |
552 | def create_datemultestcase(operand1, operand2, expectation): | |
553 | """ | |
554 | Create a TestCase class for a specific test. | |
555 | ||
556 | This allows having a separate TestCase for each test tuple from the | |
557 | DATE_CALC_TEST_CASES list, so that a failed test won't stop other tests. | |
558 | """ | |
559 | ||
560 | class TestDateMul(unittest.TestCase): | |
561 | ''' | |
562 | A test case template test addition operators for Duration objects. | |
563 | ''' | |
564 | ||
565 | def test_mul(self): | |
566 | ''' | |
567 | Test operator *. | |
568 | ''' | |
569 | self.assertEqual(operand1 * operand2, expectation) | |
570 | ||
571 | return unittest.TestLoader().loadTestsFromTestCase(TestDateMul) | |
572 | ||
573 | ||
500 | 574 | def test_suite(): |
501 | 575 | ''' |
502 | 576 | Return a test suite containing all test defined above. |
512 | 586 | suite.addTest(create_datetestcase(*testdata)) |
513 | 587 | for testdata in DATE_CALC_TEST_CASES: |
514 | 588 | suite.addTest(create_datecalctestcase(*testdata)) |
589 | for testdata in DATE_MUL_TEST_CASES: | |
590 | suite.addTest(create_datemultestcase(*testdata)) | |
515 | 591 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(DurationTest)) |
516 | 592 | return suite |
517 | 593 |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: isodate |
2 | Version: 0.5.1 | |
3 | Summary: An ISO 8601 date/time/duration parser and formater | |
2 | Version: 0.5.4 | |
3 | Summary: An ISO 8601 date/time/duration parser and formatter | |
4 | 4 | Home-page: http://cheeseshop.python.org/pypi/isodate |
5 | 5 | Author: Gerhard Weis |
6 | 6 | Author-email: gerhard.weis@proclos.com |
9 | 9 | ISO 8601 date/time parser |
10 | 10 | ========================= |
11 | 11 | |
12 | .. image:: https://travis-ci.org/gweis/isodate.png?branch=master | |
12 | .. image:: https://travis-ci.org/gweis/isodate.svg?branch=master | |
13 | 13 | :target: https://travis-ci.org/gweis/isodate |
14 | 14 | :alt: Travis-CI |
15 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master | |
15 | .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master | |
16 | 16 | :target: https://coveralls.io/r/gweis/isodate?branch=master |
17 | 17 | :alt: Coveralls |
18 | .. image:: https://pypip.in/v/isodate/badge.png | |
18 | .. image:: https://pypip.in/version/isodate/badge.svg | |
19 | 19 | :target: https://pypi.python.org/pypi/isodate/ |
20 | 20 | :alt: Latest Version |
21 | .. image:: https://pypip.in/d/isodate/badge.png | |
22 | :target: https://pypi.python.org/pypi//isodate/ | |
21 | .. image:: https://pypip.in/download/isodate/badge.svg | |
22 | :target: https://pypi.python.org/pypi/isodate/ | |
23 | 23 | :alt: Downloads |
24 | .. image:: https://pypip.in/license/isodate/badge.png | |
24 | .. image:: https://pypip.in/license/isodate/badge.svg | |
25 | 25 | :target: https://pypi.python.org/pypi/isodate/ |
26 | 26 | :alt: License |
27 | 27 | |
67 | 67 | which can be used almost like a *timedelta* object (with some limitations). |
68 | 68 | However, a *Duration* object can be converted into a *timedelta* object. |
69 | 69 | |
70 | There are also ISO formating methods for all supported data types. Each | |
70 | There are also ISO formatting methods for all supported data types. Each | |
71 | 71 | *xxx_isoformat* method accepts a format parameter. The default format is |
72 | 72 | always the ISO 8601 expanded format. This is the same format used by |
73 | 73 | *datetime.isoformat*: |
128 | 128 | CHANGES |
129 | 129 | ======= |
130 | 130 | |
131 | 0.5.4 (2015-08-06) | |
132 | ------------------ | |
133 | ||
134 | - Fix parsing of Periods (Fabien Bochu) | |
135 | - Make Duration objects hashable (Geoffrey Fairchild) | |
136 | - Add multiplication to duration (Reinoud Elhorst) | |
137 | ||
138 | ||
131 | 139 | 0.5.1 (2014-11-07) |
132 | 140 | ------------------ |
133 | 141 |