Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/future/backports/datetime.py: 32%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1138 statements  

1"""Concrete date/time and related types. 

2 

3See http://www.iana.org/time-zones/repository/tz-link.html for 

4time zone and DST data sources. 

5""" 

6from __future__ import division 

7from __future__ import unicode_literals 

8from __future__ import print_function 

9from __future__ import absolute_import 

10from future.builtins import str 

11from future.builtins import bytes 

12from future.builtins import map 

13from future.builtins import round 

14from future.builtins import int 

15from future.builtins import object 

16from future.utils import native_str, PY2 

17 

18import time as _time 

19import math as _math 

20 

21def _cmp(x, y): 

22 return 0 if x == y else 1 if x > y else -1 

23 

24MINYEAR = 1 

25MAXYEAR = 9999 

26_MAXORDINAL = 3652059 # date.max.toordinal() 

27 

28# Utility functions, adapted from Python's Demo/classes/Dates.py, which 

29# also assumes the current Gregorian calendar indefinitely extended in 

30# both directions. Difference: Dates.py calls January 1 of year 0 day 

31# number 1. The code here calls January 1 of year 1 day number 1. This is 

32# to match the definition of the "proleptic Gregorian" calendar in Dershowitz 

33# and Reingold's "Calendrical Calculations", where it's the base calendar 

34# for all computations. See the book for algorithms for converting between 

35# proleptic Gregorian ordinals and many other calendar systems. 

36 

37_DAYS_IN_MONTH = [None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 

38 

39_DAYS_BEFORE_MONTH = [None] 

40dbm = 0 

41for dim in _DAYS_IN_MONTH[1:]: 

42 _DAYS_BEFORE_MONTH.append(dbm) 

43 dbm += dim 

44del dbm, dim 

45 

46def _is_leap(year): 

47 "year -> 1 if leap year, else 0." 

48 return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) 

49 

50def _days_before_year(year): 

51 "year -> number of days before January 1st of year." 

52 y = year - 1 

53 return y*365 + y//4 - y//100 + y//400 

54 

55def _days_in_month(year, month): 

56 "year, month -> number of days in that month in that year." 

57 assert 1 <= month <= 12, month 

58 if month == 2 and _is_leap(year): 

59 return 29 

60 return _DAYS_IN_MONTH[month] 

61 

62def _days_before_month(year, month): 

63 "year, month -> number of days in year preceding first day of month." 

64 assert 1 <= month <= 12, 'month must be in 1..12' 

65 return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year)) 

66 

67def _ymd2ord(year, month, day): 

68 "year, month, day -> ordinal, considering 01-Jan-0001 as day 1." 

69 assert 1 <= month <= 12, 'month must be in 1..12' 

70 dim = _days_in_month(year, month) 

71 assert 1 <= day <= dim, ('day must be in 1..%d' % dim) 

72 return (_days_before_year(year) + 

73 _days_before_month(year, month) + 

74 day) 

75 

76_DI400Y = _days_before_year(401) # number of days in 400 years 

77_DI100Y = _days_before_year(101) # " " " " 100 " 

78_DI4Y = _days_before_year(5) # " " " " 4 " 

79 

80# A 4-year cycle has an extra leap day over what we'd get from pasting 

81# together 4 single years. 

82assert _DI4Y == 4 * 365 + 1 

83 

84# Similarly, a 400-year cycle has an extra leap day over what we'd get from 

85# pasting together 4 100-year cycles. 

86assert _DI400Y == 4 * _DI100Y + 1 

87 

88# OTOH, a 100-year cycle has one fewer leap day than we'd get from 

89# pasting together 25 4-year cycles. 

90assert _DI100Y == 25 * _DI4Y - 1 

91 

92def _ord2ymd(n): 

93 "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1." 

94 

95 # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years 

96 # repeats exactly every 400 years. The basic strategy is to find the 

97 # closest 400-year boundary at or before n, then work with the offset 

98 # from that boundary to n. Life is much clearer if we subtract 1 from 

99 # n first -- then the values of n at 400-year boundaries are exactly 

100 # those divisible by _DI400Y: 

101 # 

102 # D M Y n n-1 

103 # -- --- ---- ---------- ---------------- 

104 # 31 Dec -400 -_DI400Y -_DI400Y -1 

105 # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary 

106 # ... 

107 # 30 Dec 000 -1 -2 

108 # 31 Dec 000 0 -1 

109 # 1 Jan 001 1 0 400-year boundary 

110 # 2 Jan 001 2 1 

111 # 3 Jan 001 3 2 

112 # ... 

113 # 31 Dec 400 _DI400Y _DI400Y -1 

114 # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary 

115 n -= 1 

116 n400, n = divmod(n, _DI400Y) 

117 year = n400 * 400 + 1 # ..., -399, 1, 401, ... 

118 

119 # Now n is the (non-negative) offset, in days, from January 1 of year, to 

120 # the desired date. Now compute how many 100-year cycles precede n. 

121 # Note that it's possible for n100 to equal 4! In that case 4 full 

122 # 100-year cycles precede the desired day, which implies the desired 

123 # day is December 31 at the end of a 400-year cycle. 

124 n100, n = divmod(n, _DI100Y) 

125 

126 # Now compute how many 4-year cycles precede it. 

127 n4, n = divmod(n, _DI4Y) 

128 

129 # And now how many single years. Again n1 can be 4, and again meaning 

130 # that the desired day is December 31 at the end of the 4-year cycle. 

131 n1, n = divmod(n, 365) 

132 

133 year += n100 * 100 + n4 * 4 + n1 

134 if n1 == 4 or n100 == 4: 

135 assert n == 0 

136 return year-1, 12, 31 

137 

138 # Now the year is correct, and n is the offset from January 1. We find 

139 # the month via an estimate that's either exact or one too large. 

140 leapyear = n1 == 3 and (n4 != 24 or n100 == 3) 

141 assert leapyear == _is_leap(year) 

142 month = (n + 50) >> 5 

143 preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear) 

144 if preceding > n: # estimate is too large 

145 month -= 1 

146 preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear) 

147 n -= preceding 

148 assert 0 <= n < _days_in_month(year, month) 

149 

150 # Now the year and month are correct, and n is the offset from the 

151 # start of that month: we're done! 

152 return year, month, n+1 

153 

154# Month and day names. For localized versions, see the calendar module. 

155_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", 

156 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 

157_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 

158 

159 

160def _build_struct_time(y, m, d, hh, mm, ss, dstflag): 

161 wday = (_ymd2ord(y, m, d) + 6) % 7 

162 dnum = _days_before_month(y, m) + d 

163 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag)) 

164 

165def _format_time(hh, mm, ss, us): 

166 # Skip trailing microseconds when us==0. 

167 result = "%02d:%02d:%02d" % (hh, mm, ss) 

168 if us: 

169 result += ".%06d" % us 

170 return result 

171 

172# Correctly substitute for %z and %Z escapes in strftime formats. 

173def _wrap_strftime(object, format, timetuple): 

174 # Don't call utcoffset() or tzname() unless actually needed. 

175 freplace = None # the string to use for %f 

176 zreplace = None # the string to use for %z 

177 Zreplace = None # the string to use for %Z 

178 

179 # Scan format for %z and %Z escapes, replacing as needed. 

180 newformat = [] 

181 push = newformat.append 

182 i, n = 0, len(format) 

183 while i < n: 

184 ch = format[i] 

185 i += 1 

186 if ch == '%': 

187 if i < n: 

188 ch = format[i] 

189 i += 1 

190 if ch == 'f': 

191 if freplace is None: 

192 freplace = '%06d' % getattr(object, 

193 'microsecond', 0) 

194 newformat.append(freplace) 

195 elif ch == 'z': 

196 if zreplace is None: 

197 zreplace = "" 

198 if hasattr(object, "utcoffset"): 

199 offset = object.utcoffset() 

200 if offset is not None: 

201 sign = '+' 

202 if offset.days < 0: 

203 offset = -offset 

204 sign = '-' 

205 h, m = divmod(offset, timedelta(hours=1)) 

206 assert not m % timedelta(minutes=1), "whole minute" 

207 m //= timedelta(minutes=1) 

208 zreplace = '%c%02d%02d' % (sign, h, m) 

209 assert '%' not in zreplace 

210 newformat.append(zreplace) 

211 elif ch == 'Z': 

212 if Zreplace is None: 

213 Zreplace = "" 

214 if hasattr(object, "tzname"): 

215 s = object.tzname() 

216 if s is not None: 

217 # strftime is going to have at this: escape % 

218 Zreplace = s.replace('%', '%%') 

219 newformat.append(Zreplace) 

220 else: 

221 push('%') 

222 push(ch) 

223 else: 

224 push('%') 

225 else: 

226 push(ch) 

227 newformat = "".join(newformat) 

228 return _time.strftime(newformat, timetuple) 

229 

230def _call_tzinfo_method(tzinfo, methname, tzinfoarg): 

231 if tzinfo is None: 

232 return None 

233 return getattr(tzinfo, methname)(tzinfoarg) 

234 

235# Just raise TypeError if the arg isn't None or a string. 

236def _check_tzname(name): 

237 if name is not None and not isinstance(name, str): 

238 raise TypeError("tzinfo.tzname() must return None or string, " 

239 "not '%s'" % type(name)) 

240 

241# name is the offset-producing method, "utcoffset" or "dst". 

242# offset is what it returned. 

243# If offset isn't None or timedelta, raises TypeError. 

244# If offset is None, returns None. 

245# Else offset is checked for being in range, and a whole # of minutes. 

246# If it is, its integer value is returned. Else ValueError is raised. 

247def _check_utc_offset(name, offset): 

248 assert name in ("utcoffset", "dst") 

249 if offset is None: 

250 return 

