datetime.py 90 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639
  1. """Concrete date/time and related types.
  2. See http://www.iana.org/time-zones/repository/tz-link.html for
  3. time zone and DST data sources.
  4. """
  5. __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
  6. "MINYEAR", "MAXYEAR", "UTC")
  7. import time as _time
  8. import math as _math
  9. import sys
  10. from operator import index as _index
  11. def _cmp(x, y):
  12. return 0 if x == y else 1 if x > y else -1
  13. MINYEAR = 1
  14. MAXYEAR = 9999
  15. _MAXORDINAL = 3652059 # date.max.toordinal()
  16. # Utility functions, adapted from Python's Demo/classes/Dates.py, which
  17. # also assumes the current Gregorian calendar indefinitely extended in
  18. # both directions. Difference: Dates.py calls January 1 of year 0 day
  19. # number 1. The code here calls January 1 of year 1 day number 1. This is
  20. # to match the definition of the "proleptic Gregorian" calendar in Dershowitz
  21. # and Reingold's "Calendrical Calculations", where it's the base calendar
  22. # for all computations. See the book for algorithms for converting between
  23. # proleptic Gregorian ordinals and many other calendar systems.
  24. # -1 is a placeholder for indexing purposes.
  25. _DAYS_IN_MONTH = [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  26. _DAYS_BEFORE_MONTH = [-1] # -1 is a placeholder for indexing purposes.
  27. dbm = 0
  28. for dim in _DAYS_IN_MONTH[1:]:
  29. _DAYS_BEFORE_MONTH.append(dbm)
  30. dbm += dim
  31. del dbm, dim
  32. def _is_leap(year):
  33. "year -> 1 if leap year, else 0."
  34. return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
  35. def _days_before_year(year):
  36. "year -> number of days before January 1st of year."
  37. y = year - 1
  38. return y*365 + y//4 - y//100 + y//400
  39. def _days_in_month(year, month):
  40. "year, month -> number of days in that month in that year."
  41. assert 1 <= month <= 12, month
  42. if month == 2 and _is_leap(year):
  43. return 29
  44. return _DAYS_IN_MONTH[month]
  45. def _days_before_month(year, month):
  46. "year, month -> number of days in year preceding first day of month."
  47. assert 1 <= month <= 12, 'month must be in 1..12'
  48. return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year))
  49. def _ymd2ord(year, month, day):
  50. "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
  51. assert 1 <= month <= 12, 'month must be in 1..12'
  52. dim = _days_in_month(year, month)
  53. assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
  54. return (_days_before_year(year) +
  55. _days_before_month(year, month) +
  56. day)
  57. _DI400Y = _days_before_year(401) # number of days in 400 years
  58. _DI100Y = _days_before_year(101) # " " " " 100 "
  59. _DI4Y = _days_before_year(5) # " " " " 4 "
  60. # A 4-year cycle has an extra leap day over what we'd get from pasting
  61. # together 4 single years.
  62. assert _DI4Y == 4 * 365 + 1
  63. # Similarly, a 400-year cycle has an extra leap day over what we'd get from
  64. # pasting together 4 100-year cycles.
  65. assert _DI400Y == 4 * _DI100Y + 1
  66. # OTOH, a 100-year cycle has one fewer leap day than we'd get from
  67. # pasting together 25 4-year cycles.
  68. assert _DI100Y == 25 * _DI4Y - 1
  69. def _ord2ymd(n):
  70. "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
  71. # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years
  72. # repeats exactly every 400 years. The basic strategy is to find the
  73. # closest 400-year boundary at or before n, then work with the offset
  74. # from that boundary to n. Life is much clearer if we subtract 1 from
  75. # n first -- then the values of n at 400-year boundaries are exactly
  76. # those divisible by _DI400Y:
  77. #
  78. # D M Y n n-1
  79. # -- --- ---- ---------- ----------------
  80. # 31 Dec -400 -_DI400Y -_DI400Y -1
  81. # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary
  82. # ...
  83. # 30 Dec 000 -1 -2
  84. # 31 Dec 000 0 -1
  85. # 1 Jan 001 1 0 400-year boundary
  86. # 2 Jan 001 2 1
  87. # 3 Jan 001 3 2
  88. # ...
  89. # 31 Dec 400 _DI400Y _DI400Y -1
  90. # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary
  91. n -= 1
  92. n400, n = divmod(n, _DI400Y)
  93. year = n400 * 400 + 1 # ..., -399, 1, 401, ...
  94. # Now n is the (non-negative) offset, in days, from January 1 of year, to
  95. # the desired date. Now compute how many 100-year cycles precede n.
  96. # Note that it's possible for n100 to equal 4! In that case 4 full
  97. # 100-year cycles precede the desired day, which implies the desired
  98. # day is December 31 at the end of a 400-year cycle.
  99. n100, n = divmod(n, _DI100Y)
  100. # Now compute how many 4-year cycles precede it.
  101. n4, n = divmod(n, _DI4Y)
  102. # And now how many single years. Again n1 can be 4, and again meaning
  103. # that the desired day is December 31 at the end of the 4-year cycle.
  104. n1, n = divmod(n, 365)
  105. year += n100 * 100 + n4 * 4 + n1
  106. if n1 == 4 or n100 == 4:
  107. assert n == 0
  108. return year-1, 12, 31
  109. # Now the year is correct, and n is the offset from January 1. We find
  110. # the month via an estimate that's either exact or one too large.
  111. leapyear = n1 == 3 and (n4 != 24 or n100 == 3)
  112. assert leapyear == _is_leap(year)
  113. month = (n + 50) >> 5
  114. preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear)
  115. if preceding > n: # estimate is too large
  116. month -= 1
  117. preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear)
  118. n -= preceding
  119. assert 0 <= n < _days_in_month(year, month)
  120. # Now the year and month are correct, and n is the offset from the
  121. # start of that month: we're done!
  122. return year, month, n+1
  123. # Month and day names. For localized versions, see the calendar module.
  124. _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  125. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  126. _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  127. def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
  128. wday = (_ymd2ord(y, m, d) + 6) % 7
  129. dnum = _days_before_month(y, m) + d
  130. return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
  131. def _format_time(hh, mm, ss, us, timespec='auto'):
  132. specs = {
  133. 'hours': '{:02d}',
  134. 'minutes': '{:02d}:{:02d}',
  135. 'seconds': '{:02d}:{:02d}:{:02d}',
  136. 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
  137. 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
  138. }
  139. if timespec == 'auto':
  140. # Skip trailing microseconds when us==0.
  141. timespec = 'microseconds' if us else 'seconds'
  142. elif timespec == 'milliseconds':
  143. us //= 1000
  144. try:
  145. fmt = specs[timespec]
  146. except KeyError:
  147. raise ValueError('Unknown timespec value')
  148. else:
  149. return fmt.format(hh, mm, ss, us)
  150. def _format_offset(off):
  151. s = ''
  152. if off is not None:
  153. if off.days < 0:
  154. sign = "-"
  155. off = -off
  156. else:
  157. sign = "+"
  158. hh, mm = divmod(off, timedelta(hours=1))
  159. mm, ss = divmod(mm, timedelta(minutes=1))
  160. s += "%s%02d:%02d" % (sign, hh, mm)
  161. if ss or ss.microseconds:
  162. s += ":%02d" % ss.seconds
  163. if ss.microseconds:
  164. s += '.%06d' % ss.microseconds
  165. return s
  166. # Correctly substitute for %z and %Z escapes in strftime formats.
  167. def _wrap_strftime(object, format, timetuple):
  168. # Don't call utcoffset() or tzname() unless actually needed.
  169. freplace = None # the string to use for %f
  170. zreplace = None # the string to use for %z
  171. Zreplace = None # the string to use for %Z
  172. # Scan format for %z and %Z escapes, replacing as needed.
  173. newformat = []
  174. push = newformat.append
  175. i, n = 0, len(format)
  176. while i < n:
  177. ch = format[i]
  178. i += 1
  179. if ch == '%':
  180. if i < n:
  181. ch = format[i]
  182. i += 1
  183. if ch == 'f':
  184. if freplace is None:
  185. freplace = '%06d' % getattr(object,
  186. 'microsecond', 0)
  187. newformat.append(freplace)
  188. elif ch == 'z':
  189. if zreplace is None:
  190. zreplace = ""
  191. if hasattr(object, "utcoffset"):
  192. offset = object.utcoffset()
  193. if offset is not None:
  194. sign = '+'
  195. if offset.days < 0:
  196. offset = -offset
  197. sign = '-'
  198. h, rest = divmod(offset, timedelta(hours=1))
  199. m, rest = divmod(rest, timedelta(minutes=1))
  200. s = rest.seconds
  201. u = offset.microseconds
  202. if u:
  203. zreplace = '%c%02d%02d%02d.%06d' % (sign, h, m, s, u)
  204. elif s:
  205. zreplace = '%c%02d%02d%02d' % (sign, h, m, s)
  206. else:
  207. zreplace = '%c%02d%02d' % (sign, h, m)
  208. assert '%' not in zreplace
  209. newformat.append(zreplace)
  210. elif ch == 'Z':
  211. if Zreplace is None:
  212. Zreplace = ""
  213. if hasattr(object, "tzname"):
  214. s = object.tzname()
  215. if s is not None:
  216. # strftime is going to have at this: escape %
  217. Zreplace = s.replace('%', '%%')
  218. newformat.append(Zreplace)
  219. else:
  220. push('%')
  221. push(ch)
  222. else:
  223. push('%')
  224. else:
  225. push(ch)
  226. newformat = "".join(newformat)
  227. return _time.strftime(newformat, timetuple)
  228. # Helpers for parsing the result of isoformat()
  229. def _is_ascii_digit(c):
  230. return c in "0123456789"
  231. def _find_isoformat_datetime_separator(dtstr):
  232. # See the comment in _datetimemodule.c:_find_isoformat_datetime_separator
  233. len_dtstr = len(dtstr)
  234. if len_dtstr == 7:
  235. return 7
  236. assert len_dtstr > 7
  237. date_separator = "-"
  238. week_indicator = "W"
  239. if dtstr[4] == date_separator:
  240. if dtstr[5] == week_indicator:
  241. if len_dtstr < 8:
  242. raise ValueError("Invalid ISO string")
  243. if len_dtstr > 8 and dtstr[8] == date_separator:
  244. if len_dtstr == 9:
  245. raise ValueError("Invalid ISO string")
  246. if len_dtstr > 10 and _is_ascii_digit(dtstr[10]):
  247. # This is as far as we need to resolve the ambiguity for
  248. # the moment - if we have YYYY-Www-##, the separator is
  249. # either a hyphen at 8 or a number at 10.
  250. #
  251. # We'll assume it's a hyphen at 8 because it's way more
  252. # likely that someone will use a hyphen as a separator than
  253. # a number, but at this point it's really best effort
  254. # because this is an extension of the spec anyway.
  255. # TODO(pganssle): Document this
  256. return 8
  257. return 10
  258. else:
  259. # YYYY-Www (8)
  260. return 8
  261. else:
  262. # YYYY-MM-DD (10)
  263. return 10
  264. else:
  265. if dtstr[4] == week_indicator:
  266. # YYYYWww (7) or YYYYWwwd (8)
  267. idx = 7
  268. while idx < len_dtstr:
  269. if not _is_ascii_digit(dtstr[idx]):
  270. break
  271. idx += 1
  272. if idx < 9:
  273. return idx
  274. if idx % 2 == 0:
  275. # If the index of the last number is even, it's YYYYWwwd
  276. return 7
  277. else:
  278. return 8
  279. else:
  280. # YYYYMMDD (8)
  281. return 8
  282. def _parse_isoformat_date(dtstr):
  283. # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,
  284. # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
  285. assert len(dtstr) in (7, 8, 10)
  286. year = int(dtstr[0:4])
  287. has_sep = dtstr[4] == '-'
  288. pos = 4 + has_sep
  289. if dtstr[pos:pos + 1] == "W":
  290. # YYYY-?Www-?D?
  291. pos += 1
  292. weekno = int(dtstr[pos:pos + 2])
  293. pos += 2
  294. dayno = 1
  295. if len(dtstr) > pos:
  296. if (dtstr[pos:pos + 1] == '-') != has_sep:
  297. raise ValueError("Inconsistent use of dash separator")
  298. pos += has_sep
  299. dayno = int(dtstr[pos:pos + 1])
  300. return list(_isoweek_to_gregorian(year, weekno, dayno))
  301. else:
  302. month = int(dtstr[pos:pos + 2])
  303. pos += 2
  304. if (dtstr[pos:pos + 1] == "-") != has_sep:
  305. raise ValueError("Inconsistent use of dash separator")
  306. pos += has_sep
  307. day = int(dtstr[pos:pos + 2])
  308. return [year, month, day]
  309. _FRACTION_CORRECTION = [100000, 10000, 1000, 100, 10]
  310. def _parse_hh_mm_ss_ff(tstr):
  311. # Parses things of the form HH[:?MM[:?SS[{.,}fff[fff]]]]
  312. len_str = len(tstr)
  313. time_comps = [0, 0, 0, 0]
  314. pos = 0
  315. for comp in range(0, 3):
  316. if (len_str - pos) < 2:
  317. raise ValueError("Incomplete time component")
  318. time_comps[comp] = int(tstr[pos:pos+2])
  319. pos += 2
  320. next_char = tstr[pos:pos+1]
  321. if comp == 0:
  322. has_sep = next_char == ':'
  323. if not next_char or comp >= 2:
  324. break
  325. if has_sep and next_char != ':':
  326. raise ValueError("Invalid time separator: %c" % next_char)
  327. pos += has_sep
  328. if pos < len_str:
  329. if tstr[pos] not in '.,':
  330. raise ValueError("Invalid microsecond component")
  331. else:
  332. pos += 1
  333. len_remainder = len_str - pos
  334. if len_remainder >= 6:
  335. to_parse = 6
  336. else:
  337. to_parse = len_remainder
  338. time_comps[3] = int(tstr[pos:(pos+to_parse)])
  339. if to_parse < 6:
  340. time_comps[3] *= _FRACTION_CORRECTION[to_parse-1]
  341. if (len_remainder > to_parse
  342. and not all(map(_is_ascii_digit, tstr[(pos+to_parse):]))):
  343. raise ValueError("Non-digit values in unparsed fraction")
  344. return time_comps
  345. def _parse_isoformat_time(tstr):
  346. # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
  347. len_str = len(tstr)
  348. if len_str < 2:
  349. raise ValueError("Isoformat time too short")
  350. # This is equivalent to re.search('[+-Z]', tstr), but faster
  351. tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1 or tstr.find('Z') + 1)
  352. timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr
  353. time_comps = _parse_hh_mm_ss_ff(timestr)
  354. tzi = None
  355. if tz_pos == len_str and tstr[-1] == 'Z':
  356. tzi = timezone.utc
  357. elif tz_pos > 0:
  358. tzstr = tstr[tz_pos:]
  359. # Valid time zone strings are:
  360. # HH len: 2
  361. # HHMM len: 4
  362. # HH:MM len: 5
  363. # HHMMSS len: 6
  364. # HHMMSS.f+ len: 7+
  365. # HH:MM:SS len: 8
  366. # HH:MM:SS.f+ len: 10+
  367. if len(tzstr) in (0, 1, 3):
  368. raise ValueError("Malformed time zone string")
  369. tz_comps = _parse_hh_mm_ss_ff(tzstr)
  370. if all(x == 0 for x in tz_comps):
  371. tzi = timezone.utc
  372. else:
  373. tzsign = -1 if tstr[tz_pos - 1] == '-' else 1
  374. td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
  375. seconds=tz_comps[2], microseconds=tz_comps[3])
  376. tzi = timezone(tzsign * td)
  377. time_comps.append(tzi)
  378. return time_comps
  379. # tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
  380. def _isoweek_to_gregorian(year, week, day):
  381. # Year is bounded this way because 9999-12-31 is (9999, 52, 5)
  382. if not MINYEAR <= year <= MAXYEAR:
  383. raise ValueError(f"Year is out of range: {year}")
  384. if not 0 < week < 53:
  385. out_of_range = True
  386. if week == 53:
  387. # ISO years have 53 weeks in them on years starting with a
  388. # Thursday and leap years starting on a Wednesday
  389. first_weekday = _ymd2ord(year, 1, 1) % 7
  390. if (first_weekday == 4 or (first_weekday == 3 and
  391. _is_leap(year))):
  392. out_of_range = False
  393. if out_of_range:
  394. raise ValueError(f"Invalid week: {week}")
  395. if not 0 < day < 8:
  396. raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
  397. # Now compute the offset from (Y, 1, 1) in days:
  398. day_offset = (week - 1) * 7 + (day - 1)
  399. # Calculate the ordinal day for monday, week 1
  400. day_1 = _isoweek1monday(year)
  401. ord_day = day_1 + day_offset
  402. return _ord2ymd(ord_day)
  403. # Just raise TypeError if the arg isn't None or a string.
  404. def _check_tzname(name):
  405. if name is not None and not isinstance(name, str):
  406. raise TypeError("tzinfo.tzname() must return None or string, "
  407. "not '%s'" % type(name))
  408. # name is the offset-producing method, "utcoffset" or "dst".
  409. # offset is what it returned.
  410. # If offset isn't None or timedelta, raises TypeError.
  411. # If offset is None, returns None.
  412. # Else offset is checked for being in range.
  413. # If it is, its integer value is returned. Else ValueError is raised.
  414. def _check_utc_offset(name, offset):
  415. assert name in ("utcoffset", "dst")
  416. if offset is None:
  417. return
  418. if not isinstance(offset, timedelta):
  419. raise TypeError("tzinfo.%s() must return None "
  420. "or timedelta, not '%s'" % (name, type(offset)))
  421. if not -timedelta(1) < offset < timedelta(1):
  422. raise ValueError("%s()=%s, must be strictly between "
  423. "-timedelta(hours=24) and timedelta(hours=24)" %
  424. (name, offset))
  425. def _check_date_fields(year, month, day):
  426. year = _index(year)
  427. month = _index(month)
  428. day = _index(day)
  429. if not MINYEAR <= year <= MAXYEAR:
  430. raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
  431. if not 1 <= month <= 12:
  432. raise ValueError('month must be in 1..12', month)
  433. dim = _days_in_month(year, month)
  434. if not 1 <= day <= dim:
  435. raise ValueError('day must be in 1..%d' % dim, day)
  436. return year, month, day
  437. def _check_time_fields(hour, minute, second, microsecond, fold):
  438. hour = _index(hour)
  439. minute = _index(minute)
  440. second = _index(second)
  441. microsecond = _index(microsecond)
  442. if not 0 <= hour <= 23:
  443. raise ValueError('hour must be in 0..23', hour)
  444. if not 0 <= minute <= 59:
  445. raise ValueError('minute must be in 0..59', minute)
  446. if not 0 <= second <= 59:
  447. raise ValueError('second must be in 0..59', second)
  448. if not 0 <= microsecond <= 999999:
  449. raise ValueError('microsecond must be in 0..999999', microsecond)
  450. if fold not in (0, 1):
  451. raise ValueError('fold must be either 0 or 1', fold)
  452. return hour, minute, second, microsecond, fold
  453. def _check_tzinfo_arg(tz):
  454. if tz is not None and not isinstance(tz, tzinfo):
  455. raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
  456. def _cmperror(x, y):
  457. raise TypeError("can't compare '%s' to '%s'" % (
  458. type(x).__name__, type(y).__name__))
  459. def _divide_and_round(a, b):
  460. """divide a by b and round result to the nearest integer
  461. When the ratio is exactly half-way between two integers,
  462. the even integer is returned.
  463. """
  464. # Based on the reference implementation for divmod_near
  465. # in Objects/longobject.c.
  466. q, r = divmod(a, b)
  467. # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
  468. # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
  469. # positive, 2 * r < b if b negative.
  470. r *= 2
  471. greater_than_half = r > b if b > 0 else r < b
  472. if greater_than_half or r == b and q % 2 == 1:
  473. q += 1
  474. return q
  475. class timedelta:
  476. """Represent the difference between two datetime objects.
  477. Supported operators:
  478. - add, subtract timedelta
  479. - unary plus, minus, abs
  480. - compare to timedelta
  481. - multiply, divide by int
  482. In addition, datetime supports subtraction of two datetime objects
  483. returning a timedelta, and addition or subtraction of a datetime
  484. and a timedelta giving a datetime.
  485. Representation: (days, seconds, microseconds). Why? Because I
  486. felt like it.
  487. """
  488. __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
  489. def __new__(cls, days=0, seconds=0, microseconds=0,
  490. milliseconds=0, minutes=0, hours=0, weeks=0):
  491. # Doing this efficiently and accurately in C is going to be difficult
  492. # and error-prone, due to ubiquitous overflow possibilities, and that
  493. # C double doesn't have enough bits of precision to represent
  494. # microseconds over 10K years faithfully. The code here tries to make
  495. # explicit where go-fast assumptions can be relied on, in order to
  496. # guide the C implementation; it's way more convoluted than speed-
  497. # ignoring auto-overflow-to-long idiomatic Python could be.
  498. # XXX Check that all inputs are ints or floats.
  499. # Final values, all integer.
  500. # s and us fit in 32-bit signed ints; d isn't bounded.
  501. d = s = us = 0
  502. # Normalize everything to days, seconds, microseconds.
  503. days += weeks*7
  504. seconds += minutes*60 + hours*3600
  505. microseconds += milliseconds*1000
  506. # Get rid of all fractions, and normalize s and us.
  507. # Take a deep breath <wink>.
  508. if isinstance(days, float):
  509. dayfrac, days = _math.modf(days)
  510. daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
  511. assert daysecondswhole == int(daysecondswhole) # can't overflow
  512. s = int(daysecondswhole)
  513. assert days == int(days)
  514. d = int(days)
  515. else:
  516. daysecondsfrac = 0.0
  517. d = days
  518. assert isinstance(daysecondsfrac, float)
  519. assert abs(daysecondsfrac) <= 1.0
  520. assert isinstance(d, int)
  521. assert abs(s) <= 24 * 3600
  522. # days isn't referenced again before redefinition
  523. if isinstance(seconds, float):
  524. secondsfrac, seconds = _math.modf(seconds)
  525. assert seconds == int(seconds)
  526. seconds = int(seconds)
  527. secondsfrac += daysecondsfrac
  528. assert abs(secondsfrac) <= 2.0
  529. else:
  530. secondsfrac = daysecondsfrac
  531. # daysecondsfrac isn't referenced again
  532. assert isinstance(secondsfrac, float)
  533. assert abs(secondsfrac) <= 2.0
  534. assert isinstance(seconds, int)
  535. days, seconds = divmod(seconds, 24*3600)
  536. d += days
  537. s += int(seconds) # can't overflow
  538. assert isinstance(s, int)
  539. assert abs(s) <= 2 * 24 * 3600
  540. # seconds isn't referenced again before redefinition
  541. usdouble = secondsfrac * 1e6
  542. assert abs(usdouble) < 2.1e6 # exact value not critical
  543. # secondsfrac isn't referenced again
  544. if isinstance(microseconds, float):
  545. microseconds = round(microseconds + usdouble)
  546. seconds, microseconds = divmod(microseconds, 1000000)
  547. days, seconds = divmod(seconds, 24*3600)
  548. d += days
  549. s += seconds
  550. else:
  551. microseconds = int(microseconds)
  552. seconds, microseconds = divmod(microseconds, 1000000)
  553. days, seconds = divmod(seconds, 24*3600)
  554. d += days
  555. s += seconds
  556. microseconds = round(microseconds + usdouble)
  557. assert isinstance(s, int)
  558. assert isinstance(microseconds, int)
  559. assert abs(s) <= 3 * 24 * 3600
  560. assert abs(microseconds) < 3.1e6
  561. # Just a little bit of carrying possible for microseconds and seconds.
  562. seconds, us = divmod(microseconds, 1000000)
  563. s += seconds
  564. days, s = divmod(s, 24*3600)
  565. d += days
  566. assert isinstance(d, int)
  567. assert isinstance(s, int) and 0 <= s < 24*3600
  568. assert isinstance(us, int) and 0 <= us < 1000000
  569. if abs(d) > 999999999:
  570. raise OverflowError("timedelta # of days is too large: %d" % d)
  571. self = object.__new__(cls)
  572. self._days = d
  573. self._seconds = s
  574. self._microseconds = us
  575. self._hashcode = -1
  576. return self
  577. def __repr__(self):
  578. args = []
  579. if self._days:
  580. args.append("days=%d" % self._days)
  581. if self._seconds:
  582. args.append("seconds=%d" % self._seconds)
  583. if self._microseconds:
  584. args.append("microseconds=%d" % self._microseconds)
  585. if not args:
  586. args.append('0')
  587. return "%s.%s(%s)" % (self.__class__.__module__,
  588. self.__class__.__qualname__,
  589. ', '.join(args))
  590. def __str__(self):
  591. mm, ss = divmod(self._seconds, 60)
  592. hh, mm = divmod(mm, 60)
  593. s = "%d:%02d:%02d" % (hh, mm, ss)
  594. if self._days:
  595. def plural(n):
  596. return n, abs(n) != 1 and "s" or ""
  597. s = ("%d day%s, " % plural(self._days)) + s
  598. if self._microseconds:
  599. s = s + ".%06d" % self._microseconds
  600. return s
  601. def total_seconds(self):
  602. """Total seconds in the duration."""
  603. return ((self.days * 86400 + self.seconds) * 10**6 +
  604. self.microseconds) / 10**6
  605. # Read-only field accessors
  606. @property
  607. def days(self):
  608. """days"""
  609. return self._days
  610. @property
  611. def seconds(self):
  612. """seconds"""
  613. return self._seconds
  614. @property
  615. def microseconds(self):
  616. """microseconds"""
  617. return self._microseconds
  618. def __add__(self, other):
  619. if isinstance(other, timedelta):
  620. # for CPython compatibility, we cannot use
  621. # our __class__ here, but need a real timedelta
  622. return timedelta(self._days + other._days,
  623. self._seconds + other._seconds,
  624. self._microseconds + other._microseconds)
  625. return NotImplemented
  626. __radd__ = __add__
  627. def __sub__(self, other):
  628. if isinstance(other, timedelta):
  629. # for CPython compatibility, we cannot use
  630. # our __class__ here, but need a real timedelta
  631. return timedelta(self._days - other._days,
  632. self._seconds - other._seconds,
  633. self._microseconds - other._microseconds)
  634. return NotImplemented
  635. def __rsub__(self, other):
  636. if isinstance(other, timedelta):
  637. return -self + other
  638. return NotImplemented
  639. def __neg__(self):
  640. # for CPython compatibility, we cannot use
  641. # our __class__ here, but need a real timedelta
  642. return timedelta(-self._days,
  643. -self._seconds,
  644. -self._microseconds)
  645. def __pos__(self):
  646. return self
  647. def __abs__(self):
  648. if self._days < 0:
  649. return -self
  650. else:
  651. return self
  652. def __mul__(self, other):
  653. if isinstance(other, int):
  654. # for CPython compatibility, we cannot use
  655. # our __class__ here, but need a real timedelta
  656. return timedelta(self._days * other,
  657. self._seconds * other,
  658. self._microseconds * other)
  659. if isinstance(other, float):
  660. usec = self._to_microseconds()
  661. a, b = other.as_integer_ratio()
  662. return timedelta(0, 0, _divide_and_round(usec * a, b))
  663. return NotImplemented
  664. __rmul__ = __mul__
  665. def _to_microseconds(self):
  666. return ((self._days * (24*3600) + self._seconds) * 1000000 +
  667. self._microseconds)
  668. def __floordiv__(self, other):
  669. if not isinstance(other, (int, timedelta)):
  670. return NotImplemented
  671. usec = self._to_microseconds()
  672. if isinstance(other, timedelta):
  673. return usec // other._to_microseconds()
  674. if isinstance(other, int):
  675. return timedelta(0, 0, usec // other)
  676. def __truediv__(self, other):
  677. if not isinstance(other, (int, float, timedelta)):
  678. return NotImplemented
  679. usec = self._to_microseconds()
  680. if isinstance(other, timedelta):
  681. return usec / other._to_microseconds()
  682. if isinstance(other, int):
  683. return timedelta(0, 0, _divide_and_round(usec, other))
  684. if isinstance(other, float):
  685. a, b = other.as_integer_ratio()
  686. return timedelta(0, 0, _divide_and_round(b * usec, a))
  687. def __mod__(self, other):
  688. if isinstance(other, timedelta):
  689. r = self._to_microseconds() % other._to_microseconds()
  690. return timedelta(0, 0, r)
  691. return NotImplemented
  692. def __divmod__(self, other):
  693. if isinstance(other, timedelta):
  694. q, r = divmod(self._to_microseconds(),
  695. other._to_microseconds())
  696. return q, timedelta(0, 0, r)
  697. return NotImplemented
  698. # Comparisons of timedelta objects with other.
  699. def __eq__(self, other):
  700. if isinstance(other, timedelta):
  701. return self._cmp(other) == 0
  702. else:
  703. return NotImplemented
  704. def __le__(self, other):
  705. if isinstance(other, timedelta):
  706. return self._cmp(other) <= 0
  707. else:
  708. return NotImplemented
  709. def __lt__(self, other):
  710. if isinstance(other, timedelta):
  711. return self._cmp(other) < 0
  712. else:
  713. return NotImplemented
  714. def __ge__(self, other):
  715. if isinstance(other, timedelta):
  716. return self._cmp(other) >= 0
  717. else:
  718. return NotImplemented
  719. def __gt__(self, other):
  720. if isinstance(other, timedelta):
  721. return self._cmp(other) > 0
  722. else:
  723. return NotImplemented
  724. def _cmp(self, other):
  725. assert isinstance(other, timedelta)
  726. return _cmp(self._getstate(), other._getstate())
  727. def __hash__(self):
  728. if self._hashcode == -1:
  729. self._hashcode = hash(self._getstate())
  730. return self._hashcode
  731. def __bool__(self):
  732. return (self._days != 0 or
  733. self._seconds != 0 or
  734. self._microseconds != 0)
  735. # Pickle support.
  736. def _getstate(self):
  737. return (self._days, self._seconds, self._microseconds)
  738. def __reduce__(self):
  739. return (self.__class__, self._getstate())
  740. timedelta.min = timedelta(-999999999)
  741. timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
  742. microseconds=999999)
  743. timedelta.resolution = timedelta(microseconds=1)
  744. class date:
  745. """Concrete date type.
  746. Constructors:
  747. __new__()
  748. fromtimestamp()
  749. today()
  750. fromordinal()
  751. Operators:
  752. __repr__, __str__
  753. __eq__, __le__, __lt__, __ge__, __gt__, __hash__
  754. __add__, __radd__, __sub__ (add/radd only with timedelta arg)
  755. Methods:
  756. timetuple()
  757. toordinal()
  758. weekday()
  759. isoweekday(), isocalendar(), isoformat()
  760. ctime()
  761. strftime()
  762. Properties (readonly):
  763. year, month, day
  764. """
  765. __slots__ = '_year', '_month', '_day', '_hashcode'
  766. def __new__(cls, year, month=None, day=None):
  767. """Constructor.
  768. Arguments:
  769. year, month, day (required, base 1)
  770. """
  771. if (month is None and
  772. isinstance(year, (bytes, str)) and len(year) == 4 and
  773. 1 <= ord(year[2:3]) <= 12):
  774. # Pickle support
  775. if isinstance(year, str):
  776. try:
  777. year = year.encode('latin1')
  778. except UnicodeEncodeError:
  779. # More informative error message.
  780. raise ValueError(
  781. "Failed to encode latin1 string when unpickling "
  782. "a date object. "
  783. "pickle.load(data, encoding='latin1') is assumed.")
  784. self = object.__new__(cls)
  785. self.__setstate(year)
  786. self._hashcode = -1
  787. return self
  788. year, month, day = _check_date_fields(year, month, day)
  789. self = object.__new__(cls)
  790. self._year = year
  791. self._month = month
  792. self._day = day
  793. self._hashcode = -1
  794. return self
  795. # Additional constructors
  796. @classmethod
  797. def fromtimestamp(cls, t):
  798. "Construct a date from a POSIX timestamp (like time.time())."
  799. y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
  800. return cls(y, m, d)
  801. @classmethod
  802. def today(cls):
  803. "Construct a date from time.time()."
  804. t = _time.time()
  805. return cls.fromtimestamp(t)
  806. @classmethod
  807. def fromordinal(cls, n):
  808. """Construct a date from a proleptic Gregorian ordinal.
  809. January 1 of year 1 is day 1. Only the year, month and day are
  810. non-zero in the result.
  811. """
  812. y, m, d = _ord2ymd(n)
  813. return cls(y, m, d)
  814. @classmethod
  815. def fromisoformat(cls, date_string):
  816. """Construct a date from a string in ISO 8601 format."""
  817. if not isinstance(date_string, str):
  818. raise TypeError('fromisoformat: argument must be str')
  819. if len(date_string) not in (7, 8, 10):
  820. raise ValueError(f'Invalid isoformat string: {date_string!r}')
  821. try:
  822. return cls(*_parse_isoformat_date(date_string))
  823. except Exception:
  824. raise ValueError(f'Invalid isoformat string: {date_string!r}')
  825. @classmethod
  826. def fromisocalendar(cls, year, week, day):
  827. """Construct a date from the ISO year, week number and weekday.
  828. This is the inverse of the date.isocalendar() function"""
  829. return cls(*_isoweek_to_gregorian(year, week, day))
  830. # Conversions to string
  831. def __repr__(self):
  832. """Convert to formal string, for repr().
  833. >>> dt = datetime(2010, 1, 1)
  834. >>> repr(dt)
  835. 'datetime.datetime(2010, 1, 1, 0, 0)'
  836. >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
  837. >>> repr(dt)
  838. 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)'
  839. """
  840. return "%s.%s(%d, %d, %d)" % (self.__class__.__module__,
  841. self.__class__.__qualname__,
  842. self._year,
  843. self._month,
  844. self._day)
  845. # XXX These shouldn't depend on time.localtime(), because that
  846. # clips the usable dates to [1970 .. 2038). At least ctime() is
  847. # easily done without using strftime() -- that's better too because
  848. # strftime("%c", ...) is locale specific.
  849. def ctime(self):
  850. "Return ctime() style string."
  851. weekday = self.toordinal() % 7 or 7
  852. return "%s %s %2d 00:00:00 %04d" % (
  853. _DAYNAMES[weekday],
  854. _MONTHNAMES[self._month],
  855. self._day, self._year)
  856. def strftime(self, fmt):
  857. """
  858. Format using strftime().
  859. Example: "%d/%m/%Y, %H:%M:%S"
  860. """
  861. return _wrap_strftime(self, fmt, self.timetuple())
  862. def __format__(self, fmt):
  863. if not isinstance(fmt, str):
  864. raise TypeError("must be str, not %s" % type(fmt).__name__)
  865. if len(fmt) != 0:
  866. return self.strftime(fmt)
  867. return str(self)
  868. def isoformat(self):
  869. """Return the date formatted according to ISO.
  870. This is 'YYYY-MM-DD'.
  871. References:
  872. - http://www.w3.org/TR/NOTE-datetime
  873. - http://www.cl.cam.ac.uk/~mgk25/iso-time.html
  874. """
  875. return "%04d-%02d-%02d" % (self._year, self._month, self._day)
  876. __str__ = isoformat
  877. # Read-only field accessors
  878. @property
  879. def year(self):
  880. """year (1-9999)"""
  881. return self._year
  882. @property
  883. def month(self):
  884. """month (1-12)"""
  885. return self._month
  886. @property
  887. def day(self):
  888. """day (1-31)"""
  889. return self._day
  890. # Standard conversions, __eq__, __le__, __lt__, __ge__, __gt__,
  891. # __hash__ (and helpers)
  892. def timetuple(self):
  893. "Return local time tuple compatible with time.localtime()."
  894. return _build_struct_time(self._year, self._month, self._day,
  895. 0, 0, 0, -1)
  896. def toordinal(self):
  897. """Return proleptic Gregorian ordinal for the year, month and day.
  898. January 1 of year 1 is day 1. Only the year, month and day values
  899. contribute to the result.
  900. """
  901. return _ymd2ord(self._year, self._month, self._day)
  902. def replace(self, year=None, month=None, day=None):
  903. """Return a new date with new values for the specified fields."""
  904. if year is None:
  905. year = self._year
  906. if month is None:
  907. month = self._month
  908. if day is None:
  909. day = self._day
  910. return type(self)(year, month, day)
  911. # Comparisons of date objects with other.
  912. def __eq__(self, other):
  913. if isinstance(other, date):
  914. return self._cmp(other) == 0
  915. return NotImplemented
  916. def __le__(self, other):
  917. if isinstance(other, date):
  918. return self._cmp(other) <= 0
  919. return NotImplemented
  920. def __lt__(self, other):
  921. if isinstance(other, date):
  922. return self._cmp(other) < 0
  923. return NotImplemented
  924. def __ge__(self, other):
  925. if isinstance(other, date):
  926. return self._cmp(other) >= 0
  927. return NotImplemented
  928. def __gt__(self, other):
  929. if isinstance(other, date):
  930. return self._cmp(other) > 0
  931. return NotImplemented
  932. def _cmp(self, other):
  933. assert isinstance(other, date)
  934. y, m, d = self._year, self._month, self._day
  935. y2, m2, d2 = other._year, other._month, other._day
  936. return _cmp((y, m, d), (y2, m2, d2))
  937. def __hash__(self):
  938. "Hash."
  939. if self._hashcode == -1:
  940. self._hashcode = hash(self._getstate())
  941. return self._hashcode
  942. # Computations
  943. def __add__(self, other):
  944. "Add a date to a timedelta."
  945. if isinstance(other, timedelta):
  946. o = self.toordinal() + other.days
  947. if 0 < o <= _MAXORDINAL:
  948. return type(self).fromordinal(o)
  949. raise OverflowError("result out of range")
  950. return NotImplemented
  951. __radd__ = __add__
  952. def __sub__(self, other):
  953. """Subtract two dates, or a date and a timedelta."""
  954. if isinstance(other, timedelta):
  955. return self + timedelta(-other.days)
  956. if isinstance(other, date):
  957. days1 = self.toordinal()
  958. days2 = other.toordinal()
  959. return timedelta(days1 - days2)
  960. return NotImplemented
  961. def weekday(self):
  962. "Return day of the week, where Monday == 0 ... Sunday == 6."
  963. return (self.toordinal() + 6) % 7
  964. # Day-of-the-week and week-of-the-year, according to ISO
  965. def isoweekday(self):
  966. "Return day of the week, where Monday == 1 ... Sunday == 7."
  967. # 1-Jan-0001 is a Monday
  968. return self.toordinal() % 7 or 7
  969. def isocalendar(self):
  970. """Return a named tuple containing ISO year, week number, and weekday.
  971. The first ISO week of the year is the (Mon-Sun) week
  972. containing the year's first Thursday; everything else derives
  973. from that.
  974. The first week is 1; Monday is 1 ... Sunday is 7.
  975. ISO calendar algorithm taken from
  976. http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
  977. (used with permission)
  978. """
  979. year = self._year
  980. week1monday = _isoweek1monday(year)
  981. today = _ymd2ord(self._year, self._month, self._day)
  982. # Internally, week and day have origin 0
  983. week, day = divmod(today - week1monday, 7)
  984. if week < 0:
  985. year -= 1
  986. week1monday = _isoweek1monday(year)
  987. week, day = divmod(today - week1monday, 7)
  988. elif week >= 52:
  989. if today >= _isoweek1monday(year+1):
  990. year += 1
  991. week = 0
  992. return _IsoCalendarDate(year, week+1, day+1)
  993. # Pickle support.
  994. def _getstate(self):
  995. yhi, ylo = divmod(self._year, 256)
  996. return bytes([yhi, ylo, self._month, self._day]),
  997. def __setstate(self, string):
  998. yhi, ylo, self._month, self._day = string
  999. self._year = yhi * 256 + ylo
  1000. def __reduce__(self):
  1001. return (self.__class__, self._getstate())
  1002. _date_class = date # so functions w/ args named "date" can get at the class
  1003. date.min = date(1, 1, 1)
  1004. date.max = date(9999, 12, 31)
  1005. date.resolution = timedelta(days=1)
  1006. class tzinfo:
  1007. """Abstract base class for time zone info classes.
  1008. Subclasses must override the name(), utcoffset() and dst() methods.
  1009. """
  1010. __slots__ = ()
  1011. def tzname(self, dt):
  1012. "datetime -> string name of time zone."
  1013. raise NotImplementedError("tzinfo subclass must override tzname()")
  1014. def utcoffset(self, dt):
  1015. "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
  1016. raise NotImplementedError("tzinfo subclass must override utcoffset()")
  1017. def dst(self, dt):
  1018. """datetime -> DST offset as timedelta, positive for east of UTC.
  1019. Return 0 if DST not in effect. utcoffset() must include the DST
  1020. offset.
  1021. """
  1022. raise NotImplementedError("tzinfo subclass must override dst()")
  1023. def fromutc(self, dt):
  1024. "datetime in UTC -> datetime in local time."
  1025. if not isinstance(dt, datetime):
  1026. raise TypeError("fromutc() requires a datetime argument")
  1027. if dt.tzinfo is not self:
  1028. raise ValueError("dt.tzinfo is not self")
  1029. dtoff = dt.utcoffset()
  1030. if dtoff is None:
  1031. raise ValueError("fromutc() requires a non-None utcoffset() "
  1032. "result")
  1033. # See the long comment block at the end of this file for an
  1034. # explanation of this algorithm.
  1035. dtdst = dt.dst()
  1036. if dtdst is None:
  1037. raise ValueError("fromutc() requires a non-None dst() result")
  1038. delta = dtoff - dtdst
  1039. if delta:
  1040. dt += delta
  1041. dtdst = dt.dst()
  1042. if dtdst is None:
  1043. raise ValueError("fromutc(): dt.dst gave inconsistent "
  1044. "results; cannot convert")
  1045. return dt + dtdst
  1046. # Pickle support.
  1047. def __reduce__(self):
  1048. getinitargs = getattr(self, "__getinitargs__", None)
  1049. if getinitargs:
  1050. args = getinitargs()
  1051. else:
  1052. args = ()
  1053. return (self.__class__, args, self.__getstate__())
  1054. class IsoCalendarDate(tuple):
  1055. def __new__(cls, year, week, weekday, /):
  1056. return super().__new__(cls, (year, week, weekday))
  1057. @property
  1058. def year(self):
  1059. return self[0]
  1060. @property
  1061. def week(self):
  1062. return self[1]
  1063. @property
  1064. def weekday(self):
  1065. return self[2]
  1066. def __reduce__(self):
  1067. # This code is intended to pickle the object without making the
  1068. # class public. See https://bugs.python.org/msg352381
  1069. return (tuple, (tuple(self),))
  1070. def __repr__(self):
  1071. return (f'{self.__class__.__name__}'
  1072. f'(year={self[0]}, week={self[1]}, weekday={self[2]})')
  1073. _IsoCalendarDate = IsoCalendarDate
  1074. del IsoCalendarDate
  1075. _tzinfo_class = tzinfo
  1076. class time:
  1077. """Time with time zone.
  1078. Constructors:
  1079. __new__()
  1080. Operators:
  1081. __repr__, __str__
  1082. __eq__, __le__, __lt__, __ge__, __gt__, __hash__
  1083. Methods:
  1084. strftime()
  1085. isoformat()
  1086. utcoffset()
  1087. tzname()
  1088. dst()
  1089. Properties (readonly):
  1090. hour, minute, second, microsecond, tzinfo, fold
  1091. """
  1092. __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
  1093. def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
  1094. """Constructor.
  1095. Arguments:
  1096. hour, minute (required)
  1097. second, microsecond (default to zero)
  1098. tzinfo (default to None)
  1099. fold (keyword only, default to zero)
  1100. """
  1101. if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
  1102. ord(hour[0:1])&0x7F < 24):
  1103. # Pickle support
  1104. if isinstance(hour, str):
  1105. try:
  1106. hour = hour.encode('latin1')
  1107. except UnicodeEncodeError:
  1108. # More informative error message.
  1109. raise ValueError(
  1110. "Failed to encode latin1 string when unpickling "
  1111. "a time object. "
  1112. "pickle.load(data, encoding='latin1') is assumed.")
  1113. self = object.__new__(cls)
  1114. self.__setstate(hour, minute or None)
  1115. self._hashcode = -1
  1116. return self
  1117. hour, minute, second, microsecond, fold = _check_time_fields(
  1118. hour, minute, second, microsecond, fold)
  1119. _check_tzinfo_arg(tzinfo)
  1120. self = object.__new__(cls)
  1121. self._hour = hour
  1122. self._minute = minute
  1123. self._second = second
  1124. self._microsecond = microsecond
  1125. self._tzinfo = tzinfo
  1126. self._hashcode = -1
  1127. self._fold = fold
  1128. return self
  1129. # Read-only field accessors
  1130. @property
  1131. def hour(self):
  1132. """hour (0-23)"""
  1133. return self._hour
  1134. @property
  1135. def minute(self):
  1136. """minute (0-59)"""
  1137. return self._minute
  1138. @property
  1139. def second(self):
  1140. """second (0-59)"""
  1141. return self._second
  1142. @property
  1143. def microsecond(self):
  1144. """microsecond (0-999999)"""
  1145. return self._microsecond
  1146. @property
  1147. def tzinfo(self):
  1148. """timezone info object"""
  1149. return self._tzinfo
  1150. @property
  1151. def fold(self):
  1152. return self._fold
  1153. # Standard conversions, __hash__ (and helpers)
  1154. # Comparisons of time objects with other.
  1155. def __eq__(self, other):
  1156. if isinstance(other, time):
  1157. return self._cmp(other, allow_mixed=True) == 0
  1158. else:
  1159. return NotImplemented
  1160. def __le__(self, other):
  1161. if isinstance(other, time):
  1162. return self._cmp(other) <= 0
  1163. else:
  1164. return NotImplemented
  1165. def __lt__(self, other):
  1166. if isinstance(other, time):
  1167. return self._cmp(other) < 0
  1168. else:
  1169. return NotImplemented
  1170. def __ge__(self, other):
  1171. if isinstance(other, time):
  1172. return self._cmp(other) >= 0
  1173. else:
  1174. return NotImplemented
  1175. def __gt__(self, other):
  1176. if isinstance(other, time):
  1177. return self._cmp(other) > 0
  1178. else:
  1179. return NotImplemented
  1180. def _cmp(self, other, allow_mixed=False):
  1181. assert isinstance(other, time)
  1182. mytz = self._tzinfo
  1183. ottz = other._tzinfo
  1184. myoff = otoff = None
  1185. if mytz is ottz:
  1186. base_compare = True
  1187. else:
  1188. myoff = self.utcoffset()
  1189. otoff = other.utcoffset()
  1190. base_compare = myoff == otoff
  1191. if base_compare:
  1192. return _cmp((self._hour, self._minute, self._second,
  1193. self._microsecond),
  1194. (other._hour, other._minute, other._second,
  1195. other._microsecond))
  1196. if myoff is None or otoff is None:
  1197. if allow_mixed:
  1198. return 2 # arbitrary non-zero value
  1199. else:
  1200. raise TypeError("cannot compare naive and aware times")
  1201. myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
  1202. othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
  1203. return _cmp((myhhmm, self._second, self._microsecond),
  1204. (othhmm, other._second, other._microsecond))
  1205. def __hash__(self):
  1206. """Hash."""
  1207. if self._hashcode == -1:
  1208. if self.fold:
  1209. t = self.replace(fold=0)
  1210. else:
  1211. t = self
  1212. tzoff = t.utcoffset()
  1213. if not tzoff: # zero or None
  1214. self._hashcode = hash(t._getstate()[0])
  1215. else:
  1216. h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
  1217. timedelta(hours=1))
  1218. assert not m % timedelta(minutes=1), "whole minute"
  1219. m //= timedelta(minutes=1)
  1220. if 0 <= h < 24:
  1221. self._hashcode = hash(time(h, m, self.second, self.microsecond))
  1222. else:
  1223. self._hashcode = hash((h, m, self.second, self.microsecond))
  1224. return self._hashcode
  1225. # Conversion to string
  1226. def _tzstr(self):
  1227. """Return formatted timezone offset (+xx:xx) or an empty string."""
  1228. off = self.utcoffset()
  1229. return _format_offset(off)
  1230. def __repr__(self):
  1231. """Convert to formal string, for repr()."""
  1232. if self._microsecond != 0:
  1233. s = ", %d, %d" % (self._second, self._microsecond)
  1234. elif self._second != 0:
  1235. s = ", %d" % self._second
  1236. else:
  1237. s = ""
  1238. s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
  1239. self.__class__.__qualname__,
  1240. self._hour, self._minute, s)
  1241. if self._tzinfo is not None:
  1242. assert s[-1:] == ")"
  1243. s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
  1244. if self._fold:
  1245. assert s[-1:] == ")"
  1246. s = s[:-1] + ", fold=1)"
  1247. return s
  1248. def isoformat(self, timespec='auto'):
  1249. """Return the time formatted according to ISO.
  1250. The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
  1251. part is omitted if self.microsecond == 0.
  1252. The optional argument timespec specifies the number of additional
  1253. terms of the time to include. Valid options are 'auto', 'hours',
  1254. 'minutes', 'seconds', 'milliseconds' and 'microseconds'.
  1255. """
  1256. s = _format_time(self._hour, self._minute, self._second,
  1257. self._microsecond, timespec)
  1258. tz = self._tzstr()
  1259. if tz:
  1260. s += tz
  1261. return s
  1262. __str__ = isoformat
  1263. @classmethod
  1264. def fromisoformat(cls, time_string):
  1265. """Construct a time from a string in one of the ISO 8601 formats."""
  1266. if not isinstance(time_string, str):
  1267. raise TypeError('fromisoformat: argument must be str')
  1268. # The spec actually requires that time-only ISO 8601 strings start with
  1269. # T, but the extended format allows this to be omitted as long as there
  1270. # is no ambiguity with date strings.
  1271. time_string = time_string.removeprefix('T')
  1272. try:
  1273. return cls(*_parse_isoformat_time(time_string))
  1274. except Exception:
  1275. raise ValueError(f'Invalid isoformat string: {time_string!r}')
  1276. def strftime(self, fmt):
  1277. """Format using strftime(). The date part of the timestamp passed
  1278. to underlying strftime should not be used.
  1279. """
  1280. # The year must be >= 1000 else Python's strftime implementation
  1281. # can raise a bogus exception.
  1282. timetuple = (1900, 1, 1,
  1283. self._hour, self._minute, self._second,
  1284. 0, 1, -1)
  1285. return _wrap_strftime(self, fmt, timetuple)
  1286. def __format__(self, fmt):
  1287. if not isinstance(fmt, str):
  1288. raise TypeError("must be str, not %s" % type(fmt).__name__)
  1289. if len(fmt) != 0:
  1290. return self.strftime(fmt)
  1291. return str(self)
  1292. # Timezone functions
  1293. def utcoffset(self):
  1294. """Return the timezone offset as timedelta, positive east of UTC
  1295. (negative west of UTC)."""
  1296. if self._tzinfo is None:
  1297. return None
  1298. offset = self._tzinfo.utcoffset(None)
  1299. _check_utc_offset("utcoffset", offset)
  1300. return offset
  1301. def tzname(self):
  1302. """Return the timezone name.
  1303. Note that the name is 100% informational -- there's no requirement that
  1304. it mean anything in particular. For example, "GMT", "UTC", "-500",
  1305. "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
  1306. """
  1307. if self._tzinfo is None:
  1308. return None
  1309. name = self._tzinfo.tzname(None)
  1310. _check_tzname(name)
  1311. return name
  1312. def dst(self):
  1313. """Return 0 if DST is not in effect, or the DST offset (as timedelta
  1314. positive eastward) if DST is in effect.
  1315. This is purely informational; the DST offset has already been added to
  1316. the UTC offset returned by utcoffset() if applicable, so there's no
  1317. need to consult dst() unless you're interested in displaying the DST
  1318. info.
  1319. """
  1320. if self._tzinfo is None:
  1321. return None
  1322. offset = self._tzinfo.dst(None)
  1323. _check_utc_offset("dst", offset)
  1324. return offset
  1325. def replace(self, hour=None, minute=None, second=None, microsecond=None,
  1326. tzinfo=True, *, fold=None):
  1327. """Return a new time with new values for the specified fields."""
  1328. if hour is None:
  1329. hour = self.hour
  1330. if minute is None:
  1331. minute = self.minute
  1332. if second is None:
  1333. second = self.second
  1334. if microsecond is None:
  1335. microsecond = self.microsecond
  1336. if tzinfo is True:
  1337. tzinfo = self.tzinfo
  1338. if fold is None:
  1339. fold = self._fold
  1340. return type(self)(hour, minute, second, microsecond, tzinfo, fold=fold)
  1341. # Pickle support.
  1342. def _getstate(self, protocol=3):
  1343. us2, us3 = divmod(self._microsecond, 256)
  1344. us1, us2 = divmod(us2, 256)
  1345. h = self._hour
  1346. if self._fold and protocol > 3:
  1347. h += 128
  1348. basestate = bytes([h, self._minute, self._second,
  1349. us1, us2, us3])
  1350. if self._tzinfo is None:
  1351. return (basestate,)
  1352. else:
  1353. return (basestate, self._tzinfo)
  1354. def __setstate(self, string, tzinfo):
  1355. if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
  1356. raise TypeError("bad tzinfo state arg")
  1357. h, self._minute, self._second, us1, us2, us3 = string
  1358. if h > 127:
  1359. self._fold = 1
  1360. self._hour = h - 128
  1361. else:
  1362. self._fold = 0
  1363. self._hour = h
  1364. self._microsecond = (((us1 << 8) | us2) << 8) | us3
  1365. self._tzinfo = tzinfo
  1366. def __reduce_ex__(self, protocol):
  1367. return (self.__class__, self._getstate(protocol))
  1368. def __reduce__(self):
  1369. return self.__reduce_ex__(2)
  1370. _time_class = time # so functions w/ args named "time" can get at the class
  1371. time.min = time(0, 0, 0)
  1372. time.max = time(23, 59, 59, 999999)
  1373. time.resolution = timedelta(microseconds=1)
  1374. class datetime(date):
  1375. """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
  1376. The year, month and day arguments are required. tzinfo may be None, or an
  1377. instance of a tzinfo subclass. The remaining arguments may be ints.
  1378. """
  1379. __slots__ = date.__slots__ + time.__slots__
  1380. def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
  1381. microsecond=0, tzinfo=None, *, fold=0):
  1382. if (isinstance(year, (bytes, str)) and len(year) == 10 and
  1383. 1 <= ord(year[2:3])&0x7F <= 12):
  1384. # Pickle support
  1385. if isinstance(year, str):
  1386. try:
  1387. year = bytes(year, 'latin1')
  1388. except UnicodeEncodeError:
  1389. # More informative error message.
  1390. raise ValueError(
  1391. "Failed to encode latin1 string when unpickling "
  1392. "a datetime object. "
  1393. "pickle.load(data, encoding='latin1') is assumed.")
  1394. self = object.__new__(cls)
  1395. self.__setstate(year, month)
  1396. self._hashcode = -1
  1397. return self
  1398. year, month, day = _check_date_fields(year, month, day)
  1399. hour, minute, second, microsecond, fold = _check_time_fields(
  1400. hour, minute, second, microsecond, fold)
  1401. _check_tzinfo_arg(tzinfo)
  1402. self = object.__new__(cls)
  1403. self._year = year
  1404. self._month = month
  1405. self._day = day
  1406. self._hour = hour
  1407. self._minute = minute
  1408. self._second = second
  1409. self._microsecond = microsecond
  1410. self._tzinfo = tzinfo
  1411. self._hashcode = -1
  1412. self._fold = fold
  1413. return self
  1414. # Read-only field accessors
  1415. @property
  1416. def hour(self):
  1417. """hour (0-23)"""
  1418. return self._hour
  1419. @property
  1420. def minute(self):
  1421. """minute (0-59)"""
  1422. return self._minute
  1423. @property
  1424. def second(self):
  1425. """second (0-59)"""
  1426. return self._second
  1427. @property
  1428. def microsecond(self):
  1429. """microsecond (0-999999)"""
  1430. return self._microsecond
  1431. @property
  1432. def tzinfo(self):
  1433. """timezone info object"""
  1434. return self._tzinfo
  1435. @property
  1436. def fold(self):
  1437. return self._fold
  1438. @classmethod
  1439. def _fromtimestamp(cls, t, utc, tz):
  1440. """Construct a datetime from a POSIX timestamp (like time.time()).
  1441. A timezone info object may be passed in as well.
  1442. """
  1443. frac, t = _math.modf(t)
  1444. us = round(frac * 1e6)
  1445. if us >= 1000000:
  1446. t += 1
  1447. us -= 1000000
  1448. elif us < 0:
  1449. t -= 1
  1450. us += 1000000
  1451. converter = _time.gmtime if utc else _time.localtime
  1452. y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
  1453. ss = min(ss, 59) # clamp out leap seconds if the platform has them
  1454. result = cls(y, m, d, hh, mm, ss, us, tz)
  1455. if tz is None and not utc:
  1456. # As of version 2015f max fold in IANA database is
  1457. # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
  1458. # Let's probe 24 hours in the past to detect a transition:
  1459. max_fold_seconds = 24 * 3600
  1460. # On Windows localtime_s throws an OSError for negative values,
  1461. # thus we can't perform fold detection for values of time less
  1462. # than the max time fold. See comments in _datetimemodule's
  1463. # version of this method for more details.
  1464. if t < max_fold_seconds and sys.platform.startswith("win"):
  1465. return result
  1466. y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
  1467. probe1 = cls(y, m, d, hh, mm, ss, us, tz)
  1468. trans = result - probe1 - timedelta(0, max_fold_seconds)
  1469. if trans.days < 0:
  1470. y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
  1471. probe2 = cls(y, m, d, hh, mm, ss, us, tz)
  1472. if probe2 == result:
  1473. result._fold = 1
  1474. elif tz is not None:
  1475. result = tz.fromutc(result)
  1476. return result
  1477. @classmethod
  1478. def fromtimestamp(cls, t, tz=None):
  1479. """Construct a datetime from a POSIX timestamp (like time.time()).
  1480. A timezone info object may be passed in as well.
  1481. """
  1482. _check_tzinfo_arg(tz)
  1483. return cls._fromtimestamp(t, tz is not None, tz)
  1484. @classmethod
  1485. def utcfromtimestamp(cls, t):
  1486. """Construct a naive UTC datetime from a POSIX timestamp."""
  1487. return cls._fromtimestamp(t, True, None)
  1488. @classmethod
  1489. def now(cls, tz=None):
  1490. "Construct a datetime from time.time() and optional time zone info."
  1491. t = _time.time()
  1492. return cls.fromtimestamp(t, tz)
  1493. @classmethod
  1494. def utcnow(cls):
  1495. "Construct a UTC datetime from time.time()."
  1496. t = _time.time()
  1497. return cls.utcfromtimestamp(t)
  1498. @classmethod
  1499. def combine(cls, date, time, tzinfo=True):
  1500. "Construct a datetime from a given date and a given time."
  1501. if not isinstance(date, _date_class):
  1502. raise TypeError("date argument must be a date instance")
  1503. if not isinstance(time, _time_class):
  1504. raise TypeError("time argument must be a time instance")
  1505. if tzinfo is True:
  1506. tzinfo = time.tzinfo
  1507. return cls(date.year, date.month, date.day,
  1508. time.hour, time.minute, time.second, time.microsecond,
  1509. tzinfo, fold=time.fold)
  1510. @classmethod
  1511. def fromisoformat(cls, date_string):
  1512. """Construct a datetime from a string in one of the ISO 8601 formats."""
  1513. if not isinstance(date_string, str):
  1514. raise TypeError('fromisoformat: argument must be str')
  1515. if len(date_string) < 7:
  1516. raise ValueError(f'Invalid isoformat string: {date_string!r}')
  1517. # Split this at the separator
  1518. try:
  1519. separator_location = _find_isoformat_datetime_separator(date_string)
  1520. dstr = date_string[0:separator_location]
  1521. tstr = date_string[(separator_location+1):]
  1522. date_components = _parse_isoformat_date(dstr)
  1523. except ValueError:
  1524. raise ValueError(
  1525. f'Invalid isoformat string: {date_string!r}') from None
  1526. if tstr:
  1527. try:
  1528. time_components = _parse_isoformat_time(tstr)
  1529. except ValueError:
  1530. raise ValueError(
  1531. f'Invalid isoformat string: {date_string!r}') from None
  1532. else:
  1533. time_components = [0, 0, 0, 0, None]
  1534. return cls(*(date_components + time_components))
  1535. def timetuple(self):
  1536. "Return local time tuple compatible with time.localtime()."
  1537. dst = self.dst()
  1538. if dst is None:
  1539. dst = -1
  1540. elif dst:
  1541. dst = 1
  1542. else:
  1543. dst = 0
  1544. return _build_struct_time(self.year, self.month, self.day,
  1545. self.hour, self.minute, self.second,
  1546. dst)
  1547. def _mktime(self):
  1548. """Return integer POSIX timestamp."""
  1549. epoch = datetime(1970, 1, 1)
  1550. max_fold_seconds = 24 * 3600
  1551. t = (self - epoch) // timedelta(0, 1)
  1552. def local(u):
  1553. y, m, d, hh, mm, ss = _time.localtime(u)[:6]
  1554. return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
  1555. # Our goal is to solve t = local(u) for u.
  1556. a = local(t) - t
  1557. u1 = t - a
  1558. t1 = local(u1)
  1559. if t1 == t:
  1560. # We found one solution, but it may not be the one we need.
  1561. # Look for an earlier solution (if `fold` is 0), or a
  1562. # later one (if `fold` is 1).
  1563. u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
  1564. b = local(u2) - u2
  1565. if a == b:
  1566. return u1
  1567. else:
  1568. b = t1 - u1
  1569. assert a != b
  1570. u2 = t - b
  1571. t2 = local(u2)
  1572. if t2 == t:
  1573. return u2
  1574. if t1 == t:
  1575. return u1
  1576. # We have found both offsets a and b, but neither t - a nor t - b is
  1577. # a solution. This means t is in the gap.
  1578. return (max, min)[self.fold](u1, u2)
  1579. def timestamp(self):
  1580. "Return POSIX timestamp as float"
  1581. if self._tzinfo is None:
  1582. s = self._mktime()
  1583. return s + self.microsecond / 1e6
  1584. else:
  1585. return (self - _EPOCH).total_seconds()
  1586. def utctimetuple(self):
  1587. "Return UTC time tuple compatible with time.gmtime()."
  1588. offset = self.utcoffset()
  1589. if offset:
  1590. self -= offset
  1591. y, m, d = self.year, self.month, self.day
  1592. hh, mm, ss = self.hour, self.minute, self.second
  1593. return _build_struct_time(y, m, d, hh, mm, ss, 0)
  1594. def date(self):
  1595. "Return the date part."
  1596. return date(self._year, self._month, self._day)
  1597. def time(self):
  1598. "Return the time part, with tzinfo None."
  1599. return time(self.hour, self.minute, self.second, self.microsecond, fold=self.fold)
  1600. def timetz(self):
  1601. "Return the time part, with same tzinfo."
  1602. return time(self.hour, self.minute, self.second, self.microsecond,
  1603. self._tzinfo, fold=self.fold)
  1604. def replace(self, year=None, month=None, day=None, hour=None,
  1605. minute=None, second=None, microsecond=None, tzinfo=True,
  1606. *, fold=None):
  1607. """Return a new datetime with new values for the specified fields."""
  1608. if year is None:
  1609. year = self.year
  1610. if month is None:
  1611. month = self.month
  1612. if day is None:
  1613. day = self.day
  1614. if hour is None:
  1615. hour = self.hour
  1616. if minute is None:
  1617. minute = self.minute
  1618. if second is None:
  1619. second = self.second
  1620. if microsecond is None:
  1621. microsecond = self.microsecond
  1622. if tzinfo is True:
  1623. tzinfo = self.tzinfo
  1624. if fold is None:
  1625. fold = self.fold
  1626. return type(self)(year, month, day, hour, minute, second,
  1627. microsecond, tzinfo, fold=fold)
  1628. def _local_timezone(self):
  1629. if self.tzinfo is None:
  1630. ts = self._mktime()
  1631. else:
  1632. ts = (self - _EPOCH) // timedelta(seconds=1)
  1633. localtm = _time.localtime(ts)
  1634. local = datetime(*localtm[:6])
  1635. # Extract TZ data
  1636. gmtoff = localtm.tm_gmtoff
  1637. zone = localtm.tm_zone
  1638. return timezone(timedelta(seconds=gmtoff), zone)
  1639. def astimezone(self, tz=None):
  1640. if tz is None:
  1641. tz = self._local_timezone()
  1642. elif not isinstance(tz, tzinfo):
  1643. raise TypeError("tz argument must be an instance of tzinfo")
  1644. mytz = self.tzinfo
  1645. if mytz is None:
  1646. mytz = self._local_timezone()
  1647. myoffset = mytz.utcoffset(self)
  1648. else:
  1649. myoffset = mytz.utcoffset(self)
  1650. if myoffset is None:
  1651. mytz = self.replace(tzinfo=None)._local_timezone()
  1652. myoffset = mytz.utcoffset(self)
  1653. if tz is mytz:
  1654. return self
  1655. # Convert self to UTC, and attach the new time zone object.
  1656. utc = (self - myoffset).replace(tzinfo=tz)
  1657. # Convert from UTC to tz's local time.
  1658. return tz.fromutc(utc)
  1659. # Ways to produce a string.
  1660. def ctime(self):
  1661. "Return ctime() style string."
  1662. weekday = self.toordinal() % 7 or 7
  1663. return "%s %s %2d %02d:%02d:%02d %04d" % (
  1664. _DAYNAMES[weekday],
  1665. _MONTHNAMES[self._month],
  1666. self._day,
  1667. self._hour, self._minute, self._second,
  1668. self._year)
  1669. def isoformat(self, sep='T', timespec='auto'):
  1670. """Return the time formatted according to ISO.
  1671. The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
  1672. By default, the fractional part is omitted if self.microsecond == 0.
  1673. If self.tzinfo is not None, the UTC offset is also attached, giving
  1674. giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
  1675. Optional argument sep specifies the separator between date and
  1676. time, default 'T'.
  1677. The optional argument timespec specifies the number of additional
  1678. terms of the time to include. Valid options are 'auto', 'hours',
  1679. 'minutes', 'seconds', 'milliseconds' and 'microseconds'.
  1680. """
  1681. s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
  1682. _format_time(self._hour, self._minute, self._second,
  1683. self._microsecond, timespec))
  1684. off = self.utcoffset()
  1685. tz = _format_offset(off)
  1686. if tz:
  1687. s += tz
  1688. return s
  1689. def __repr__(self):
  1690. """Convert to formal string, for repr()."""
  1691. L = [self._year, self._month, self._day, # These are never zero
  1692. self._hour, self._minute, self._second, self._microsecond]
  1693. if L[-1] == 0:
  1694. del L[-1]
  1695. if L[-1] == 0:
  1696. del L[-1]
  1697. s = "%s.%s(%s)" % (self.__class__.__module__,
  1698. self.__class__.__qualname__,
  1699. ", ".join(map(str, L)))
  1700. if self._tzinfo is not None:
  1701. assert s[-1:] == ")"
  1702. s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
  1703. if self._fold:
  1704. assert s[-1:] == ")"
  1705. s = s[:-1] + ", fold=1)"
  1706. return s
  1707. def __str__(self):
  1708. "Convert to string, for str()."
  1709. return self.isoformat(sep=' ')
  1710. @classmethod
  1711. def strptime(cls, date_string, format):
  1712. 'string, format -> new datetime parsed from a string (like time.strptime()).'
  1713. import _strptime
  1714. return _strptime._strptime_datetime(cls, date_string, format)
  1715. def utcoffset(self):
  1716. """Return the timezone offset as timedelta positive east of UTC (negative west of
  1717. UTC)."""
  1718. if self._tzinfo is None:
  1719. return None
  1720. offset = self._tzinfo.utcoffset(self)
  1721. _check_utc_offset("utcoffset", offset)
  1722. return offset
  1723. def tzname(self):
  1724. """Return the timezone name.
  1725. Note that the name is 100% informational -- there's no requirement that
  1726. it mean anything in particular. For example, "GMT", "UTC", "-500",
  1727. "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
  1728. """
  1729. if self._tzinfo is None:
  1730. return None
  1731. name = self._tzinfo.tzname(self)
  1732. _check_tzname(name)
  1733. return name
  1734. def dst(self):
  1735. """Return 0 if DST is not in effect, or the DST offset (as timedelta
  1736. positive eastward) if DST is in effect.
  1737. This is purely informational; the DST offset has already been added to
  1738. the UTC offset returned by utcoffset() if applicable, so there's no
  1739. need to consult dst() unless you're interested in displaying the DST
  1740. info.
  1741. """
  1742. if self._tzinfo is None:
  1743. return None
  1744. offset = self._tzinfo.dst(self)
  1745. _check_utc_offset("dst", offset)
  1746. return offset
  1747. # Comparisons of datetime objects with other.
  1748. def __eq__(self, other):
  1749. if isinstance(other, datetime):
  1750. return self._cmp(other, allow_mixed=True) == 0
  1751. elif not isinstance(other, date):
  1752. return NotImplemented
  1753. else:
  1754. return False
  1755. def __le__(self, other):
  1756. if isinstance(other, datetime):
  1757. return self._cmp(other) <= 0
  1758. elif not isinstance(other, date):
  1759. return NotImplemented
  1760. else:
  1761. _cmperror(self, other)
  1762. def __lt__(self, other):
  1763. if isinstance(other, datetime):
  1764. return self._cmp(other) < 0
  1765. elif not isinstance(other, date):
  1766. return NotImplemented
  1767. else:
  1768. _cmperror(self, other)
  1769. def __ge__(self, other):
  1770. if isinstance(other, datetime):
  1771. return self._cmp(other) >= 0
  1772. elif not isinstance(other, date):
  1773. return NotImplemented
  1774. else:
  1775. _cmperror(self, other)
  1776. def __gt__(self, other):
  1777. if isinstance(other, datetime):
  1778. return self._cmp(other) > 0
  1779. elif not isinstance(other, date):
  1780. return NotImplemented
  1781. else:
  1782. _cmperror(self, other)
  1783. def _cmp(self, other, allow_mixed=False):
  1784. assert isinstance(other, datetime)
  1785. mytz = self._tzinfo
  1786. ottz = other._tzinfo
  1787. myoff = otoff = None
  1788. if mytz is ottz:
  1789. base_compare = True
  1790. else:
  1791. myoff = self.utcoffset()
  1792. otoff = other.utcoffset()
  1793. # Assume that allow_mixed means that we are called from __eq__
  1794. if allow_mixed:
  1795. if myoff != self.replace(fold=not self.fold).utcoffset():
  1796. return 2
  1797. if otoff != other.replace(fold=not other.fold).utcoffset():
  1798. return 2
  1799. base_compare = myoff == otoff
  1800. if base_compare:
  1801. return _cmp((self._year, self._month, self._day,
  1802. self._hour, self._minute, self._second,
  1803. self._microsecond),
  1804. (other._year, other._month, other._day,
  1805. other._hour, other._minute, other._second,
  1806. other._microsecond))
  1807. if myoff is None or otoff is None:
  1808. if allow_mixed:
  1809. return 2 # arbitrary non-zero value
  1810. else:
  1811. raise TypeError("cannot compare naive and aware datetimes")
  1812. # XXX What follows could be done more efficiently...
  1813. diff = self - other # this will take offsets into account
  1814. if diff.days < 0:
  1815. return -1
  1816. return diff and 1 or 0
  1817. def __add__(self, other):
  1818. "Add a datetime and a timedelta."
  1819. if not isinstance(other, timedelta):
  1820. return NotImplemented
  1821. delta = timedelta(self.toordinal(),
  1822. hours=self._hour,
  1823. minutes=self._minute,
  1824. seconds=self._second,
  1825. microseconds=self._microsecond)
  1826. delta += other
  1827. hour, rem = divmod(delta.seconds, 3600)
  1828. minute, second = divmod(rem, 60)
  1829. if 0 < delta.days <= _MAXORDINAL:
  1830. return type(self).combine(date.fromordinal(delta.days),
  1831. time(hour, minute, second,
  1832. delta.microseconds,
  1833. tzinfo=self._tzinfo))
  1834. raise OverflowError("result out of range")
  1835. __radd__ = __add__
  1836. def __sub__(self, other):
  1837. "Subtract two datetimes, or a datetime and a timedelta."
  1838. if not isinstance(other, datetime):
  1839. if isinstance(other, timedelta):
  1840. return self + -other
  1841. return NotImplemented
  1842. days1 = self.toordinal()
  1843. days2 = other.toordinal()
  1844. secs1 = self._second + self._minute * 60 + self._hour * 3600
  1845. secs2 = other._second + other._minute * 60 + other._hour * 3600
  1846. base = timedelta(days1 - days2,
  1847. secs1 - secs2,
  1848. self._microsecond - other._microsecond)
  1849. if self._tzinfo is other._tzinfo:
  1850. return base
  1851. myoff = self.utcoffset()
  1852. otoff = other.utcoffset()
  1853. if myoff == otoff:
  1854. return base
  1855. if myoff is None or otoff is None:
  1856. raise TypeError("cannot mix naive and timezone-aware time")
  1857. return base + otoff - myoff
  1858. def __hash__(self):
  1859. if self._hashcode == -1:
  1860. if self.fold:
  1861. t = self.replace(fold=0)
  1862. else:
  1863. t = self
  1864. tzoff = t.utcoffset()
  1865. if tzoff is None:
  1866. self._hashcode = hash(t._getstate()[0])
  1867. else:
  1868. days = _ymd2ord(self.year, self.month, self.day)
  1869. seconds = self.hour * 3600 + self.minute * 60 + self.second
  1870. self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
  1871. return self._hashcode
  1872. # Pickle support.
  1873. def _getstate(self, protocol=3):
  1874. yhi, ylo = divmod(self._year, 256)
  1875. us2, us3 = divmod(self._microsecond, 256)
  1876. us1, us2 = divmod(us2, 256)
  1877. m = self._month
  1878. if self._fold and protocol > 3:
  1879. m += 128
  1880. basestate = bytes([yhi, ylo, m, self._day,
  1881. self._hour, self._minute, self._second,
  1882. us1, us2, us3])
  1883. if self._tzinfo is None:
  1884. return (basestate,)
  1885. else:
  1886. return (basestate, self._tzinfo)
  1887. def __setstate(self, string, tzinfo):
  1888. if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
  1889. raise TypeError("bad tzinfo state arg")
  1890. (yhi, ylo, m, self._day, self._hour,
  1891. self._minute, self._second, us1, us2, us3) = string
  1892. if m > 127:
  1893. self._fold = 1
  1894. self._month = m - 128
  1895. else:
  1896. self._fold = 0
  1897. self._month = m
  1898. self._year = yhi * 256 + ylo
  1899. self._microsecond = (((us1 << 8) | us2) << 8) | us3
  1900. self._tzinfo = tzinfo
  1901. def __reduce_ex__(self, protocol):
  1902. return (self.__class__, self._getstate(protocol))
  1903. def __reduce__(self):
  1904. return self.__reduce_ex__(2)
  1905. datetime.min = datetime(1, 1, 1)
  1906. datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
  1907. datetime.resolution = timedelta(microseconds=1)
  1908. def _isoweek1monday(year):
  1909. # Helper to calculate the day number of the Monday starting week 1
  1910. # XXX This could be done more efficiently
  1911. THURSDAY = 3
  1912. firstday = _ymd2ord(year, 1, 1)
  1913. firstweekday = (firstday + 6) % 7 # See weekday() above
  1914. week1monday = firstday - firstweekday
  1915. if firstweekday > THURSDAY:
  1916. week1monday += 7
  1917. return week1monday
  1918. class timezone(tzinfo):
  1919. __slots__ = '_offset', '_name'
  1920. # Sentinel value to disallow None
  1921. _Omitted = object()
  1922. def __new__(cls, offset, name=_Omitted):
  1923. if not isinstance(offset, timedelta):
  1924. raise TypeError("offset must be a timedelta")
  1925. if name is cls._Omitted:
  1926. if not offset:
  1927. return cls.utc
  1928. name = None
  1929. elif not isinstance(name, str):
  1930. raise TypeError("name must be a string")
  1931. if not cls._minoffset <= offset <= cls._maxoffset:
  1932. raise ValueError("offset must be a timedelta "
  1933. "strictly between -timedelta(hours=24) and "
  1934. "timedelta(hours=24).")
  1935. return cls._create(offset, name)
  1936. @classmethod
  1937. def _create(cls, offset, name=None):
  1938. self = tzinfo.__new__(cls)
  1939. self._offset = offset
  1940. self._name = name
  1941. return self
  1942. def __getinitargs__(self):
  1943. """pickle support"""
  1944. if self._name is None:
  1945. return (self._offset,)
  1946. return (self._offset, self._name)
  1947. def __eq__(self, other):
  1948. if isinstance(other, timezone):
  1949. return self._offset == other._offset
  1950. return NotImplemented
  1951. def __hash__(self):
  1952. return hash(self._offset)
  1953. def __repr__(self):
  1954. """Convert to formal string, for repr().
  1955. >>> tz = timezone.utc
  1956. >>> repr(tz)
  1957. 'datetime.timezone.utc'
  1958. >>> tz = timezone(timedelta(hours=-5), 'EST')
  1959. >>> repr(tz)
  1960. "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
  1961. """
  1962. if self is self.utc:
  1963. return 'datetime.timezone.utc'
  1964. if self._name is None:
  1965. return "%s.%s(%r)" % (self.__class__.__module__,
  1966. self.__class__.__qualname__,
  1967. self._offset)
  1968. return "%s.%s(%r, %r)" % (self.__class__.__module__,
  1969. self.__class__.__qualname__,
  1970. self._offset, self._name)
  1971. def __str__(self):
  1972. return self.tzname(None)
  1973. def utcoffset(self, dt):
  1974. if isinstance(dt, datetime) or dt is None:
  1975. return self._offset
  1976. raise TypeError("utcoffset() argument must be a datetime instance"
  1977. " or None")
  1978. def tzname(self, dt):
  1979. if isinstance(dt, datetime) or dt is None:
  1980. if self._name is None:
  1981. return self._name_from_offset(self._offset)
  1982. return self._name
  1983. raise TypeError("tzname() argument must be a datetime instance"
  1984. " or None")
  1985. def dst(self, dt):
  1986. if isinstance(dt, datetime) or dt is None:
  1987. return None
  1988. raise TypeError("dst() argument must be a datetime instance"
  1989. " or None")
  1990. def fromutc(self, dt):
  1991. if isinstance(dt, datetime):
  1992. if dt.tzinfo is not self:
  1993. raise ValueError("fromutc: dt.tzinfo "
  1994. "is not self")
  1995. return dt + self._offset
  1996. raise TypeError("fromutc() argument must be a datetime instance"
  1997. " or None")
  1998. _maxoffset = timedelta(hours=24, microseconds=-1)
  1999. _minoffset = -_maxoffset
  2000. @staticmethod
  2001. def _name_from_offset(delta):
  2002. if not delta:
  2003. return 'UTC'
  2004. if delta < timedelta(0):
  2005. sign = '-'
  2006. delta = -delta
  2007. else:
  2008. sign = '+'
  2009. hours, rest = divmod(delta, timedelta(hours=1))
  2010. minutes, rest = divmod(rest, timedelta(minutes=1))
  2011. seconds = rest.seconds
  2012. microseconds = rest.microseconds
  2013. if microseconds:
  2014. return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
  2015. f'.{microseconds:06d}')
  2016. if seconds:
  2017. return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
  2018. return f'UTC{sign}{hours:02d}:{minutes:02d}'
  2019. UTC = timezone.utc = timezone._create(timedelta(0))
  2020. # bpo-37642: These attributes are rounded to the nearest minute for backwards
  2021. # compatibility, even though the constructor will accept a wider range of
  2022. # values. This may change in the future.
  2023. timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
  2024. timezone.max = timezone._create(timedelta(hours=23, minutes=59))
  2025. _EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
  2026. # Some time zone algebra. For a datetime x, let
  2027. # x.n = x stripped of its timezone -- its naive time.
  2028. # x.o = x.utcoffset(), and assuming that doesn't raise an exception or
  2029. # return None
  2030. # x.d = x.dst(), and assuming that doesn't raise an exception or
  2031. # return None
  2032. # x.s = x's standard offset, x.o - x.d
  2033. #
  2034. # Now some derived rules, where k is a duration (timedelta).
  2035. #
  2036. # 1. x.o = x.s + x.d
  2037. # This follows from the definition of x.s.
  2038. #
  2039. # 2. If x and y have the same tzinfo member, x.s = y.s.
  2040. # This is actually a requirement, an assumption we need to make about
  2041. # sane tzinfo classes.
  2042. #
  2043. # 3. The naive UTC time corresponding to x is x.n - x.o.
  2044. # This is again a requirement for a sane tzinfo class.
  2045. #
  2046. # 4. (x+k).s = x.s
  2047. # This follows from #2, and that datetime.timetz+timedelta preserves tzinfo.
  2048. #
  2049. # 5. (x+k).n = x.n + k
  2050. # Again follows from how arithmetic is defined.
  2051. #
  2052. # Now we can explain tz.fromutc(x). Let's assume it's an interesting case
  2053. # (meaning that the various tzinfo methods exist, and don't blow up or return
  2054. # None when called).
  2055. #
  2056. # The function wants to return a datetime y with timezone tz, equivalent to x.
  2057. # x is already in UTC.
  2058. #
  2059. # By #3, we want
  2060. #
  2061. # y.n - y.o = x.n [1]
  2062. #
  2063. # The algorithm starts by attaching tz to x.n, and calling that y. So
  2064. # x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
  2065. # becomes true; in effect, we want to solve [2] for k:
  2066. #
  2067. # (y+k).n - (y+k).o = x.n [2]
  2068. #
  2069. # By #1, this is the same as
  2070. #
  2071. # (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
  2072. #
  2073. # By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
  2074. # Substituting that into [3],
  2075. #
  2076. # x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
  2077. # k - (y+k).s - (y+k).d = 0; rearranging,
  2078. # k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
  2079. # k = y.s - (y+k).d
  2080. #
  2081. # On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
  2082. # approximate k by ignoring the (y+k).d term at first. Note that k can't be
  2083. # very large, since all offset-returning methods return a duration of magnitude
  2084. # less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
  2085. # be 0, so ignoring it has no consequence then.
  2086. #
  2087. # In any case, the new value is
  2088. #
  2089. # z = y + y.s [4]
  2090. #
  2091. # It's helpful to step back at look at [4] from a higher level: it's simply
  2092. # mapping from UTC to tz's standard time.
  2093. #
  2094. # At this point, if
  2095. #
  2096. # z.n - z.o = x.n [5]
  2097. #
  2098. # we have an equivalent time, and are almost done. The insecurity here is
  2099. # at the start of daylight time. Picture US Eastern for concreteness. The wall
  2100. # time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
  2101. # sense then. The docs ask that an Eastern tzinfo class consider such a time to
  2102. # be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
  2103. # on the day DST starts. We want to return the 1:MM EST spelling because that's
  2104. # the only spelling that makes sense on the local wall clock.
  2105. #
  2106. # In fact, if [5] holds at this point, we do have the standard-time spelling,
  2107. # but that takes a bit of proof. We first prove a stronger result. What's the
  2108. # difference between the LHS and RHS of [5]? Let
  2109. #
  2110. # diff = x.n - (z.n - z.o) [6]
  2111. #
  2112. # Now
  2113. # z.n = by [4]
  2114. # (y + y.s).n = by #5
  2115. # y.n + y.s = since y.n = x.n
  2116. # x.n + y.s = since z and y are have the same tzinfo member,
  2117. # y.s = z.s by #2
  2118. # x.n + z.s
  2119. #
  2120. # Plugging that back into [6] gives
  2121. #
  2122. # diff =
  2123. # x.n - ((x.n + z.s) - z.o) = expanding
  2124. # x.n - x.n - z.s + z.o = cancelling
  2125. # - z.s + z.o = by #2
  2126. # z.d
  2127. #
  2128. # So diff = z.d.
  2129. #
  2130. # If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
  2131. # spelling we wanted in the endcase described above. We're done. Contrarily,
  2132. # if z.d = 0, then we have a UTC equivalent, and are also done.
  2133. #
  2134. # If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
  2135. # add to z (in effect, z is in tz's standard time, and we need to shift the
  2136. # local clock into tz's daylight time).
  2137. #
  2138. # Let
  2139. #
  2140. # z' = z + z.d = z + diff [7]
  2141. #
  2142. # and we can again ask whether
  2143. #
  2144. # z'.n - z'.o = x.n [8]
  2145. #
  2146. # If so, we're done. If not, the tzinfo class is insane, according to the
  2147. # assumptions we've made. This also requires a bit of proof. As before, let's
  2148. # compute the difference between the LHS and RHS of [8] (and skipping some of
  2149. # the justifications for the kinds of substitutions we've done several times
  2150. # already):
  2151. #
  2152. # diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
  2153. # x.n - (z.n + diff - z'.o) = replacing diff via [6]
  2154. # x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
  2155. # x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
  2156. # - z.n + z.n - z.o + z'.o = cancel z.n
  2157. # - z.o + z'.o = #1 twice
  2158. # -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
  2159. # z'.d - z.d
  2160. #
  2161. # So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
  2162. # we've found the UTC-equivalent so are done. In fact, we stop with [7] and
  2163. # return z', not bothering to compute z'.d.
  2164. #
  2165. # How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
  2166. # a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
  2167. # would have to change the result dst() returns: we start in DST, and moving
  2168. # a little further into it takes us out of DST.
  2169. #
  2170. # There isn't a sane case where this can happen. The closest it gets is at
  2171. # the end of DST, where there's an hour in UTC with no spelling in a hybrid
  2172. # tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
  2173. # that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
  2174. # UTC) because the docs insist on that, but 0:MM is taken as being in daylight
  2175. # time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
  2176. # clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
  2177. # standard time. Since that's what the local clock *does*, we want to map both
  2178. # UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
  2179. # in local time, but so it goes -- it's the way the local clock works.
  2180. #
  2181. # When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
  2182. # so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
  2183. # z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
  2184. # (correctly) concludes that z' is not UTC-equivalent to x.
  2185. #
  2186. # Because we know z.d said z was in daylight time (else [5] would have held and
  2187. # we would have stopped then), and we know z.d != z'.d (else [8] would have held
  2188. # and we have stopped then), and there are only 2 possible values dst() can
  2189. # return in Eastern, it follows that z'.d must be 0 (which it is in the example,
  2190. # but the reasoning doesn't depend on the example -- it depends on there being
  2191. # two possible dst() outcomes, one zero and the other non-zero). Therefore
  2192. # z' must be in standard time, and is the spelling we want in this case.
  2193. #
  2194. # Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
  2195. # concerned (because it takes z' as being in standard time rather than the
  2196. # daylight time we intend here), but returning it gives the real-life "local
  2197. # clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
  2198. # tz.
  2199. #
  2200. # When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
  2201. # the 1:MM standard time spelling we want.
  2202. #
  2203. # So how can this break? One of the assumptions must be violated. Two
  2204. # possibilities:
  2205. #
  2206. # 1) [2] effectively says that y.s is invariant across all y belong to a given
  2207. # time zone. This isn't true if, for political reasons or continental drift,
  2208. # a region decides to change its base offset from UTC.
  2209. #
  2210. # 2) There may be versions of "double daylight" time where the tail end of
  2211. # the analysis gives up a step too early. I haven't thought about that
  2212. # enough to say.
  2213. #
  2214. # In any case, it's clear that the default fromutc() is strong enough to handle
  2215. # "almost all" time zones: so long as the standard offset is invariant, it
  2216. # doesn't matter if daylight time transition points change from year to year, or
  2217. # if daylight time is skipped in some years; it doesn't matter how large or
  2218. # small dst() may get within its bounds; and it doesn't even matter if some
  2219. # perverse time zone returns a negative dst()). So a breaking case must be
  2220. # pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
  2221. try:
  2222. from _datetime import *
  2223. except ImportError:
  2224. pass
  2225. else:
  2226. # Clean up unused names
  2227. del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
  2228. _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
  2229. _check_date_fields, _check_time_fields,
  2230. _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
  2231. _date_class, _days_before_month, _days_before_year, _days_in_month,
  2232. _format_time, _format_offset, _index, _is_leap, _isoweek1monday, _math,
  2233. _ord2ymd, _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord,
  2234. _divide_and_round, _parse_isoformat_date, _parse_isoformat_time,
  2235. _parse_hh_mm_ss_ff, _IsoCalendarDate, _isoweek_to_gregorian,
  2236. _find_isoformat_datetime_separator, _FRACTION_CORRECTION,
  2237. _is_ascii_digit)
  2238. # XXX Since import * above excludes names that start with _,
  2239. # docstring does not get overwritten. In the future, it may be
  2240. # appropriate to maintain a single module level docstring and
  2241. # remove the following line.
  2242. from _datetime import __doc__