dateutil / dateutil
 1 ```# -*- coding: utf-8 -*- ``` 2 20 ```from __future__ import unicode_literals ``` 3 4 20 ```from datetime import datetime, timedelta, date, time ``` 5 20 ```import itertools as it ``` 6 7 20 ```from dateutil import tz ``` 8 20 ```from dateutil.tz import UTC ``` 9 20 ```from dateutil.parser import isoparser, isoparse ``` 10 11 20 ```import pytest ``` 12 20 ```import six ``` 13 14 15 20 ```def _generate_tzoffsets(limited): ``` 16 20 ``` def _mkoffset(hmtuple, fmt): ``` 17 20 ``` h, m = hmtuple ``` 18 20 ``` m_td = (-1 if h < 0 else 1) * m ``` 19 20 20 ``` tzo = tz.tzoffset(None, timedelta(hours=h, minutes=m_td)) ``` 21 20 ``` return tzo, fmt.format(h, m) ``` 22 23 20 ``` out = [] ``` 24 20 ``` if not limited: ``` 25 ``` # The subset that's just hours ``` 26 20 ``` hm_out_h = [(h, 0) for h in (-23, -5, 0, 5, 23)] ``` 27 20 ``` out.extend([_mkoffset(hm, '{:+03d}') for hm in hm_out_h]) ``` 28 29 ``` # Ones that have hours and minutes ``` 30 20 ``` hm_out = [] + hm_out_h ``` 31 20 ``` hm_out += [(-12, 15), (11, 30), (10, 2), (5, 15), (-5, 30)] ``` 32 ``` else: ``` 33 20 ``` hm_out = [(-5, -0)] ``` 34 35 20 ``` fmts = ['{:+03d}:{:02d}', '{:+03d}{:02d}'] ``` 36 20 ``` out += [_mkoffset(hm, fmt) for hm in hm_out for fmt in fmts] ``` 37 38 ``` # Also add in UTC and naive ``` 39 20 ``` out.append((UTC, 'Z')) ``` 40 20 ``` out.append((None, '')) ``` 41 42 20 ``` return out ``` 43 44 20 ```FULL_TZOFFSETS = _generate_tzoffsets(False) ``` 45 20 ```FULL_TZOFFSETS_AWARE = [x for x in FULL_TZOFFSETS if x[1]] ``` 46 20 ```TZOFFSETS = _generate_tzoffsets(True) ``` 47 48 20 ```DATES = [datetime(1996, 1, 1), datetime(2017, 1, 1)] ``` 49 20 ```@pytest.mark.parametrize('dt', tuple(DATES)) ``` 50 2 ```def test_year_only(dt): ``` 51 20 ``` dtstr = dt.strftime('%Y') ``` 52 53 20 ``` assert isoparse(dtstr) == dt ``` 54 55 20 ```DATES += [datetime(2000, 2, 1), datetime(2017, 4, 1)] ``` 56 20 ```@pytest.mark.parametrize('dt', tuple(DATES)) ``` 57 2 ```def test_year_month(dt): ``` 58 20 ``` fmt = '%Y-%m' ``` 59 20 ``` dtstr = dt.strftime(fmt) ``` 60 61 20 ``` assert isoparse(dtstr) == dt ``` 62 63 20 ```DATES += [datetime(2016, 2, 29), datetime(2018, 3, 15)] ``` 64 20 ```YMD_FMTS = ('%Y%m%d', '%Y-%m-%d') ``` 65 20 ```@pytest.mark.parametrize('dt', tuple(DATES)) ``` 66 20 ```@pytest.mark.parametrize('fmt', YMD_FMTS) ``` 67 2 ```def test_year_month_day(dt, fmt): ``` 68 20 ``` dtstr = dt.strftime(fmt) ``` 69 70 20 ``` assert isoparse(dtstr) == dt ``` 71 72 20 ```def _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset, ``` 73 ``` microsecond_precision=None): ``` 74 20 ``` tzi, offset_str = tzoffset ``` 75 20 ``` fmt = date_fmt + 'T' + time_fmt ``` 76 20 ``` dt = dt.replace(tzinfo=tzi) ``` 77 20 ``` dtstr = dt.strftime(fmt) ``` 78 79 20 ``` if microsecond_precision is not None: ``` 80 ``` if not fmt.endswith('%f'): # pragma: nocover ``` 81 ``` raise ValueError('Time format has no microseconds!') ``` 82 83 20 ``` if microsecond_precision != 6: ``` 84 20 ``` dtstr = dtstr[:-(6 - microsecond_precision)] ``` 85 ``` elif microsecond_precision > 6: # pragma: nocover ``` 86 ``` raise ValueError('Precision must be 1-6') ``` 87 88 20 ``` dtstr += offset_str ``` 89 90 20 ``` assert isoparse(dtstr) == dt ``` 91 92 20 ```DATETIMES = [datetime(1998, 4, 16, 12), ``` 93 ``` datetime(2019, 11, 18, 23), ``` 94 ``` datetime(2014, 12, 16, 4)] ``` 95 20 ```@pytest.mark.parametrize('dt', tuple(DATETIMES)) ``` 96 20 ```@pytest.mark.parametrize('date_fmt', YMD_FMTS) ``` 97 20 ```@pytest.mark.parametrize('tzoffset', TZOFFSETS) ``` 98 2 ```def test_ymd_h(dt, date_fmt, tzoffset): ``` 99 20 ``` _isoparse_date_and_time(dt, date_fmt, '%H', tzoffset) ``` 100 101 20 ```DATETIMES = [datetime(2012, 1, 6, 9, 37)] ``` 102 20 ```@pytest.mark.parametrize('dt', tuple(DATETIMES)) ``` 103 20 ```@pytest.mark.parametrize('date_fmt', YMD_FMTS) ``` 104 20 ```@pytest.mark.parametrize('time_fmt', ('%H%M', '%H:%M')) ``` 105 20 ```@pytest.mark.parametrize('tzoffset', TZOFFSETS) ``` 106 2 ```def test_ymd_hm(dt, date_fmt, time_fmt, tzoffset): ``` 107 20 ``` _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset) ``` 108 109 20 ```DATETIMES = [datetime(2003, 9, 2, 22, 14, 2), ``` 110 ``` datetime(2003, 8, 8, 14, 9, 14), ``` 111 ``` datetime(2003, 4, 7, 6, 14, 59)] ``` 112 20 ```HMS_FMTS = ('%H%M%S', '%H:%M:%S') ``` 113 20 ```@pytest.mark.parametrize('dt', tuple(DATETIMES)) ``` 114 20 ```@pytest.mark.parametrize('date_fmt', YMD_FMTS) ``` 115 20 ```@pytest.mark.parametrize('time_fmt', HMS_FMTS) ``` 116 20 ```@pytest.mark.parametrize('tzoffset', TZOFFSETS) ``` 117 2 ```def test_ymd_hms(dt, date_fmt, time_fmt, tzoffset): ``` 118 20 ``` _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset) ``` 119 120 20 ```DATETIMES = [datetime(2017, 11, 27, 6, 14, 30, 123456)] ``` 121 20 ```@pytest.mark.parametrize('dt', tuple(DATETIMES)) ``` 122 20 ```@pytest.mark.parametrize('date_fmt', YMD_FMTS) ``` 123 20 ```@pytest.mark.parametrize('time_fmt', (x + sep + '%f' for x in HMS_FMTS ``` 124 ``` for sep in '.,')) ``` 125 20 ```@pytest.mark.parametrize('tzoffset', TZOFFSETS) ``` 126 20 ```@pytest.mark.parametrize('precision', list(range(3, 7))) ``` 127 2 ```def test_ymd_hms_micro(dt, date_fmt, time_fmt, tzoffset, precision): ``` 128 ``` # Truncate the microseconds to the desired precision for the representation ``` 129 20 ``` dt = dt.replace(microsecond=int(round(dt.microsecond, precision-6))) ``` 130 131 20 ``` _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset, precision) ``` 132 133 ```### ``` 134 ```# Truncation of extra digits beyond microsecond precision ``` 135 20 ```@pytest.mark.parametrize('dt_str', [ ``` 136 ``` '2018-07-03T14:07:00.123456000001', ``` 137 ``` '2018-07-03T14:07:00.123456999999', ``` 138 ```]) ``` 139 2 ```def test_extra_subsecond_digits(dt_str): ``` 140 20 ``` assert isoparse(dt_str) == datetime(2018, 7, 3, 14, 7, 0, 123456) ``` 141 142 20 ```@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS) ``` 143 2 ```def test_full_tzoffsets(tzoffset): ``` 144 20 ``` dt = datetime(2017, 11, 27, 6, 14, 30, 123456) ``` 145 20 ``` date_fmt = '%Y-%m-%d' ``` 146 20 ``` time_fmt = '%H:%M:%S.%f' ``` 147 148 20 ``` _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset) ``` 149 150 20 ```@pytest.mark.parametrize('dt_str', [ ``` 151 ``` '2014-04-11T00', ``` 152 ``` '2014-04-10T24', ``` 153 ``` '2014-04-11T00:00', ``` 154 ``` '2014-04-10T24:00', ``` 155 ``` '2014-04-11T00:00:00', ``` 156 ``` '2014-04-10T24:00:00', ``` 157 ``` '2014-04-11T00:00:00.000', ``` 158 ``` '2014-04-10T24:00:00.000', ``` 159 ``` '2014-04-11T00:00:00.000000', ``` 160 ``` '2014-04-10T24:00:00.000000'] ``` 161 ```) ``` 162 2 ```def test_datetime_midnight(dt_str): ``` 163 20 ``` assert isoparse(dt_str) == datetime(2014, 4, 11, 0, 0, 0, 0) ``` 164 165 20 ```@pytest.mark.parametrize('datestr', [ ``` 166 ``` '2014-01-01', ``` 167 ``` '20140101', ``` 168 ```]) ``` 169 20 ```@pytest.mark.parametrize('sep', [' ', 'a', 'T', '_', '-']) ``` 170 2 ```def test_isoparse_sep_none(datestr, sep): ``` 171 20 ``` isostr = datestr + sep + '14:33:09' ``` 172 20 ``` assert isoparse(isostr) == datetime(2014, 1, 1, 14, 33, 9) ``` 173 174 ```## ``` 175 ```# Uncommon date formats ``` 176 20 ```TIME_ARGS = ('time_args', ``` 177 ``` ((None, time(0), None), ) + tuple(('%H:%M:%S.%f', _t, _tz) ``` 178 ``` for _t, _tz in it.product([time(0), time(9, 30), time(14, 47)], ``` 179 ``` TZOFFSETS))) ``` 180 181 20 ```@pytest.mark.parametrize('isocal,dt_expected',[ ``` 182 ``` ((2017, 10), datetime(2017, 3, 6)), ``` 183 ``` ((2020, 1), datetime(2019, 12, 30)), # ISO year != Cal year ``` 184 ``` ((2004, 53), datetime(2004, 12, 27)), # Only half the week is in 2014 ``` 185 ```]) ``` 186 2 ```def test_isoweek(isocal, dt_expected): ``` 187 ``` # TODO: Figure out how to parametrize this on formats, too ``` 188 20 ``` for fmt in ('{:04d}-W{:02d}', '{:04d}W{:02d}'): ``` 189 20 ``` dtstr = fmt.format(*isocal) ``` 190 20 ``` assert isoparse(dtstr) == dt_expected ``` 191 192 20 ```@pytest.mark.parametrize('isocal,dt_expected',[ ``` 193 ``` ((2016, 13, 7), datetime(2016, 4, 3)), ``` 194 ``` ((2004, 53, 7), datetime(2005, 1, 2)), # ISO year != Cal year ``` 195 ``` ((2009, 1, 2), datetime(2008, 12, 30)), # ISO year < Cal year ``` 196 ``` ((2009, 53, 6), datetime(2010, 1, 2)) # ISO year > Cal year ``` 197 ```]) ``` 198 2 ```def test_isoweek_day(isocal, dt_expected): ``` 199 ``` # TODO: Figure out how to parametrize this on formats, too ``` 200 20 ``` for fmt in ('{:04d}-W{:02d}-{:d}', '{:04d}W{:02d}{:d}'): ``` 201 20 ``` dtstr = fmt.format(*isocal) ``` 202 20 ``` assert isoparse(dtstr) == dt_expected ``` 203 204 20 ```@pytest.mark.parametrize('isoord,dt_expected', [ ``` 205 ``` ((2004, 1), datetime(2004, 1, 1)), ``` 206 ``` ((2016, 60), datetime(2016, 2, 29)), ``` 207 ``` ((2017, 60), datetime(2017, 3, 1)), ``` 208 ``` ((2016, 366), datetime(2016, 12, 31)), ``` 209 ``` ((2017, 365), datetime(2017, 12, 31)) ``` 210 ```]) ``` 211 2 ```def test_iso_ordinal(isoord, dt_expected): ``` 212 20 ``` for fmt in ('{:04d}-{:03d}', '{:04d}{:03d}'): ``` 213 20 ``` dtstr = fmt.format(*isoord) ``` 214 215 20 ``` assert isoparse(dtstr) == dt_expected ``` 216 217 218 ```### ``` 219 ```# Acceptance of bytes ``` 220 20 ```@pytest.mark.parametrize('isostr,dt', [ ``` 221 ``` (b'2014', datetime(2014, 1, 1)), ``` 222 ``` (b'20140204', datetime(2014, 2, 4)), ``` 223 ``` (b'2014-02-04', datetime(2014, 2, 4)), ``` 224 ``` (b'2014-02-04T12', datetime(2014, 2, 4, 12)), ``` 225 ``` (b'2014-02-04T12:30', datetime(2014, 2, 4, 12, 30)), ``` 226 ``` (b'2014-02-04T12:30:15', datetime(2014, 2, 4, 12, 30, 15)), ``` 227 ``` (b'2014-02-04T12:30:15.224', datetime(2014, 2, 4, 12, 30, 15, 224000)), ``` 228 ``` (b'20140204T123015.224', datetime(2014, 2, 4, 12, 30, 15, 224000)), ``` 229 ``` (b'2014-02-04T12:30:15.224Z', datetime(2014, 2, 4, 12, 30, 15, 224000, ``` 230 ``` UTC)), ``` 231 ``` (b'2014-02-04T12:30:15.224z', datetime(2014, 2, 4, 12, 30, 15, 224000, ``` 232 ``` UTC)), ``` 233 ``` (b'2014-02-04T12:30:15.224+05:00', ``` 234 ``` datetime(2014, 2, 4, 12, 30, 15, 224000, ``` 235 ``` tzinfo=tz.tzoffset(None, timedelta(hours=5))))]) ``` 236 2 ```def test_bytes(isostr, dt): ``` 237 20 ``` assert isoparse(isostr) == dt ``` 238 239 240 ```### ``` 241 ```# Invalid ISO strings ``` 242 20 ```@pytest.mark.parametrize('isostr,exception', [ ``` 243 ``` ('201', ValueError), # ISO string too short ``` 244 ``` ('2012-0425', ValueError), # Inconsistent date separators ``` 245 ``` ('201204-25', ValueError), # Inconsistent date separators ``` 246 ``` ('20120425T0120:00', ValueError), # Inconsistent time separators ``` 247 ``` ('20120425T012500-334', ValueError), # Wrong microsecond separator ``` 248 ``` ('2001-1', ValueError), # YYYY-M not valid ``` 249 ``` ('2012-04-9', ValueError), # YYYY-MM-D not valid ``` 250 ``` ('201204', ValueError), # YYYYMM not valid ``` 251 ``` ('20120411T03:30+', ValueError), # Time zone too short ``` 252 ``` ('20120411T03:30+1234567', ValueError), # Time zone too long ``` 253 ``` ('20120411T03:30-25:40', ValueError), # Time zone invalid ``` 254 ``` ('2012-1a', ValueError), # Invalid month ``` 255 ``` ('20120411T03:30+00:60', ValueError), # Time zone invalid minutes ``` 256 ``` ('20120411T03:30+00:61', ValueError), # Time zone invalid minutes ``` 257 ``` ('20120411T033030.123456012:00', # No sign in time zone ``` 258 ``` ValueError), ``` 259 ``` ('2012-W00', ValueError), # Invalid ISO week ``` 260 ``` ('2012-W55', ValueError), # Invalid ISO week ``` 261 ``` ('2012-W01-0', ValueError), # Invalid ISO week day ``` 262 ``` ('2012-W01-8', ValueError), # Invalid ISO week day ``` 263 ``` ('2013-000', ValueError), # Invalid ordinal day ``` 264 ``` ('2013-366', ValueError), # Invalid ordinal day ``` 265 ``` ('2013366', ValueError), # Invalid ordinal day ``` 266 ``` ('2014-03-12Т12:30:14', ValueError), # Cyrillic T ``` 267 ``` ('2014-04-21T24:00:01', ValueError), # Invalid use of 24 for midnight ``` 268 ``` ('2014_W01-1', ValueError), # Invalid separator ``` 269 ``` ('2014W01-1', ValueError), # Inconsistent use of dashes ``` 270 ``` ('2014-W011', ValueError), # Inconsistent use of dashes ``` 271 272 ```]) ``` 273 2 ```def test_iso_raises(isostr, exception): ``` 274 20 ``` with pytest.raises(exception): ``` 275 20 ``` isoparse(isostr) ``` 276 277 278 20 ```@pytest.mark.parametrize('sep_act, valid_sep, exception', [ ``` 279 ``` ('T', 'C', ValueError), ``` 280 ``` ('C', 'T', ValueError), ``` 281 ```]) ``` 282 2 ```def test_iso_with_sep_raises(sep_act, valid_sep, exception): ``` 283 20 ``` parser = isoparser(sep=valid_sep) ``` 284 20 ``` isostr = '2012-04-25' + sep_act + '01:25:00' ``` 285 20 ``` with pytest.raises(exception): ``` 286 20 ``` parser.isoparse(isostr) ``` 287 288 289 20 ```@pytest.mark.xfail() ``` 290 ```@pytest.mark.parametrize('isostr,exception', [ # pragma: nocover ``` 291 ``` ('20120425T01:2000', ValueError), # Inconsistent time separators ``` 292 ```]) ``` 293 ```def test_iso_raises_failing(isostr, exception): ``` 294 ``` # These are test cases where the current implementation is too lenient ``` 295 ``` # and need to be fixed ``` 296 ``` with pytest.raises(exception): ``` 297 ``` isoparse(isostr) ``` 298 299 300 ```### ``` 301 ```# Test ISOParser constructor ``` 302 20 ```@pytest.mark.parametrize('sep', [' ', '9', '🍛']) ``` 303 2 ```def test_isoparser_invalid_sep(sep): ``` 304 20 ``` with pytest.raises(ValueError): ``` 305 20 ``` isoparser(sep=sep) ``` 306 307 308 ```# This only fails on Python 3 ``` 309 20 ```@pytest.mark.xfail(not six.PY2, reason="Fails on Python 3 only") ``` 310 2 ```def test_isoparser_byte_sep(): ``` 311 6 ``` dt = datetime(2017, 12, 6, 12, 30, 45) ``` 312 6 ``` dt_str = dt.isoformat(sep=str('T')) ``` 313 314 6 ``` dt_rt = isoparser(sep=b'T').isoparse(dt_str) ``` 315 316 6 ``` assert dt == dt_rt ``` 317 318 319 ```### ``` 320 ```# Test parse_tzstr ``` 321 20 ```@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS) ``` 322 2 ```def test_parse_tzstr(tzoffset): ``` 323 20 ``` dt = datetime(2017, 11, 27, 6, 14, 30, 123456) ``` 324 20 ``` date_fmt = '%Y-%m-%d' ``` 325 20 ``` time_fmt = '%H:%M:%S.%f' ``` 326 327 20 ``` _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset) ``` 328 329 330 20 ```@pytest.mark.parametrize('tzstr', [ ``` 331 ``` '-00:00', '+00:00', '+00', '-00', '+0000', '-0000' ``` 332 ```]) ``` 333 20 ```@pytest.mark.parametrize('zero_as_utc', [True, False]) ``` 334 2 ```def test_parse_tzstr_zero_as_utc(tzstr, zero_as_utc): ``` 335 20 ``` tzi = isoparser().parse_tzstr(tzstr, zero_as_utc=zero_as_utc) ``` 336 20 ``` assert tzi == UTC ``` 337 20 ``` assert (type(tzi) == tz.tzutc) == zero_as_utc ``` 338 339 340 20 ```@pytest.mark.parametrize('tzstr,exception', [ ``` 341 ``` ('00:00', ValueError), # No sign ``` 342 ``` ('05:00', ValueError), # No sign ``` 343 ``` ('_00:00', ValueError), # Invalid sign ``` 344 ``` ('+25:00', ValueError), # Offset too large ``` 345 ``` ('00:0000', ValueError), # String too long ``` 346 ```]) ``` 347 2 ```def test_parse_tzstr_fails(tzstr, exception): ``` 348 20 ``` with pytest.raises(exception): ``` 349 20 ``` isoparser().parse_tzstr(tzstr) ``` 350 351 ```### ``` 352 ```# Test parse_isodate ``` 353 20 ```def __make_date_examples(): ``` 354 20 ``` dates_no_day = [ ``` 355 ``` date(1999, 12, 1), ``` 356 ``` date(2016, 2, 1) ``` 357 ``` ] ``` 358 359 20 ``` if not six.PY2: ``` 360 ``` # strftime does not support dates before 1900 in Python 2 ``` 361 14 ``` dates_no_day.append(date(1000, 11, 1)) ``` 362 363 ``` # Only one supported format for dates with no day ``` 364 20 ``` o = zip(dates_no_day, it.repeat('%Y-%m')) ``` 365 366 20 ``` dates_w_day = [ ``` 367 ``` date(1969, 12, 31), ``` 368 ``` date(1900, 1, 1), ``` 369 ``` date(2016, 2, 29), ``` 370 ``` date(2017, 11, 14) ``` 371 ``` ] ``` 372 373 20 ``` dates_w_day_fmts = ('%Y%m%d', '%Y-%m-%d') ``` 374 20 ``` o = it.chain(o, it.product(dates_w_day, dates_w_day_fmts)) ``` 375 376 20 ``` return list(o) ``` 377 378 379 20 ```@pytest.mark.parametrize('d,dt_fmt', __make_date_examples()) ``` 380 20 ```@pytest.mark.parametrize('as_bytes', [True, False]) ``` 381 2 ```def test_parse_isodate(d, dt_fmt, as_bytes): ``` 382 20 ``` d_str = d.strftime(dt_fmt) ``` 383 20 ``` if isinstance(d_str, six.text_type) and as_bytes: ``` 384 14 ``` d_str = d_str.encode('ascii') ``` 385 20 ``` elif isinstance(d_str, bytes) and not as_bytes: ``` 386 6 ``` d_str = d_str.decode('ascii') ``` 387 388 20 ``` iparser = isoparser() ``` 389 20 ``` assert iparser.parse_isodate(d_str) == d ``` 390 391 392 20 ```@pytest.mark.parametrize('isostr,exception', [ ``` 393 ``` ('243', ValueError), # ISO string too short ``` 394 ``` ('2014-0423', ValueError), # Inconsistent date separators ``` 395 ``` ('201404-23', ValueError), # Inconsistent date separators ``` 396 ``` ('2014日03月14', ValueError), # Not ASCII ``` 397 ``` ('2013-02-29', ValueError), # Not a leap year ``` 398 ``` ('2014/12/03', ValueError), # Wrong separators ``` 399 ``` ('2014-04-19T', ValueError), # Unknown components ``` 400 ```]) ``` 401 2 ```def test_isodate_raises(isostr, exception): ``` 402 20 ``` with pytest.raises(exception): ``` 403 20 ``` isoparser().parse_isodate(isostr) ``` 404 405 406 ```### ``` 407 ```# Test parse_isotime ``` 408 20 ```def __make_time_examples(): ``` 409 20 ``` outputs = [] ``` 410 411 ``` # HH ``` 412 20 ``` time_h = [time(0), time(8), time(22)] ``` 413 20 ``` time_h_fmts = ['%H'] ``` 414 415 20 ``` outputs.append(it.product(time_h, time_h_fmts)) ``` 416 417 ``` # HHMM / HH:MM ``` 418 20 ``` time_hm = [time(0, 0), time(0, 30), time(8, 47), time(16, 1)] ``` 419 20 ``` time_hm_fmts = ['%H%M', '%H:%M'] ``` 420 421 20 ``` outputs.append(it.product(time_hm, time_hm_fmts)) ``` 422 423 ``` # HHMMSS / HH:MM:SS ``` 424 20 ``` time_hms = [time(0, 0, 0), time(0, 15, 30), ``` 425 ``` time(8, 2, 16), time(12, 0), time(16, 2), time(20, 45)] ``` 426 427 20 ``` time_hms_fmts = ['%H%M%S', '%H:%M:%S'] ``` 428 429 20 ``` outputs.append(it.product(time_hms, time_hms_fmts)) ``` 430 431 ``` # HHMMSS.ffffff / HH:MM:SS.ffffff ``` 432 20 ``` time_hmsu = [time(0, 0, 0, 0), time(4, 15, 3, 247993), ``` 433 ``` time(14, 21, 59, 948730), ``` 434 ``` time(23, 59, 59, 999999)] ``` 435 436 20 ``` time_hmsu_fmts = ['%H%M%S.%f', '%H:%M:%S.%f'] ``` 437 438 20 ``` outputs.append(it.product(time_hmsu, time_hmsu_fmts)) ``` 439 440 20 ``` outputs = list(map(list, outputs)) ``` 441 442 ``` # Time zones ``` 443 20 ``` ex_naive = list(it.chain.from_iterable(x[0:2] for x in outputs)) ``` 444 20 ``` o = it.product(ex_naive, TZOFFSETS) # ((time, fmt), (tzinfo, offsetstr)) ``` 445 20 ``` o = ((t.replace(tzinfo=tzi), fmt + off_str) ``` 446 ``` for (t, fmt), (tzi, off_str) in o) ``` 447 448 20 ``` outputs.append(o) ``` 449 450 20 ``` return list(it.chain.from_iterable(outputs)) ``` 451 452 453 20 ```@pytest.mark.parametrize('time_val,time_fmt', __make_time_examples()) ``` 454 20 ```@pytest.mark.parametrize('as_bytes', [True, False]) ``` 455 2 ```def test_isotime(time_val, time_fmt, as_bytes): ``` 456 20 ``` tstr = time_val.strftime(time_fmt) ``` 457 20 ``` if isinstance(tstr, six.text_type) and as_bytes: ``` 458 14 ``` tstr = tstr.encode('ascii') ``` 459 20 ``` elif isinstance(tstr, bytes) and not as_bytes: ``` 460 6 ``` tstr = tstr.decode('ascii') ``` 461 462 20 ``` iparser = isoparser() ``` 463 464 20 ``` assert iparser.parse_isotime(tstr) == time_val ``` 465 466 467 20 ```@pytest.mark.parametrize('isostr', [ ``` 468 ``` '24:00', ``` 469 ``` '2400', ``` 470 ``` '24:00:00', ``` 471 ``` '240000', ``` 472 ``` '24:00:00.000', ``` 473 ``` '24:00:00,000', ``` 474 ``` '24:00:00.000000', ``` 475 ``` '24:00:00,000000', ``` 476 ```]) ``` 477 2 ```def test_isotime_midnight(isostr): ``` 478 20 ``` iparser = isoparser() ``` 479 20 ``` assert iparser.parse_isotime(isostr) == time(0, 0, 0, 0) ``` 480 481 482 20 ```@pytest.mark.parametrize('isostr,exception', [ ``` 483 ``` ('3', ValueError), # ISO string too short ``` 484 ``` ('14時30分15秒', ValueError), # Not ASCII ``` 485 ``` ('14_30_15', ValueError), # Invalid separators ``` 486 ``` ('1430:15', ValueError), # Inconsistent separator use ``` 487 ``` ('25', ValueError), # Invalid hours ``` 488 ``` ('25:15', ValueError), # Invalid hours ``` 489 ``` ('14:60', ValueError), # Invalid minutes ``` 490 ``` ('14:59:61', ValueError), # Invalid seconds ``` 491 ``` ('14:30:15.34468305:00', ValueError), # No sign in time zone ``` 492 ``` ('14:30:15+', ValueError), # Time zone too short ``` 493 ``` ('14:30:15+1234567', ValueError), # Time zone invalid ``` 494 ``` ('14:59:59+25:00', ValueError), # Invalid tz hours ``` 495 ``` ('14:59:59+12:62', ValueError), # Invalid tz minutes ``` 496 ``` ('14:59:30_344583', ValueError), # Invalid microsecond separator ``` 497 ``` ('24:01', ValueError), # 24 used for non-midnight time ``` 498 ``` ('24:00:01', ValueError), # 24 used for non-midnight time ``` 499 ``` ('24:00:00.001', ValueError), # 24 used for non-midnight time ``` 500 ``` ('24:00:00.000001', ValueError), # 24 used for non-midnight time ``` 501 ```]) ``` 502 2 ```def test_isotime_raises(isostr, exception): ``` 503 20 ``` iparser = isoparser() ``` 504 20 ``` with pytest.raises(exception): ``` 505 20 ``` iparser.parse_isotime(isostr) ``` 506 507 508 20 ```@pytest.mark.xfail() ``` 509 ```@pytest.mark.parametrize('isostr,exception', [ # pragma: nocover ``` 510 ``` ('14:3015', ValueError), # Inconsistent separator use ``` 511 ``` ('201202', ValueError) # Invalid ISO format ``` 512 ```]) ``` 513 ```def test_isotime_raises_xfail(isostr, exception): ``` 514 ``` iparser = isoparser() ``` 515 ``` with pytest.raises(exception): ``` 516 ``` iparser.parse_isotime(isostr) ```

Read our documentation on viewing source code .