251 if not isinstance(offset, timedelta): 

252 raise TypeError("tzinfo.%s() must return None " 

253 "or timedelta, not '%s'" % (name, type(offset))) 

254 if offset % timedelta(minutes=1) or offset.microseconds: 

255 raise ValueError("tzinfo.%s() must return a whole number " 

256 "of minutes, got %s" % (name, offset)) 

257 if not -timedelta(1) < offset < timedelta(1): 

258 raise ValueError("%s()=%s, must be must be strictly between" 

259 " -timedelta(hours=24) and timedelta(hours=24)" 

260 % (name, offset)) 

261 

262def _check_date_fields(year, month, day): 

263 if not isinstance(year, int): 

264 raise TypeError('int expected') 

265 if not MINYEAR <= year <= MAXYEAR: 

266 raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year) 

267 if not 1 <= month <= 12: 

268 raise ValueError('month must be in 1..12', month) 

269 dim = _days_in_month(year, month) 

270 if not 1 <= day <= dim: 

271 raise ValueError('day must be in 1..%d' % dim, day) 

272 

273def _check_time_fields(hour, minute, second, microsecond): 

274 if not isinstance(hour, int): 

275 raise TypeError('int expected') 

276 if not 0 <= hour <= 23: 

277 raise ValueError('hour must be in 0..23', hour) 

278 if not 0 <= minute <= 59: 

279 raise ValueError('minute must be in 0..59', minute) 

280 if not 0 <= second <= 59: 

281 raise ValueError('second must be in 0..59', second) 

282 if not 0 <= microsecond <= 999999: 

283 raise ValueError('microsecond must be in 0..999999', microsecond) 

284 

285def _check_tzinfo_arg(tz): 

286 if tz is not None and not isinstance(tz, tzinfo): 

287 raise TypeError("tzinfo argument must be None or of a tzinfo subclass") 

288 

289def _cmperror(x, y): 

290 raise TypeError("can't compare '%s' to '%s'" % ( 

291 type(x).__name__, type(y).__name__)) 

292 

293class timedelta(object): 

294 """Represent the difference between two datetime objects. 

295 

296 Supported operators: 

297 

298 - add, subtract timedelta 

299 - unary plus, minus, abs 

300 - compare to timedelta 

301 - multiply, divide by int 

302 

303 In addition, datetime supports subtraction of two datetime objects 

304 returning a timedelta, and addition or subtraction of a datetime 

305 and a timedelta giving a datetime. 

306 

307 Representation: (days, seconds, microseconds). Why? Because I 

308 felt like it. 

309 """ 

310 __slots__ = '_days', '_seconds', '_microseconds' 

311 

312 def __new__(cls, days=0, seconds=0, microseconds=0, 

313 milliseconds=0, minutes=0, hours=0, weeks=0): 

314 # Doing this efficiently and accurately in C is going to be difficult 

315 # and error-prone, due to ubiquitous overflow possibilities, and that 

316 # C double doesn't have enough bits of precision to represent 

317 # microseconds over 10K years faithfully. The code here tries to make 

318 # explicit where go-fast assumptions can be relied on, in order to 

319 # guide the C implementation; it's way more convoluted than speed- 

320 # ignoring auto-overflow-to-long idiomatic Python could be. 

321 

322 # XXX Check that all inputs are ints or floats. 

323 

324 # Final values, all integer. 

325 # s and us fit in 32-bit signed ints; d isn't bounded. 

326 d = s = us = 0 

327 

328 # Normalize everything to days, seconds, microseconds. 

329 days += weeks*7 

330 seconds += minutes*60 + hours*3600 

331 microseconds += milliseconds*1000 

332 

333 # Get rid of all fractions, and normalize s and us. 

334 # Take a deep breath <wink>. 

335 if isinstance(days, float): 

336 dayfrac, days = _math.modf(days) 

337 daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.)) 

338 assert daysecondswhole == int(daysecondswhole) # can't overflow 

339 s = int(daysecondswhole) 

340 assert days == int(days) 

341 d = int(days) 

342 else: 

343 daysecondsfrac = 0.0 

344 d = days 

345 assert isinstance(daysecondsfrac, float) 

346 assert abs(daysecondsfrac) <= 1.0 

347 assert isinstance(d, int) 

348 assert abs(s) <= 24 * 3600 

349 # days isn't referenced again before redefinition 

350 

351 if isinstance(seconds, float): 

352 secondsfrac, seconds = _math.modf(seconds) 

353 assert seconds == int(seconds) 

354 seconds = int(seconds) 

355 secondsfrac += daysecondsfrac 

356 assert abs(secondsfrac) <= 2.0 

357 else: 

358 secondsfrac = daysecondsfrac 

359 # daysecondsfrac isn't referenced again 

360 assert isinstance(secondsfrac, float) 

361 assert abs(secondsfrac) <= 2.0 

362 

363 assert isinstance(seconds, int) 

364 days, seconds = divmod(seconds, 24*3600) 

365 d += days 

366 s += int(seconds) # can't overflow 

367 assert isinstance(s, int) 

368 assert abs(s) <= 2 * 24 * 3600 

369 # seconds isn't referenced again before redefinition 

370 

371 usdouble = secondsfrac * 1e6 

372 assert abs(usdouble) < 2.1e6 # exact value not critical 

373 # secondsfrac isn't referenced again 

374 

375 if isinstance(microseconds, float): 

376 microseconds += usdouble 

377 microseconds = round(microseconds, 0) 

378 seconds, microseconds = divmod(microseconds, 1e6) 

379 assert microseconds == int(microseconds) 

380 assert seconds == int(seconds) 

381 days, seconds = divmod(seconds, 24.*3600.) 

382 assert days == int(days) 

383 assert seconds == int(seconds) 

384 d += int(days) 

385 s += int(seconds) # can't overflow 

386 assert isinstance(s, int) 

387 assert abs(s) <= 3 * 24 * 3600 

388 else: 

389 seconds, microseconds = divmod(microseconds, 1000000) 

390 days, seconds = divmod(seconds, 24*3600) 

391 d += days 

392 s += int(seconds) # can't overflow 

393 assert isinstance(s, int) 

394 assert abs(s) <= 3 * 24 * 3600 

395 microseconds = float(microseconds) 

396 microseconds += usdouble 

397 microseconds = round(microseconds, 0) 

398 assert abs(s) <= 3 * 24 * 3600 

399 assert abs(microseconds) < 3.1e6 

400 

401 # Just a little bit of carrying possible for microseconds and seconds. 

402 assert isinstance(microseconds, float) 

403 assert int(microseconds) == microseconds 

404 us = int(microseconds) 

405 seconds, us = divmod(us, 1000000) 

406 s += seconds # cant't overflow 

407 assert isinstance(s, int) 

408 days, s = divmod(s, 24*3600) 

409 d += days 

410 

411 assert isinstance(d, int) 

412 assert isinstance(s, int) and 0 <= s < 24*3600 

413 assert isinstance(us, int) and 0 <= us < 1000000 

414 

415 self = object.__new__(cls) 

416 

417 self._days = d 

418 self._seconds = s 

419 self._microseconds = us 

420 if abs(d) > 999999999: 

421 raise OverflowError("timedelta # of days is too large: %d" % d) 

422 

423 return self 

424 

425 def __repr__(self): 

426 if self._microseconds: 

427 return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, 

428 self._days, 

429 self._seconds, 

430 self._microseconds) 

431 if self._seconds: 

432 return "%s(%d, %d)" % ('datetime.' + self.__class__.__name__, 

433 self._days, 

434 self._seconds) 

435 return "%s(%d)" % ('datetime.' + self.__class__.__name__, self._days) 

436 

437 def __str__(self): 

438 mm, ss = divmod(self._seconds, 60) 

439 hh, mm = divmod(mm, 60) 

440 s = "%d:%02d:%02d" % (hh, mm, ss) 

441 if self._days: 

442 def plural(n): 

443 return n, abs(n) != 1 and "s" or "" 

444 s = ("%d day%s, " % plural(self._days)) + s 

445 if self._microseconds: 

446 s = s + ".%06d" % self._microseconds 

447 return s 

448 

449 def total_seconds(self): 

450 """Total seconds in the duration.""" 

451 return ((self.days * 86400 + self.seconds)*10**6 + 

452 self.microseconds) / 10**6 

453 

454 # Read-only field accessors 

455 @property 

456 def days(self): 

457 """days""" 

458 return self._days 

459 

460 @property 

461 def seconds(self): 

462 """seconds""" 

463 return self._seconds 

464 

465 @property 

466 def microseconds(self): 

467 """microseconds""" 

468 return self._microseconds 

469 

470 def __add__(self, other): 

471 if isinstance(other, timedelta): 

472 # for CPython compatibility, we cannot use 

473 # our __class__ here, but need a real timedelta 

474 return timedelta(self._days + other._days, 

475 self._seconds + other._seconds, 

476 self._microseconds + other._microseconds) 

477 return NotImplemented 

478 

479 __radd__ = __add__ 

480 

481 def __sub__(self, other): 

482 if isinstance(other, timedelta): 

483 # for CPython compatibility, we cannot use 

484 # our __class__ here, but need a real timedelta 

485 return timedelta(self._days - other._days, 

486 self._seconds - other._seconds, 

487 self._microseconds - other._microseconds) 

488 return NotImplemented 

489 

490 def __rsub__(self, other): 

491 if isinstance(other, timedelta): 

492 return -self + other 

493 return NotImplemented 

494 

495 def __neg__(self): 

496 # for CPython compatibility, we cannot use 

497 # our __class__ here, but need a real timedelta 

498 return timedelta(-self._days, 

499 -self._seconds, 

500 -self._microseconds) 

501 

502 def __pos__(self): 

503 return self 

504 

505 def __abs__(self): 

506 if self._days < 0: 

507 return -self 

508 else: 

509 return self 

510 

511 def __mul__(self, other): 

512 if isinstance(other, int): 

513 # for CPython compatibility, we cannot use 

514 # our __class__ here, but need a real timedelta 

515 return timedelta(self._days * other, 

516 self._seconds * other, 

517 self._microseconds * other) 

518 if isinstance(other, float): 

519 a, b = other.as_integer_ratio() 

520 return self * a / b 

521 return NotImplemented 

522 

523 __rmul__ = __mul__ 

524 

525 def _to_microseconds(self): 

526 return ((self._days * (24*3600) + self._seconds) * 1000000 + 

527 self._microseconds) 

528 

529 def __floordiv__(self, other): 

530 if not isinstance(other, (int, timedelta)): 

531 return NotImplemented 

532 usec = self._to_microseconds() 

533 if isinstance(other, timedelta): 

534 return usec // other._to_microseconds() 

535 if isinstance(other, int): 

536 return timedelta(0, 0, usec // other) 

537 

538 def __truediv__(self, other): 

539 if not isinstance(other, (int, float, timedelta)): 

540 return NotImplemented 

541 usec = self._to_microseconds() 

542 if isinstance(other, timedelta): 

543 return usec / other._to_microseconds() 

544 if isinstance(other, int): 

545 return timedelta(0, 0, usec / other) 

546 if isinstance(other, float): 

547 a, b = other.as_integer_ratio() 

548 return timedelta(0, 0, b * usec / a) 

549 

550 def __mod__(self, other): 

551 if isinstance(other, timedelta): 

552 r = self._to_microseconds() % other._to_microseconds() 

553 return timedelta(0, 0, r) 

554 return NotImplemented 

555 

556 def __divmod__(self, other): 

557 if isinstance(other, timedelta): 

558 q, r = divmod(self._to_microseconds(), 

559 other._to_microseconds()) 

560 return q, timedelta(0, 0, r) 

561 return NotImplemented 

562 

563 # Comparisons of timedelta objects with other. 

564 

565 def __eq__(self, other): 

566 if isinstance(other, timedelta): 

567 return self._cmp(other) == 0 

568 else: 

569 return False 

570 

571 def __ne__(self, other): 

572 if isinstance(other, timedelta): 

573 return self._cmp(other) != 0 

574 else: 

575 return True 

576 

577 def __le__(self, other): 

578 if isinstance(other, timedelta): 

579 return self._cmp(other) <= 0 

580 else: 

581 _cmperror(self, other) 

582 

583 def __lt__(self, other): 

584 if isinstance(other, timedelta): 

585 return self._cmp(other) < 0 

586 else: 

587 _cmperror(self, other) 

588 

589 def __ge__(self, other): 

590 if isinstance(other, timedelta): 

591 return self._cmp(other) >= 0 

592 else: 

593 _cmperror(self, other) 

594 

595 def __gt__(self, other): 

596 if isinstance(other, timedelta): 

597 return self._cmp(other) > 0 

598 else: 

599 _cmperror(self, other) 

600 

601 def _cmp(self, other): 

602 assert isinstance(other, timedelta) 

603 return _cmp(self._getstate(), other._getstate()) 

604 

605 def __hash__(self): 

606 return hash(self._getstate()) 

607 

608 def __bool__(self): 

609 return (self._days != 0 or 

610 self._seconds != 0 or 

611 self._microseconds != 0) 

612 

613 # Pickle support. 

614 

615 def _getstate(self): 

616 return (self._days, self._seconds, self._microseconds) 

617 

618 def __reduce__(self): 

619 return (self.__class__, self._getstate()) 

620 

621timedelta.min = timedelta(-999999999) 

622timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59, 

623 microseconds=999999) 

624timedelta.resolution = timedelta(microseconds=1) 

625 

626class date(object): 

627 """Concrete date type. 

628 

629 Constructors: 

630 

631 __new__() 

632 fromtimestamp() 

633 today() 

634 fromordinal() 

635 

636 Operators: 

637 

638 __repr__, __str__ 

639 __cmp__, __hash__ 

640 __add__, __radd__, __sub__ (add/radd only with timedelta arg) 

641 

642 Methods: 

643 

644 timetuple() 

645 toordinal() 

646 weekday() 

647 isoweekday(), isocalendar(), isoformat() 

648 ctime() 

649 strftime() 

650 

651 Properties (readonly): 

652 year, month, day 

653 """ 

654 __slots__ = '_year', '_month', '_day' 

655 

656 def __new__(cls, year, month=None, day=None): 

657 """Constructor. 

658 

659 Arguments: 

660 

661 year, month, day (required, base 1) 

662 """ 

663 if (isinstance(year, bytes) and len(year) == 4 and 

664 1 <= year[2] <= 12 and month is None): # Month is sane 

665 # Pickle support 

666 self = object.__new__(cls) 

667 self.__setstate(year) 

668 return self 

669 _check_date_fields(year, month, day) 

670 self = object.__new__(cls) 

671 self._year = year 

672 self._month = month 

673 self._day = day 

674 return self 

675 

676 # Additional constructors 

677 

678 @classmethod 

679 def fromtimestamp(cls, t): 

680 "Construct a date from a POSIX timestamp (like time.time())." 

681 y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t) 

682 return cls(y, m, d) 

683 

684 @classmethod 

685 def today(cls): 

686 "Construct a date from time.time()." 

687 t = _time.time() 

688 return cls.fromtimestamp(t) 

689 

690 @classmethod 

691 def fromordinal(cls, n): 

692 """Construct a date from a proleptic Gregorian ordinal. 

693 

694 January 1 of year 1 is day 1. Only the year, month and day are 

695 non-zero in the result. 

696 """ 

697 y, m, d = _ord2ymd(n) 

698 return cls(y, m, d) 

699 

700 # Conversions to string 

701 

702 def __repr__(self): 

703 """Convert to formal string, for repr(). 

704 

705 >>> dt = datetime(2010, 1, 1) 

706 >>> repr(dt) 

707 'datetime.datetime(2010, 1, 1, 0, 0)' 

708 

709 >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc) 

710 >>> repr(dt) 

711 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)' 

712 """ 

713 return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, 

714 self._year, 

715 self._month, 

716 self._day) 

717 # XXX These shouldn't depend on time.localtime(), because that 

718 # clips the usable dates to [1970 .. 2038). At least ctime() is 

719 # easily done without using strftime() -- that's better too because 

720 # strftime("%c", ...) is locale specific. 

721 

722 

723 def ctime(self): 

724 "Return ctime() style string." 

725 weekday = self.toordinal() % 7 or 7 

726 return "%s %s %2d 00:00:00 %04d" % ( 

727 _DAYNAMES[weekday], 

728 _MONTHNAMES[self._month], 

729 self._day, self._year) 

730 

731 def strftime(self, fmt): 

732 "Format using strftime()." 

733 return _wrap_strftime(self, fmt, self.timetuple()) 

734 

735 def __format__(self, fmt): 

736 if len(fmt) != 0: 

737 return self.strftime(fmt) 

738 return str(self) 

739 

740 def isoformat(self): 

741 """Return the date formatted according to ISO. 

742 

743 This is 'YYYY-MM-DD'. 

744 

745 References: 

746 - http://www.w3.org/TR/NOTE-datetime 

747 - http://www.cl.cam.ac.uk/~mgk25/iso-time.html 

748 """ 

749 return "%04d-%02d-%02d" % (self._year, self._month, self._day) 

750 

751 __str__ = isoformat 

752 

753 # Read-only field accessors 

754 @property 

755 def year(self): 

756 """year (1-9999)""" 

757 return self._year 

758 

759 @property 

760 def month(self): 

761 """month (1-12)""" 

762 return self._month 

763 

764 @property 

765 def day(self): 

766 """day (1-31)""" 

767 return self._day 

768 

769 # Standard conversions, __cmp__, __hash__ (and helpers) 

770 

771 def timetuple(self): 

772 "Return local time tuple compatible with time.localtime()." 

773 return _build_struct_time(self._year, self._month, self._day, 

774 0, 0, 0, -1) 

775 

776 def toordinal(self): 

777 """Return proleptic Gregorian ordinal for the year, month and day. 

778 

779 January 1 of year 1 is day 1. Only the year, month and day values 

780 contribute to the result. 

781 """ 

782 return _ymd2ord(self._year, self._month, self._day) 

783 

784 def replace(self, year=None, month=None, day=None): 

785 """Return a new date with new values for the specified fields.""" 

786 if year is None: 

787 year = self._year 

788 if month is None: 

789 month = self._month 

790 if day is None: 

791 day = self._day 

792 _check_date_fields(year, month, day) 

793 return date(year, month, day) 

794 

795 # Comparisons of date objects with other. 

796 

797 def __eq__(self, other): 

798 if isinstance(other, date): 

799 return self._cmp(other) == 0 

800 return NotImplemented 

801 

802 def __ne__(self, other): 

803 if isinstance(other, date): 

804 return self._cmp(other) != 0 

805 return NotImplemented 

806 

807 def __le__(self, other): 

808 if isinstance(other, date): 

809 return self._cmp(other) <= 0 

810 return NotImplemented 

811 

812 def __lt__(self, other): 

813 if isinstance(other, date): 

814 return self._cmp(other) < 0 

815 return NotImplemented 

816 

817 def __ge__(self, other): 

818 if isinstance(other, date): 

819 return self._cmp(other) >= 0 

820 return NotImplemented 

821 

822 def __gt__(self, other): 

823 if isinstance(other, date): 

824 return self._cmp(other) > 0 

825 return NotImplemented 

826 

827 def _cmp(self, other): 

828 assert isinstance(other, date) 

829 y, m, d = self._year, self._month, self._day 

830 y2, m2, d2 = other._year, other._month, other._day 

831 return _cmp((y, m, d), (y2, m2, d2)) 

832 

833 def __hash__(self): 

834 "Hash." 

835 return hash(self._getstate()) 

836 

837 # Computations 

838 

839 def __add__(self, other): 

840 "Add a date to a timedelta." 

841 if isinstance(other, timedelta): 

842 o = self.toordinal() + other.days 

843 if 0 < o <= _MAXORDINAL: 

844 return date.fromordinal(o) 

845 raise OverflowError("result out of range") 

846 return NotImplemented 

847 

848 __radd__ = __add__ 

849 

850 def __sub__(self, other): 

851 """Subtract two dates, or a date and a timedelta.""" 

852 if isinstance(other, timedelta): 

853 return self + timedelta(-other.days) 

854 if isinstance(other, date): 

855 days1 = self.toordinal() 

856 days2 = other.toordinal() 

857 return timedelta(days1 - days2) 

858 return NotImplemented 

859 

860 def weekday(self): 

861 "Return day of the week, where Monday == 0 ... Sunday == 6." 

862 return (self.toordinal() + 6) % 7 

863 

864 # Day-of-the-week and week-of-the-year, according to ISO 

865 

866 def isoweekday(self): 

867 "Return day of the week, where Monday == 1 ... Sunday == 7." 

868 # 1-Jan-0001 is a Monday 

869 return self.toordinal() % 7 or 7 

870 

871 def isocalendar(self): 

872 """Return a 3-tuple containing ISO year, week number, and weekday. 

873 

874 The first ISO week of the year is the (Mon-Sun) week 

875 containing the year's first Thursday; everything else derives 

876 from that. 

877 

878 The first week is 1; Monday is 1 ... Sunday is 7. 

879 

880 ISO calendar algorithm taken from 

881 http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm 

882 """ 

883 year = self._year 

884 week1monday = _isoweek1monday(year) 

885 today = _ymd2ord(self._year, self._month, self._day) 

886 # Internally, week and day have origin 0 

887 week, day = divmod(today - week1monday, 7) 

888 if week < 0: 

889 year -= 1 

890 week1monday = _isoweek1monday(year) 

891 week, day = divmod(today - week1monday, 7) 

892 elif week >= 52: 

893 if today >= _isoweek1monday(year+1): 

894 year += 1 

895 week = 0 

896 return year, week+1, day+1 

897 

898 # Pickle support. 

899 

900 def _getstate(self): 

901 yhi, ylo = divmod(self._year, 256) 

902 return bytes([yhi, ylo, self._month, self._day]), 

903 

904 def __setstate(self, string): 

905 if len(string) != 4 or not (1 <= string[2] <= 12): 

906 raise TypeError("not enough arguments") 

907 yhi, ylo, self._month, self._day = string 

908 self._year = yhi * 256 + ylo 

909 

910 def __reduce__(self): 

911 return (self.__class__, self._getstate()) 

912 

913_date_class = date # so functions w/ args named "date" can get at the class 

914 

915date.min = date(1, 1, 1) 

916date.max = date(9999, 12, 31) 

917date.resolution = timedelta(days=1) 

918 

919class tzinfo(object): 

920 """Abstract base class for time zone info classes. 

921 

922 Subclasses must override the name(), utcoffset() and dst() methods. 

923 """ 

924 __slots__ = () 

925 def tzname(self, dt): 

926 "datetime -> string name of time zone." 

927 raise NotImplementedError("tzinfo subclass must override tzname()") 

928 

929 def utcoffset(self, dt): 

930 "datetime -> minutes east of UTC (negative for west of UTC)" 

931 raise NotImplementedError("tzinfo subclass must override utcoffset()") 

932 

933 def dst(self, dt): 

934 """datetime -> DST offset in minutes east of UTC. 

935 

936 Return 0 if DST not in effect. utcoffset() must include the DST 

937 offset. 

938 """ 

939 raise NotImplementedError("tzinfo subclass must override dst()") 

940 

941 def fromutc(self, dt): 

942 "datetime in UTC -> datetime in local time." 

943 

944 if not isinstance(dt, datetime): 

945 raise TypeError("fromutc() requires a datetime argument") 

946 if dt.tzinfo is not self: 

947 raise ValueError("dt.tzinfo is not self") 

948 

949 dtoff = dt.utcoffset() 

950 if dtoff is None: 

951 raise ValueError("fromutc() requires a non-None utcoffset() " 

952 "result") 

953 

954 # See the long comment block at the end of this file for an 

955 # explanation of this algorithm. 

956 dtdst = dt.dst() 

957 if dtdst is None: 

958 raise ValueError("fromutc() requires a non-None dst() result") 

959 delta = dtoff - dtdst 

960 if delta: 

961 dt += delta 

962 dtdst = dt.dst() 

963 if dtdst is None: 

964 raise ValueError("fromutc(): dt.dst gave inconsistent " 

965 "results; cannot convert") 

966 return dt + dtdst 

967 

968 # Pickle support. 

969 

970 def __reduce__(self): 

971 getinitargs = getattr(self, "__getinitargs__", None) 

972 if getinitargs: 

973 args = getinitargs() 

974 else: 

975 args = () 

976 getstate = getattr(self, "__getstate__", None) 

977 if getstate: 

978 state = getstate() 

979 else: 

980 state = getattr(self, "__dict__", None) or None 

981 if state is None: 

982 return (self.__class__, args) 

983 else: 

984 return (self.__class__, args, state) 

985 

986_tzinfo_class = tzinfo 

987 

988class time(object): 

989 """Time with time zone. 

990 

991 Constructors: 

992 

993 __new__() 

994 

995 Operators: 

996 

997 __repr__, __str__ 

998 __cmp__, __hash__ 

999 

1000 Methods: 

1001 

1002 strftime() 

1003 isoformat() 

1004 utcoffset() 

1005 tzname() 

1006 dst() 

1007 

1008 Properties (readonly): 

1009 hour, minute, second, microsecond, tzinfo 

1010 """ 

1011 

1012 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): 

1013 """Constructor. 

1014 

1015 Arguments: 

1016 

1017 hour, minute (required) 

1018 second, microsecond (default to zero) 

1019 tzinfo (default to None) 

1020 """ 

1021 self = object.__new__(cls) 

1022 if isinstance(hour, bytes) and len(hour) == 6: 

1023 # Pickle support 

1024 self.__setstate(hour, minute or None) 

1025 return self 

1026 _check_tzinfo_arg(tzinfo) 

1027 _check_time_fields(hour, minute, second, microsecond) 

1028 self._hour = hour 

1029 self._minute = minute 

1030 self._second = second 

1031 self._microsecond = microsecond 

1032 self._tzinfo = tzinfo 

1033 return self 

1034 

1035 # Read-only field accessors 

1036 @property 

1037 def hour(self): 

1038 """hour (0-23)""" 

1039 return self._hour 

1040 

1041 @property 

1042 def minute(self): 

1043 """minute (0-59)""" 

1044 return self._minute 

1045 

1046 @property 

1047 def second(self): 

1048 """second (0-59)""" 

1049 return self._second 

1050 

1051 @property 

1052 def microsecond(self): 

1053 """microsecond (0-999999)""" 

1054 return self._microsecond 

1055 

1056 @property 

1057 def tzinfo(self): 

1058 """timezone info object""" 

1059 return self._tzinfo 

1060 

1061 # Standard conversions, __hash__ (and helpers) 

1062 

1063 # Comparisons of time objects with other. 

1064 

1065 def __eq__(self, other): 

1066 if isinstance(other, time): 

1067 return self._cmp(other, allow_mixed=True) == 0 

1068 else: 

1069 return False 

1070 

1071 def __ne__(self, other): 

1072 if isinstance(other, time): 

1073 return self._cmp(other, allow_mixed=True) != 0 

1074 else: 

1075 return True 

1076 

1077 def __le__(self, other): 

1078 if isinstance(other, time): 

1079 return self._cmp(other) <= 0 

1080 else: 

1081 _cmperror(self, other) 

1082 

1083 def __lt__(self, other): 

1084 if isinstance(other, time): 

1085 return self._cmp(other) < 0 

1086 else: 

1087 _cmperror(self, other) 

1088 

1089 def __ge__(self, other): 

1090 if isinstance(other, time): 

1091 return self._cmp(other) >= 0 

1092 else: 

1093 _cmperror(self, other) 

1094 

1095 def __gt__(self, other): 

1096 if isinstance(other, time): 

1097 return self._cmp(other) > 0 

1098 else: 

1099 _cmperror(self, other) 

1100 

1101 def _cmp(self, other, allow_mixed=False): 

1102 assert isinstance(other, time) 

1103 mytz = self._tzinfo 

1104 ottz = other._tzinfo 

1105 myoff = otoff = None 

1106 

1107 if mytz is ottz: 

1108 base_compare = True 

1109 else: 

1110 myoff = self.utcoffset() 

1111 otoff = other.utcoffset() 

1112 base_compare = myoff == otoff 

1113 

1114 if base_compare: 

1115 return _cmp((self._hour, self._minute, self._second, 

1116 self._microsecond), 

1117 (other._hour, other._minute, other._second, 

1118 other._microsecond)) 

1119 if myoff is None or otoff is None: 

1120 if allow_mixed: 

1121 return 2 # arbitrary non-zero value 

1122 else: 

1123 raise TypeError("cannot compare naive and aware times") 

1124 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1) 

1125 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1) 

1126 return _cmp((myhhmm, self._second, self._microsecond), 

1127 (othhmm, other._second, other._microsecond)) 

1128 

1129 def __hash__(self): 

1130 """Hash.""" 

1131 tzoff = self.utcoffset() 

1132 if not tzoff: # zero or None 

1133 return hash(self._getstate()[0]) 

1134 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff, 

1135 timedelta(hours=1)) 

1136 assert not m % timedelta(minutes=1), "whole minute" 

1137 m //= timedelta(minutes=1) 

1138 if 0 <= h < 24: 

1139 return hash(time(h, m, self.second, self.microsecond)) 

1140 return hash((h, m, self.second, self.microsecond)) 

1141 

1142 # Conversion to string 

1143 

1144 def _tzstr(self, sep=":"): 

1145 """Return formatted timezone offset (+xx:xx) or None.""" 

1146 off = self.utcoffset() 

1147 if off is not None: 

1148 if off.days < 0: 

1149 sign = "-" 

1150 off = -off 

1151 else: 

1152 sign = "+" 

1153 hh, mm = divmod(off, timedelta(hours=1)) 

1154 assert not mm % timedelta(minutes=1), "whole minute" 

1155 mm //= timedelta(minutes=1) 

1156 assert 0 <= hh < 24 

1157 off = "%s%02d%s%02d" % (sign, hh, sep, mm) 

1158 return off 

1159 

1160 def __repr__(self): 

1161 """Convert to formal string, for repr().""" 

1162 if self._microsecond != 0: 

1163 s = ", %d, %d" % (self._second, self._microsecond) 

1164 elif self._second != 0: 

1165 s = ", %d" % self._second 

1166 else: 

1167 s = "" 

1168 s= "%s(%d, %d%s)" % ('datetime.' + self.__class__.__name__, 

1169 self._hour, self._minute, s) 

1170 if self._tzinfo is not None: 

1171 assert s[-1:] == ")" 

1172 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" 

1173 return s 

1174 

1175 def isoformat(self): 

1176 """Return the time formatted according to ISO. 

1177 

1178 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if 

1179 self.microsecond == 0. 

1180 """ 

1181 s = _format_time(self._hour, self._minute, self._second, 

1182 self._microsecond) 

1183 tz = self._tzstr() 

1184 if tz: 

1185 s += tz 

1186 return s 

1187 

1188 __str__ = isoformat 

1189 

1190 def strftime(self, fmt): 

1191 """Format using strftime(). The date part of the timestamp passed 

1192 to underlying strftime should not be used. 

1193 """ 

1194 # The year must be >= 1000 else Python's strftime implementation 

1195 # can raise a bogus exception. 

1196 timetuple = (1900, 1, 1, 

1197 self._hour, self._minute, self._second, 

1198 0, 1, -1) 

1199 return _wrap_strftime(self, fmt, timetuple) 

1200 

1201 def __format__(self, fmt): 

1202 if len(fmt) != 0: 

1203 return self.strftime(fmt) 

1204 return str(self) 

1205 

1206 # Timezone functions 

1207 

1208 def utcoffset(self): 

1209 """Return the timezone offset in minutes east of UTC (negative west of 

1210 UTC).""" 

1211 if self._tzinfo is None: 

1212 return None 

1213 offset = self._tzinfo.utcoffset(None) 

1214 _check_utc_offset("utcoffset", offset) 

1215 return offset 

1216 

1217 def tzname(self): 

1218 """Return the timezone name. 

1219 

1220 Note that the name is 100% informational -- there's no requirement that 

1221 it mean anything in particular. For example, "GMT", "UTC", "-500", 

1222 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. 

1223 """ 

1224 if self._tzinfo is None: 

1225 return None 

1226 name = self._tzinfo.tzname(None) 

1227 _check_tzname(name) 

1228 return name 

1229 

1230 def dst(self): 

1231 """Return 0 if DST is not in effect, or the DST offset (in minutes 

1232 eastward) if DST is in effect. 

1233 

1234 This is purely informational; the DST offset has already been added to 

1235 the UTC offset returned by utcoffset() if applicable, so there's no 

1236 need to consult dst() unless you're interested in displaying the DST 

1237 info. 

1238 """ 

1239 if self._tzinfo is None: 

1240 return None 

1241 offset = self._tzinfo.dst(None) 

1242 _check_utc_offset("dst", offset) 

1243 return offset 

1244 

1245 def replace(self, hour=None, minute=None, second=None, microsecond=None, 

1246 tzinfo=True): 

1247 """Return a new time with new values for the specified fields.""" 

1248 if hour is None: 

1249 hour = self.hour 

1250 if minute is None: 

1251 minute = self.minute 

1252 if second is None: 

1253 second = self.second 

1254 if microsecond is None: 

1255 microsecond = self.microsecond 

1256 if tzinfo is True: 

1257 tzinfo = self.tzinfo 

1258 _check_time_fields(hour, minute, second, microsecond) 

1259 _check_tzinfo_arg(tzinfo) 

1260 return time(hour, minute, second, microsecond, tzinfo) 

1261 

1262 def __bool__(self): 

1263 if self.second or self.microsecond: 

1264 return True 

1265 offset = self.utcoffset() or timedelta(0) 

1266 return timedelta(hours=self.hour, minutes=self.minute) != offset 

1267 

1268 # Pickle support. 

1269 

1270 def _getstate(self): 

1271 us2, us3 = divmod(self._microsecond, 256) 

1272 us1, us2 = divmod(us2, 256) 

1273 basestate = bytes([self._hour, self._minute, self._second, 

1274 us1, us2, us3]) 

1275 if self._tzinfo is None: 

1276 return (basestate,) 

1277 else: 

1278 return (basestate, self._tzinfo) 

1279 

1280 def __setstate(self, string, tzinfo): 

1281 if len(string) != 6 or string[0] >= 24: 

1282 raise TypeError("an integer is required") 

1283 (self._hour, self._minute, self._second, 

1284 us1, us2, us3) = string 

1285 self._microsecond = (((us1 << 8) | us2) << 8) | us3 

1286 if tzinfo is None or isinstance(tzinfo, _tzinfo_class): 

1287 self._tzinfo = tzinfo 

1288 else: 

1289 raise TypeError("bad tzinfo state arg %r" % tzinfo) 

1290 

1291 def __reduce__(self): 

1292 return (time, self._getstate()) 

1293 

1294_time_class = time # so functions w/ args named "time" can get at the class 

1295 

1296time.min = time(0, 0, 0) 

1297time.max = time(23, 59, 59, 999999) 

1298time.resolution = timedelta(microseconds=1) 

1299 

1300class datetime(date): 

1301 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) 

1302 

1303 The year, month and day arguments are required. tzinfo may be None, or an 

1304 instance of a tzinfo subclass. The remaining arguments may be ints. 

1305 """ 

1306 

1307 __slots__ = date.__slots__ + ( 

1308 '_hour', '_minute', '_second', 

1309 '_microsecond', '_tzinfo') 

1310 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, 

1311 microsecond=0, tzinfo=None): 

1312 if isinstance(year, bytes) and len(year) == 10: 

1313 # Pickle support 

1314 self = date.__new__(cls, year[:4]) 

1315 self.__setstate(year, month) 

1316 return self 

1317 _check_tzinfo_arg(tzinfo) 

1318 _check_time_fields(hour, minute, second, microsecond) 

1319 self = date.__new__(cls, year, month, day) 

1320 self._hour = hour 

1321 self._minute = minute 

1322 self._second = second 

1323 self._microsecond = microsecond 

1324 self._tzinfo = tzinfo 

1325 return self 

1326 

1327 # Read-only field accessors 

1328 @property 

1329 def hour(self): 

1330 """hour (0-23)""" 

1331 return self._hour 

1332 

1333 @property 

1334 def minute(self): 

1335 """minute (0-59)""" 

1336 return self._minute 

1337 

1338 @property 

1339 def second(self): 

1340 """second (0-59)""" 

1341 return self._second 

1342 

1343 @property 

1344 def microsecond(self): 

1345 """microsecond (0-999999)""" 

1346 return self._microsecond 

1347 

1348 @property 

1349 def tzinfo(self): 

1350 """timezone info object""" 

1351 return self._tzinfo 

1352 

1353 @classmethod 

1354 def fromtimestamp(cls, t, tz=None): 

1355 """Construct a datetime from a POSIX timestamp (like time.time()). 

1356 

1357 A timezone info object may be passed in as well. 

1358 """ 

1359 

1360 _check_tzinfo_arg(tz) 

1361 

1362 converter = _time.localtime if tz is None else _time.gmtime 

1363 

1364 t, frac = divmod(t, 1.0) 

1365 us = int(frac * 1e6) 

1366 

1367 # If timestamp is less than one microsecond smaller than a 

1368 # full second, us can be rounded up to 1000000. In this case, 

1369 # roll over to seconds, otherwise, ValueError is raised 

1370 # by the constructor. 

1371 if us == 1000000: 

1372 t += 1 

1373 us = 0 

1374 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) 

1375 ss = min(ss, 59) # clamp out leap seconds if the platform has them 

1376 result = cls(y, m, d, hh, mm, ss, us, tz) 

1377 if tz is not None: 

1378 result = tz.fromutc(result) 

1379 return result 

1380 

1381 @classmethod 

1382 def utcfromtimestamp(cls, t): 

1383 "Construct a UTC datetime from a POSIX timestamp (like time.time())." 

1384 t, frac = divmod(t, 1.0) 

1385 us = int(frac * 1e6) 

1386 

1387 # If timestamp is less than one microsecond smaller than a 

1388 # full second, us can be rounded up to 1000000. In this case, 

1389 # roll over to seconds, otherwise, ValueError is raised 

1390 # by the constructor. 

1391 if us == 1000000: 

1392 t += 1 

1393 us = 0 

1394 y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t) 

1395 ss = min(ss, 59) # clamp out leap seconds if the platform has them 

1396 return cls(y, m, d, hh, mm, ss, us) 

1397 

1398 # XXX This is supposed to do better than we *can* do by using time.time(), 

1399 # XXX if the platform supports a more accurate way. The C implementation 

1400 # XXX uses gettimeofday on platforms that have it, but that isn't 

1401 # XXX available from Python. So now() may return different results 

1402 # XXX across the implementations. 

1403 @classmethod 

1404 def now(cls, tz=None): 

1405 "Construct a datetime from time.time() and optional time zone info." 

1406 t = _time.time() 

1407 return cls.fromtimestamp(t, tz) 

1408 

1409 @classmethod 

1410 def utcnow(cls): 

1411 "Construct a UTC datetime from time.time()." 

1412 t = _time.time() 

1413 return cls.utcfromtimestamp(t) 

1414 

1415 @classmethod 

1416 def combine(cls, date, time): 

1417 "Construct a datetime from a given date and a given time." 

1418 if not isinstance(date, _date_class): 

1419 raise TypeError("date argument must be a date instance") 

1420 if not isinstance(time, _time_class): 

1421 raise TypeError("time argument must be a time instance") 

1422 return cls(date.year, date.month, date.day, 

1423 time.hour, time.minute, time.second, time.microsecond, 

1424 time.tzinfo) 

1425 

1426 def timetuple(self): 

1427 "Return local time tuple compatible with time.localtime()." 

1428 dst = self.dst() 

1429 if dst is None: 

1430 dst = -1 

1431 elif dst: 

1432 dst = 1 

1433 else: 

1434 dst = 0 

1435 return _build_struct_time(self.year, self.month, self.day, 

1436 self.hour, self.minute, self.second, 

1437 dst) 

1438 

1439 def timestamp(self): 

1440 "Return POSIX timestamp as float" 

1441 if self._tzinfo is None: 

1442 return _time.mktime((self.year, self.month, self.day, 

1443 self.hour, self.minute, self.second, 

1444 -1, -1, -1)) + self.microsecond / 1e6 

1445 else: 

1446 return (self - _EPOCH).total_seconds() 

1447 

1448 def utctimetuple(self): 

1449 "Return UTC time tuple compatible with time.gmtime()." 

1450 offset = self.utcoffset() 

1451 if offset: 

1452 self -= offset 

1453 y, m, d = self.year, self.month, self.day 

1454 hh, mm, ss = self.hour, self.minute, self.second 

1455 return _build_struct_time(y, m, d, hh, mm, ss, 0) 

1456 

1457 def date(self): 

1458 "Return the date part." 

1459 return date(self._year, self._month, self._day) 

1460 

1461 def time(self): 

1462 "Return the time part, with tzinfo None." 

1463 return time(self.hour, self.minute, self.second, self.microsecond) 

1464 

1465 def timetz(self): 

1466 "Return the time part, with same tzinfo." 

1467 return time(self.hour, self.minute, self.second, self.microsecond, 

1468 self._tzinfo) 

1469 

1470 def replace(self, year=None, month=None, day=None, hour=None, 

1471 minute=None, second=None, microsecond=None, tzinfo=True): 

1472 """Return a new datetime with new values for the specified fields.""" 

1473 if year is None: 

1474 year = self.year 

1475 if month is None: 

1476 month = self.month 

1477 if day is None: 

1478 day = self.day 

1479 if hour is None: 

1480 hour = self.hour 

1481 if minute is None: 

1482 minute = self.minute 

1483 if second is None: 

1484 second = self.second 

1485 if microsecond is None: 

1486 microsecond = self.microsecond 

1487 if tzinfo is True: 

1488 tzinfo = self.tzinfo 

1489 _check_date_fields(year, month, day) 

1490 _check_time_fields(hour, minute, second, microsecond) 

1491 _check_tzinfo_arg(tzinfo) 

1492 return datetime(year, month, day, hour, minute, second, 

1493 microsecond, tzinfo) 

1494 

1495 def astimezone(self, tz=None): 

1496 if tz is None: 

1497 if self.tzinfo is None: 

1498 raise ValueError("astimezone() requires an aware datetime") 

1499 ts = (self - _EPOCH) // timedelta(seconds=1) 

1500 localtm = _time.localtime(ts) 

1501 local = datetime(*localtm[:6]) 

1502 try: 

1503 # Extract TZ data if available 

1504 gmtoff = localtm.tm_gmtoff 

1505 zone = localtm.tm_zone 

1506 except AttributeError: 

1507 # Compute UTC offset and compare with the value implied 

1508 # by tm_isdst. If the values match, use the zone name 

1509 # implied by tm_isdst. 

1510 delta = local - datetime(*_time.gmtime(ts)[:6]) 

1511 dst = _time.daylight and localtm.tm_isdst > 0 

1512 gmtoff = -(_time.altzone if dst else _time.timezone) 

1513 if delta == timedelta(seconds=gmtoff): 

1514 tz = timezone(delta, _time.tzname[dst]) 

1515 else: 

1516 tz = timezone(delta) 

1517 else: 

1518 tz = timezone(timedelta(seconds=gmtoff), zone) 

1519 

1520 elif not isinstance(tz, tzinfo): 

1521 raise TypeError("tz argument must be an instance of tzinfo") 

1522 

1523 mytz = self.tzinfo 

1524 if mytz is None: 

1525 raise ValueError("astimezone() requires an aware datetime") 

1526 

1527 if tz is mytz: 

1528 return self 

1529 

1530 # Convert self to UTC, and attach the new time zone object. 

1531 myoffset = self.utcoffset() 

1532 if myoffset is None: 

1533 raise ValueError("astimezone() requires an aware datetime") 

1534 utc = (self - myoffset).replace(tzinfo=tz) 

1535 

1536 # Convert from UTC to tz's local time. 

1537 return tz.fromutc(utc) 

1538 

1539 # Ways to produce a string. 

1540 

1541 def ctime(self): 

1542 "Return ctime() style string." 

1543 weekday = self.toordinal() % 7 or 7 

1544 return "%s %s %2d %02d:%02d:%02d %04d" % ( 

1545 _DAYNAMES[weekday], 

1546 _MONTHNAMES[self._month], 

1547 self._day, 

1548 self._hour, self._minute, self._second, 

1549 self._year) 

1550 

1551 def isoformat(self, sep='T'): 

1552 """Return the time formatted according to ISO. 

1553 

1554 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if 

1555 self.microsecond == 0. 

1556 

1557 If self.tzinfo is not None, the UTC offset is also attached, giving 

1558 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'. 

1559 

1560 Optional argument sep specifies the separator between date and 

1561 time, default 'T'. 

1562 """ 

1563 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, 

1564 sep) + 

1565 _format_time(self._hour, self._minute, self._second, 

1566 self._microsecond)) 

1567 off = self.utcoffset() 

1568 if off is not None: 

1569 if off.days < 0: 

1570 sign = "-" 

1571 off = -off 

1572 else: 

1573 sign = "+" 

1574 hh, mm = divmod(off, timedelta(hours=1)) 

1575 assert not mm % timedelta(minutes=1), "whole minute" 

1576 mm //= timedelta(minutes=1) 

1577 s += "%s%02d:%02d" % (sign, hh, mm) 

1578 return s 

1579 

1580 def __repr__(self): 

1581 """Convert to formal string, for repr().""" 

1582 L = [self._year, self._month, self._day, # These are never zero 

1583 self._hour, self._minute, self._second, self._microsecond] 

1584 if L[-1] == 0: 

1585 del L[-1] 

1586 if L[-1] == 0: 

1587 del L[-1] 

1588 s = ", ".join(map(str, L)) 

1589 s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s) 

1590 if self._tzinfo is not None: 

1591 assert s[-1:] == ")" 

1592 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" 

1593 return s 

1594 

1595 def __str__(self): 

1596 "Convert to string, for str()." 

1597 return self.isoformat(sep=' ') 

1598 

1599 @classmethod 

1600 def strptime(cls, date_string, format): 

1601 'string, format -> new datetime parsed from a string (like time.strptime()).' 

1602 import _strptime 

1603 return _strptime._strptime_datetime(cls, date_string, format) 

1604 

1605 def utcoffset(self): 

1606 """Return the timezone offset in minutes east of UTC (negative west of 

1607 UTC).""" 

1608 if self._tzinfo is None: 

1609 return None 

1610 offset = self._tzinfo.utcoffset(self) 

1611 _check_utc_offset("utcoffset", offset) 

1612 return offset 

1613 

1614 def tzname(self): 

1615 """Return the timezone name. 

1616 

1617 Note that the name is 100% informational -- there's no requirement that 

1618 it mean anything in particular. For example, "GMT", "UTC", "-500", 

1619 "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. 

1620 """ 

1621 name = _call_tzinfo_method(self._tzinfo, "tzname", self) 

1622 _check_tzname(name) 

1623 return name 

1624 

1625 def dst(self): 

1626 """Return 0 if DST is not in effect, or the DST offset (in minutes 

1627 eastward) if DST is in effect. 

1628 

1629 This is purely informational; the DST offset has already been added to 

1630 the UTC offset returned by utcoffset() if applicable, so there's no 

1631 need to consult dst() unless you're interested in displaying the DST 

1632 info. 

1633 """ 

1634 if self._tzinfo is None: 

1635 return None 

1636 offset = self._tzinfo.dst(self) 

1637 _check_utc_offset("dst", offset) 

1638 return offset 

1639 

1640 # Comparisons of datetime objects with other. 

1641 

1642 def __eq__(self, other): 

1643 if isinstance(other, datetime): 

1644 return self._cmp(other, allow_mixed=True) == 0 

1645 elif not isinstance(other, date): 

1646 return NotImplemented 

1647 else: 

1648 return False 

1649 

1650 def __ne__(self, other): 

1651 if isinstance(other, datetime): 

1652 return self._cmp(other, allow_mixed=True) != 0 

1653 elif not isinstance(other, date): 

1654 return NotImplemented 

1655 else: 

1656 return True 

1657 

1658 def __le__(self, other): 

1659 if isinstance(other, datetime): 

1660 return self._cmp(other) <= 0 

1661 elif not isinstance(other, date): 

1662 return NotImplemented 

1663 else: 

1664 _cmperror(self, other) 

1665 

1666 def __lt__(self, other): 

1667 if isinstance(other, datetime): 

1668 return self._cmp(other) < 0 

1669 elif not isinstance(other, date): 

1670 return NotImplemented 

1671 else: 

1672 _cmperror(self, other) 

1673 

1674 def __ge__(self, other): 

1675 if isinstance(other, datetime): 

1676 return self._cmp(other) >= 0 

1677 elif not isinstance(other, date): 

1678 return NotImplemented 

1679 else: 

1680 _cmperror(self, other) 

1681 

1682 def __gt__(self, other): 

1683 if isinstance(other, datetime): 

1684 return self._cmp(other) > 0 

1685 elif not isinstance(other, date): 

1686 return NotImplemented 

1687 else: 

1688 _cmperror(self, other) 

1689 

1690 def _cmp(self, other, allow_mixed=False): 

1691 assert isinstance(other, datetime) 

1692 mytz = self._tzinfo 

1693 ottz = other._tzinfo 

1694 myoff = otoff = None 

1695 

1696 if mytz is ottz: 

1697 base_compare = True 

1698 else: 

1699 myoff = self.utcoffset() 

1700 otoff = other.utcoffset() 

1701 base_compare = myoff == otoff 

1702 

1703 if base_compare: 

1704 return _cmp((self._year, self._month, self._day, 

1705 self._hour, self._minute, self._second, 

1706 self._microsecond), 

1707 (other._year, other._month, other._day, 

1708 other._hour, other._minute, other._second, 

1709 other._microsecond)) 

1710 if myoff is None or otoff is None: 

1711 if allow_mixed: 

1712 return 2 # arbitrary non-zero value 

1713 else: 

1714 raise TypeError("cannot compare naive and aware datetimes") 

1715 # XXX What follows could be done more efficiently... 

1716 diff = self - other # this will take offsets into account 

1717 if diff.days < 0: 

1718 return -1 

1719 return diff and 1 or 0 

1720 

1721 def __add__(self, other): 

1722 "Add a datetime and a timedelta." 

1723 if not isinstance(other, timedelta): 

1724 return NotImplemented 

1725 delta = timedelta(self.toordinal(), 

1726 hours=self._hour, 

1727 minutes=self._minute, 

1728 seconds=self._second, 

1729 microseconds=self._microsecond) 

1730 delta += other 

1731 hour, rem = divmod(delta.seconds, 3600) 

1732 minute, second = divmod(rem, 60) 

1733 if 0 < delta.days <= _MAXORDINAL: 

1734 return datetime.combine(date.fromordinal(delta.days), 

1735 time(hour, minute, second, 

1736 delta.microseconds, 

1737 tzinfo=self._tzinfo)) 

1738 raise OverflowError("result out of range") 

1739 

1740 __radd__ = __add__ 

1741 

1742 def __sub__(self, other): 

1743 "Subtract two datetimes, or a datetime and a timedelta." 

1744 if not isinstance(other, datetime): 

1745 if isinstance(other, timedelta): 

1746 return self + -other 

1747 return NotImplemented 

1748 

1749 days1 = self.toordinal() 

1750 days2 = other.toordinal() 

1751 secs1 = self._second + self._minute * 60 + self._hour * 3600 

1752 secs2 = other._second + other._minute * 60 + other._hour * 3600 

1753 base = timedelta(days1 - days2, 

1754 secs1 - secs2, 

1755 self._microsecond - other._microsecond) 

1756 if self._tzinfo is other._tzinfo: 

1757 return base 

1758 myoff = self.utcoffset() 

1759 otoff = other.utcoffset() 

1760 if myoff == otoff: 

1761 return base 

1762 if myoff is None or otoff is None: 

1763 raise TypeError("cannot mix naive and timezone-aware time") 

1764 return base + otoff - myoff 

1765 

1766 def __hash__(self): 

1767 tzoff = self.utcoffset() 

1768 if tzoff is None: 

1769 return hash(self._getstate()[0]) 

1770 days = _ymd2ord(self.year, self.month, self.day) 

1771 seconds = self.hour * 3600 + self.minute * 60 + self.second 

1772 return hash(timedelta(days, seconds, self.microsecond) - tzoff) 

1773 

1774 # Pickle support. 

1775 

1776 def _getstate(self): 

1777 yhi, ylo = divmod(self._year, 256) 

1778 us2, us3 = divmod(self._microsecond, 256) 

1779 us1, us2 = divmod(us2, 256) 

1780 basestate = bytes([yhi, ylo, self._month, self._day, 

1781 self._hour, self._minute, self._second, 

1782 us1, us2, us3]) 

1783 if self._tzinfo is None: 

1784 return (basestate,) 

1785 else: 

1786 return (basestate, self._tzinfo) 

1787 

1788 def __setstate(self, string, tzinfo): 

1789 (yhi, ylo, self._month, self._day, self._hour, 

1790 self._minute, self._second, us1, us2, us3) = string 

1791 self._year = yhi * 256 + ylo 

1792 self._microsecond = (((us1 << 8) | us2) << 8) | us3 

1793 if tzinfo is None or isinstance(tzinfo, _tzinfo_class): 

1794 self._tzinfo = tzinfo 

1795 else: 

1796 raise TypeError("bad tzinfo state arg %r" % tzinfo) 

1797 

1798 def __reduce__(self): 

1799 return (self.__class__, self._getstate()) 

1800 

1801 

1802datetime.min = datetime(1, 1, 1) 

1803datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) 

1804datetime.resolution = timedelta(microseconds=1) 

1805 

1806 

1807def _isoweek1monday(year): 

1808 # Helper to calculate the day number of the Monday starting week 1 

1809 # XXX This could be done more efficiently 

1810 THURSDAY = 3 

1811 firstday = _ymd2ord(year, 1, 1) 

1812 firstweekday = (firstday + 6) % 7 # See weekday() above 

1813 week1monday = firstday - firstweekday 

1814 if firstweekday > THURSDAY: 

1815 week1monday += 7 

1816 return week1monday 

1817 

1818class timezone(tzinfo): 

1819 __slots__ = '_offset', '_name' 

1820 

1821 # Sentinel value to disallow None 

1822 _Omitted = object() 

1823 def __new__(cls, offset, name=_Omitted): 

1824 if not isinstance(offset, timedelta): 

1825 raise TypeError("offset must be a timedelta") 

1826 if name is cls._Omitted: 

1827 if not offset: 

1828 return cls.utc 

1829 name = None 

1830 elif not isinstance(name, str): 

1831 ### 

1832 # For Python-Future: 

1833 if PY2 and isinstance(name, native_str): 

1834 name = name.decode() 

1835 else: 

1836 raise TypeError("name must be a string") 

1837 ### 

1838 if not cls._minoffset <= offset <= cls._maxoffset: 

1839 raise ValueError("offset must be a timedelta" 

1840 " strictly between -timedelta(hours=24) and" 

1841 " timedelta(hours=24).") 

1842 if (offset.microseconds != 0 or 

1843 offset.seconds % 60 != 0): 

1844 raise ValueError("offset must be a timedelta" 

1845 " representing a whole number of minutes") 

1846 return cls._create(offset, name) 

1847 

1848 @classmethod 

1849 def _create(cls, offset, name=None): 

1850 self = tzinfo.__new__(cls) 

1851 self._offset = offset 

1852 self._name = name 

1853 return self 

1854 

1855 def __getinitargs__(self): 

1856 """pickle support""" 

1857 if self._name is None: 

1858 return (self._offset,) 

1859 return (self._offset, self._name) 

1860 

1861 def __eq__(self, other): 

1862 if type(other) != timezone: 

1863 return False 

1864 return self._offset == other._offset 

1865 

1866 def __hash__(self): 

1867 return hash(self._offset) 

1868 

1869 def __repr__(self): 

1870 """Convert to formal string, for repr(). 

1871 

1872 >>> tz = timezone.utc 

1873 >>> repr(tz) 

1874 'datetime.timezone.utc' 

1875 >>> tz = timezone(timedelta(hours=-5), 'EST') 

1876 >>> repr(tz) 

1877 "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')" 

1878 """ 

1879 if self is self.utc: 

1880 return 'datetime.timezone.utc' 

1881 if self._name is None: 

1882 return "%s(%r)" % ('datetime.' + self.__class__.__name__, 

1883 self._offset) 

1884 return "%s(%r, %r)" % ('datetime.' + self.__class__.__name__, 

1885 self._offset, self._name) 

1886 

1887 def __str__(self): 

1888 return self.tzname(None) 

1889 

1890 def utcoffset(self, dt): 

1891 if isinstance(dt, datetime) or dt is None: 

1892 return self._offset 

1893 raise TypeError("utcoffset() argument must be a datetime instance" 

1894 " or None") 

1895 

1896 def tzname(self, dt): 

1897 if isinstance(dt, datetime) or dt is None: 

1898 if self._name is None: 

1899 return self._name_from_offset(self._offset) 

1900 return self._name 

1901 raise TypeError("tzname() argument must be a datetime instance" 

1902 " or None") 

1903 

1904 def dst(self, dt): 

1905 if isinstance(dt, datetime) or dt is None: 

1906 return None 

1907 raise TypeError("dst() argument must be a datetime instance" 

1908 " or None") 

1909 

1910 def fromutc(self, dt): 

1911 if isinstance(dt, datetime): 

1912 if dt.tzinfo is not self: 

1913 raise ValueError("fromutc: dt.tzinfo " 

1914 "is not self") 

1915 return dt + self._offset 

1916 raise TypeError("fromutc() argument must be a datetime instance" 

1917 " or None") 

1918 

1919 _maxoffset = timedelta(hours=23, minutes=59) 

1920 _minoffset = -_maxoffset 

1921 

1922 @staticmethod 

1923 def _name_from_offset(delta): 

1924 if delta < timedelta(0): 

1925 sign = '-' 

1926 delta = -delta 

1927 else: 

1928 sign = '+' 

1929 hours, rest = divmod(delta, timedelta(hours=1)) 

1930 minutes = rest // timedelta(minutes=1) 

1931 return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes) 

1932 

1933timezone.utc = timezone._create(timedelta(0)) 

1934timezone.min = timezone._create(timezone._minoffset) 

1935timezone.max = timezone._create(timezone._maxoffset) 

1936_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc) 

1937""" 

1938Some time zone algebra. For a datetime x, let 

1939 x.n = x stripped of its timezone -- its naive time. 

1940 x.o = x.utcoffset(), and assuming that doesn't raise an exception or 

1941 return None 

1942 x.d = x.dst(), and assuming that doesn't raise an exception or 

1943 return None 

1944 x.s = x's standard offset, x.o - x.d 

1945 

1946Now some derived rules, where k is a duration (timedelta). 

1947 

19481. x.o = x.s + x.d 

1949 This follows from the definition of x.s. 

1950 

19512. If x and y have the same tzinfo member, x.s = y.s. 

1952 This is actually a requirement, an assumption we need to make about 

1953 sane tzinfo classes. 

1954 

19553. The naive UTC time corresponding to x is x.n - x.o. 

1956 This is again a requirement for a sane tzinfo class. 

1957 

19584. (x+k).s = x.s 

1959 This follows from #2, and that datimetimetz+timedelta preserves tzinfo. 

1960 

19615. (x+k).n = x.n + k 

1962 Again follows from how arithmetic is defined. 

1963 

1964Now we can explain tz.fromutc(x). Let's assume it's an interesting case 

1965(meaning that the various tzinfo methods exist, and don't blow up or return 

1966None when called). 

1967 

1968The function wants to return a datetime y with timezone tz, equivalent to x. 

1969x is already in UTC. 

1970 

1971By #3, we want 

1972 

1973 y.n - y.o = x.n [1] 

1974 

1975The algorithm starts by attaching tz to x.n, and calling that y. So 

1976x.n = y.n at the start. Then it wants to add a duration k to y, so that [1] 

1977becomes true; in effect, we want to solve [2] for k: 

1978 

1979 (y+k).n - (y+k).o = x.n [2] 

1980 

1981By #1, this is the same as 

1982 

1983 (y+k).n - ((y+k).s + (y+k).d) = x.n [3] 

1984 

1985By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start. 

1986Substituting that into [3], 

1987 

1988 x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving 

1989 k - (y+k).s - (y+k).d = 0; rearranging, 

1990 k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so 

1991 k = y.s - (y+k).d 

1992 

1993On the RHS, (y+k).d can't be computed directly, but y.s can be, and we 

1994approximate k by ignoring the (y+k).d term at first. Note that k can't be 

1995very large, since all offset-returning methods return a duration of magnitude 

1996less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must 

1997be 0, so ignoring it has no consequence then. 

1998 

1999In any case, the new value is 

2000 

2001 z = y + y.s [4] 

2002 

2003It's helpful to step back at look at [4] from a higher level: it's simply 

2004mapping from UTC to tz's standard time. 

2005 

2006At this point, if 

2007 

2008 z.n - z.o = x.n [5] 

2009 

2010we have an equivalent time, and are almost done. The insecurity here is 

2011at the start of daylight time. Picture US Eastern for concreteness. The wall 

2012time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good 

2013sense then. The docs ask that an Eastern tzinfo class consider such a time to 

2014be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST 

2015on the day DST starts. We want to return the 1:MM EST spelling because that's 

2016the only spelling that makes sense on the local wall clock. 

2017 

2018In fact, if [5] holds at this point, we do have the standard-time spelling, 

2019but that takes a bit of proof. We first prove a stronger result. What's the 

2020difference between the LHS and RHS of [5]? Let 

2021 

2022 diff = x.n - (z.n - z.o) [6] 

2023 

2024Now 

2025 z.n = by [4] 

2026 (y + y.s).n = by #5 

2027 y.n + y.s = since y.n = x.n 

2028 x.n + y.s = since z and y are have the same tzinfo member, 

2029 y.s = z.s by #2 

2030 x.n + z.s 

2031 

2032Plugging that back into [6] gives 

2033 

2034 diff = 

2035 x.n - ((x.n + z.s) - z.o) = expanding 

2036 x.n - x.n - z.s + z.o = cancelling 

2037 - z.s + z.o = by #2 

2038 z.d 

2039 

2040So diff = z.d. 

2041 

2042If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time 

2043spelling we wanted in the endcase described above. We're done. Contrarily, 

2044if z.d = 0, then we have a UTC equivalent, and are also done. 

2045 

2046If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to 

2047add to z (in effect, z is in tz's standard time, and we need to shift the 

2048local clock into tz's daylight time). 

2049 

2050Let 

2051 

2052 z' = z + z.d = z + diff [7] 

2053 

2054and we can again ask whether 

2055 

2056 z'.n - z'.o = x.n [8] 

2057 

2058If so, we're done. If not, the tzinfo class is insane, according to the 

2059assumptions we've made. This also requires a bit of proof. As before, let's 

2060compute the difference between the LHS and RHS of [8] (and skipping some of 

2061the justifications for the kinds of substitutions we've done several times 

2062already): 

2063 

2064 diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7] 

2065 x.n - (z.n + diff - z'.o) = replacing diff via [6] 

2066 x.n - (z.n + x.n - (z.n - z.o) - z'.o) = 

2067 x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n 

2068 - z.n + z.n - z.o + z'.o = cancel z.n 

2069 - z.o + z'.o = #1 twice 

2070 -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo 

2071 z'.d - z.d 

2072 

2073So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal, 

2074we've found the UTC-equivalent so are done. In fact, we stop with [7] and 

2075return z', not bothering to compute z'.d. 

2076 

2077How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by 

2078a dst() offset, and starting *from* a time already in DST (we know z.d != 0), 

2079would have to change the result dst() returns: we start in DST, and moving 

2080a little further into it takes us out of DST. 

2081 

2082There isn't a sane case where this can happen. The closest it gets is at 

2083the end of DST, where there's an hour in UTC with no spelling in a hybrid 

2084tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During 

2085that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM 

2086UTC) because the docs insist on that, but 0:MM is taken as being in daylight 

2087time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local 

2088clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in 

2089standard time. Since that's what the local clock *does*, we want to map both 

2090UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous 

2091in local time, but so it goes -- it's the way the local clock works. 

2092 

2093When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0, 

2094so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going. 

2095z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8] 

2096(correctly) concludes that z' is not UTC-equivalent to x. 

2097 

2098Because we know z.d said z was in daylight time (else [5] would have held and 

2099we would have stopped then), and we know z.d != z'.d (else [8] would have held 

2100and we have stopped then), and there are only 2 possible values dst() can 

2101return in Eastern, it follows that z'.d must be 0 (which it is in the example, 

2102but the reasoning doesn't depend on the example -- it depends on there being 

2103two possible dst() outcomes, one zero and the other non-zero). Therefore 

2104z' must be in standard time, and is the spelling we want in this case. 

2105 

2106Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is 

2107concerned (because it takes z' as being in standard time rather than the 

2108daylight time we intend here), but returning it gives the real-life "local 

2109clock repeats an hour" behavior when mapping the "unspellable" UTC hour into 

2110tz. 

2111 

2112When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with 

2113the 1:MM standard time spelling we want. 

2114 

2115So how can this break? One of the assumptions must be violated. Two 

2116possibilities: 

2117 

21181) [2] effectively says that y.s is invariant across all y belong to a given 

2119 time zone. This isn't true if, for political reasons or continental drift, 

2120 a region decides to change its base offset from UTC. 

2121 

21222) There may be versions of "double daylight" time where the tail end of 

2123 the analysis gives up a step too early. I haven't thought about that 

2124 enough to say. 

2125 

2126In any case, it's clear that the default fromutc() is strong enough to handle 

2127"almost all" time zones: so long as the standard offset is invariant, it 

2128doesn't matter if daylight time transition points change from year to year, or 

2129if daylight time is skipped in some years; it doesn't matter how large or 

2130small dst() may get within its bounds; and it doesn't even matter if some 

2131perverse time zone returns a negative dst()). So a breaking case must be 

2132pretty bizarre, and a tzinfo subclass can override fromutc() if it is. 

2133""" 

2134try: 

2135 from _datetime import * 

2136except ImportError: 

2137 pass 

2138else: 

2139 # Clean up unused names 

2140 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, 

2141 _DI100Y, _DI400Y, _DI4Y, _MAXORDINAL, _MONTHNAMES, 

2142 _build_struct_time, _call_tzinfo_method, _check_date_fields, 

2143 _check_time_fields, _check_tzinfo_arg, _check_tzname, 

2144 _check_utc_offset, _cmp, _cmperror, _date_class, _days_before_month, 

2145 _days_before_year, _days_in_month, _format_time, _is_leap, 

2146 _isoweek1monday, _math, _ord2ymd, _time, _time_class, _tzinfo_class, 

2147 _wrap_strftime, _ymd2ord) 

2148 # XXX Since import * above excludes names that start with _, 

2149 # docstring does not get overwritten. In the future, it may be 

2150 # appropriate to maintain a single module level docstring and 

2151 # remove the following line. 

2152 from _datetime import __doc__