_zoneinfo.c 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784
  1. #ifndef Py_BUILD_CORE_BUILTIN
  2. # define Py_BUILD_CORE_MODULE 1
  3. #endif
  4. #include "Python.h"
  5. #include "pycore_long.h" // _PyLong_GetOne()
  6. #include "structmember.h"
  7. #include <ctype.h>
  8. #include <stddef.h>
  9. #include <stdint.h>
  10. #include "datetime.h"
  11. #include "clinic/_zoneinfo.c.h"
  12. /*[clinic input]
  13. module zoneinfo
  14. class zoneinfo.ZoneInfo "PyObject *" "PyTypeObject *"
  15. [clinic start generated code]*/
  16. /*[clinic end generated code: output=da39a3ee5e6b4b0d input=d12c73c0eef36df8]*/
  17. typedef struct TransitionRuleType TransitionRuleType;
  18. typedef struct StrongCacheNode StrongCacheNode;
  19. typedef struct {
  20. PyObject *utcoff;
  21. PyObject *dstoff;
  22. PyObject *tzname;
  23. long utcoff_seconds;
  24. } _ttinfo;
  25. typedef struct {
  26. _ttinfo std;
  27. _ttinfo dst;
  28. int dst_diff;
  29. TransitionRuleType *start;
  30. TransitionRuleType *end;
  31. unsigned char std_only;
  32. } _tzrule;
  33. typedef struct {
  34. PyDateTime_TZInfo base;
  35. PyObject *key;
  36. PyObject *file_repr;
  37. PyObject *weakreflist;
  38. size_t num_transitions;
  39. size_t num_ttinfos;
  40. int64_t *trans_list_utc;
  41. int64_t *trans_list_wall[2];
  42. _ttinfo **trans_ttinfos; // References to the ttinfo for each transition
  43. _ttinfo *ttinfo_before;
  44. _tzrule tzrule_after;
  45. _ttinfo *_ttinfos; // Unique array of ttinfos for ease of deallocation
  46. unsigned char fixed_offset;
  47. unsigned char source;
  48. } PyZoneInfo_ZoneInfo;
  49. struct TransitionRuleType {
  50. int64_t (*year_to_timestamp)(TransitionRuleType *, int);
  51. };
  52. typedef struct {
  53. TransitionRuleType base;
  54. uint8_t month; /* 1 - 12 */
  55. uint8_t week; /* 1 - 5 */
  56. uint8_t day; /* 0 - 6 */
  57. int16_t hour; /* -167 - 167, RFC 8536 §3.3.1 */
  58. int8_t minute; /* signed 2 digits */
  59. int8_t second; /* signed 2 digits */
  60. } CalendarRule;
  61. typedef struct {
  62. TransitionRuleType base;
  63. uint8_t julian; /* 0, 1 */
  64. uint16_t day; /* 0 - 365 */
  65. int16_t hour; /* -167 - 167, RFC 8536 §3.3.1 */
  66. int8_t minute; /* signed 2 digits */
  67. int8_t second; /* signed 2 digits */
  68. } DayRule;
  69. struct StrongCacheNode {
  70. StrongCacheNode *next;
  71. StrongCacheNode *prev;
  72. PyObject *key;
  73. PyObject *zone;
  74. };
  75. typedef struct {
  76. PyTypeObject *ZoneInfoType;
  77. // Imports
  78. PyObject *io_open;
  79. PyObject *_tzpath_find_tzfile;
  80. PyObject *_common_mod;
  81. // Caches
  82. PyObject *TIMEDELTA_CACHE;
  83. PyObject *ZONEINFO_WEAK_CACHE;
  84. StrongCacheNode *ZONEINFO_STRONG_CACHE;
  85. _ttinfo NO_TTINFO;
  86. } zoneinfo_state;
  87. // Constants
  88. static const int EPOCHORDINAL = 719163;
  89. static int DAYS_IN_MONTH[] = {
  90. -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  91. };
  92. static int DAYS_BEFORE_MONTH[] = {
  93. -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
  94. };
  95. static const int SOURCE_NOCACHE = 0;
  96. static const int SOURCE_CACHE = 1;
  97. static const int SOURCE_FILE = 2;
  98. static const size_t ZONEINFO_STRONG_CACHE_MAX_SIZE = 8;
  99. // Forward declarations
  100. static int
  101. load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self,
  102. PyObject *file_obj);
  103. static void
  104. utcoff_to_dstoff(size_t *trans_idx, long *utcoffs, long *dstoffs,
  105. unsigned char *isdsts, size_t num_transitions,
  106. size_t num_ttinfos);
  107. static int
  108. ts_to_local(size_t *trans_idx, int64_t *trans_utc, long *utcoff,
  109. int64_t *trans_local[2], size_t num_ttinfos,
  110. size_t num_transitions);
  111. static int
  112. parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out);
  113. static int
  114. parse_abbr(const char **p, PyObject **abbr);
  115. static int
  116. parse_tz_delta(const char **p, long *total_seconds);
  117. static int
  118. parse_transition_time(const char **p, int *hour, int *minute, int *second);
  119. static int
  120. parse_transition_rule(const char **p, TransitionRuleType **out);
  121. static _ttinfo *
  122. find_tzrule_ttinfo(_tzrule *rule, int64_t ts, unsigned char fold, int year);
  123. static _ttinfo *
  124. find_tzrule_ttinfo_fromutc(_tzrule *rule, int64_t ts, int year,
  125. unsigned char *fold);
  126. static int
  127. build_ttinfo(zoneinfo_state *state, long utcoffset, long dstoffset,
  128. PyObject *tzname, _ttinfo *out);
  129. static void
  130. xdecref_ttinfo(_ttinfo *ttinfo);
  131. static int
  132. ttinfo_eq(const _ttinfo *const tti0, const _ttinfo *const tti1);
  133. static int
  134. build_tzrule(zoneinfo_state *state, PyObject *std_abbr, PyObject *dst_abbr,
  135. long std_offset, long dst_offset, TransitionRuleType *start,
  136. TransitionRuleType *end, _tzrule *out);
  137. static void
  138. free_tzrule(_tzrule *tzrule);
  139. static PyObject *
  140. load_timedelta(zoneinfo_state *state, long seconds);
  141. static int
  142. get_local_timestamp(PyObject *dt, int64_t *local_ts);
  143. static _ttinfo *
  144. find_ttinfo(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *dt);
  145. static int
  146. ymd_to_ord(int y, int m, int d);
  147. static int
  148. is_leap_year(int year);
  149. static size_t
  150. _bisect(const int64_t value, const int64_t *arr, size_t size);
  151. static int
  152. eject_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  153. PyObject *key);
  154. static void
  155. clear_strong_cache(zoneinfo_state *state, const PyTypeObject *const type);
  156. static void
  157. update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  158. PyObject *key, PyObject *zone);
  159. static PyObject *
  160. zone_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  161. PyObject *const key);
  162. static inline zoneinfo_state *
  163. zoneinfo_get_state(PyObject *mod)
  164. {
  165. zoneinfo_state *state = (zoneinfo_state *)PyModule_GetState(mod);
  166. assert(state != NULL);
  167. return state;
  168. }
  169. static inline zoneinfo_state *
  170. zoneinfo_get_state_by_cls(PyTypeObject *cls)
  171. {
  172. zoneinfo_state *state = (zoneinfo_state *)_PyType_GetModuleState(cls);
  173. assert(state != NULL);
  174. return state;
  175. }
  176. static struct PyModuleDef zoneinfomodule;
  177. static inline zoneinfo_state *
  178. zoneinfo_get_state_by_self(PyTypeObject *self)
  179. {
  180. PyObject *mod = PyType_GetModuleByDef(self, &zoneinfomodule);
  181. assert(mod != NULL);
  182. return zoneinfo_get_state(mod);
  183. }
  184. static PyObject *
  185. zoneinfo_new_instance(zoneinfo_state *state, PyTypeObject *type, PyObject *key)
  186. {
  187. PyObject *file_obj = NULL;
  188. PyObject *file_path = NULL;
  189. file_path = PyObject_CallFunctionObjArgs(state->_tzpath_find_tzfile,
  190. key, NULL);
  191. if (file_path == NULL) {
  192. return NULL;
  193. }
  194. else if (file_path == Py_None) {
  195. PyObject *meth = state->_common_mod;
  196. file_obj = PyObject_CallMethod(meth, "load_tzdata", "O", key);
  197. if (file_obj == NULL) {
  198. Py_DECREF(file_path);
  199. return NULL;
  200. }
  201. }
  202. PyObject *self = (PyObject *)(type->tp_alloc(type, 0));
  203. if (self == NULL) {
  204. goto error;
  205. }
  206. if (file_obj == NULL) {
  207. PyObject *func = state->io_open;
  208. file_obj = PyObject_CallFunction(func, "Os", file_path, "rb");
  209. if (file_obj == NULL) {
  210. goto error;
  211. }
  212. }
  213. if (load_data(state, (PyZoneInfo_ZoneInfo *)self, file_obj)) {
  214. goto error;
  215. }
  216. PyObject *rv = PyObject_CallMethod(file_obj, "close", NULL);
  217. Py_SETREF(file_obj, NULL);
  218. if (rv == NULL) {
  219. goto error;
  220. }
  221. Py_DECREF(rv);
  222. ((PyZoneInfo_ZoneInfo *)self)->key = Py_NewRef(key);
  223. goto cleanup;
  224. error:
  225. Py_CLEAR(self);
  226. cleanup:
  227. if (file_obj != NULL) {
  228. PyObject *exc = PyErr_GetRaisedException();
  229. PyObject *tmp = PyObject_CallMethod(file_obj, "close", NULL);
  230. _PyErr_ChainExceptions1(exc);
  231. if (tmp == NULL) {
  232. Py_CLEAR(self);
  233. }
  234. Py_XDECREF(tmp);
  235. Py_DECREF(file_obj);
  236. }
  237. Py_DECREF(file_path);
  238. return self;
  239. }
  240. static PyObject *
  241. get_weak_cache(zoneinfo_state *state, PyTypeObject *type)
  242. {
  243. if (type == state->ZoneInfoType) {
  244. return state->ZONEINFO_WEAK_CACHE;
  245. }
  246. else {
  247. PyObject *cache =
  248. PyObject_GetAttrString((PyObject *)type, "_weak_cache");
  249. // We are assuming that the type lives at least as long as the function
  250. // that calls get_weak_cache, and that it holds a reference to the
  251. // cache, so we'll return a "borrowed reference".
  252. Py_XDECREF(cache);
  253. return cache;
  254. }
  255. }
  256. static PyObject *
  257. zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
  258. {
  259. PyObject *key = NULL;
  260. static char *kwlist[] = {"key", NULL};
  261. if (PyArg_ParseTupleAndKeywords(args, kw, "O", kwlist, &key) == 0) {
  262. return NULL;
  263. }
  264. zoneinfo_state *state = zoneinfo_get_state_by_self(type);
  265. PyObject *instance = zone_from_strong_cache(state, type, key);
  266. if (instance != NULL || PyErr_Occurred()) {
  267. return instance;
  268. }
  269. PyObject *weak_cache = get_weak_cache(state, type);
  270. instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None);
  271. if (instance == NULL) {
  272. return NULL;
  273. }
  274. if (instance == Py_None) {
  275. Py_DECREF(instance);
  276. PyObject *tmp = zoneinfo_new_instance(state, type, key);
  277. if (tmp == NULL) {
  278. return NULL;
  279. }
  280. instance =
  281. PyObject_CallMethod(weak_cache, "setdefault", "OO", key, tmp);
  282. Py_DECREF(tmp);
  283. if (instance == NULL) {
  284. return NULL;
  285. }
  286. ((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
  287. }
  288. update_strong_cache(state, type, key, instance);
  289. return instance;
  290. }
  291. static int
  292. zoneinfo_traverse(PyZoneInfo_ZoneInfo *self, visitproc visit, void *arg)
  293. {
  294. Py_VISIT(Py_TYPE(self));
  295. Py_VISIT(self->key);
  296. return 0;
  297. }
  298. static int
  299. zoneinfo_clear(PyZoneInfo_ZoneInfo *self)
  300. {
  301. Py_CLEAR(self->key);
  302. Py_CLEAR(self->file_repr);
  303. return 0;
  304. }
  305. static void
  306. zoneinfo_dealloc(PyObject *obj_self)
  307. {
  308. PyZoneInfo_ZoneInfo *self = (PyZoneInfo_ZoneInfo *)obj_self;
  309. PyTypeObject *tp = Py_TYPE(self);
  310. PyObject_GC_UnTrack(self);
  311. if (self->weakreflist != NULL) {
  312. PyObject_ClearWeakRefs(obj_self);
  313. }
  314. if (self->trans_list_utc != NULL) {
  315. PyMem_Free(self->trans_list_utc);
  316. }
  317. for (size_t i = 0; i < 2; i++) {
  318. if (self->trans_list_wall[i] != NULL) {
  319. PyMem_Free(self->trans_list_wall[i]);
  320. }
  321. }
  322. if (self->_ttinfos != NULL) {
  323. for (size_t i = 0; i < self->num_ttinfos; ++i) {
  324. xdecref_ttinfo(&(self->_ttinfos[i]));
  325. }
  326. PyMem_Free(self->_ttinfos);
  327. }
  328. if (self->trans_ttinfos != NULL) {
  329. PyMem_Free(self->trans_ttinfos);
  330. }
  331. free_tzrule(&(self->tzrule_after));
  332. zoneinfo_clear(self);
  333. tp->tp_free(obj_self);
  334. Py_DECREF(tp);
  335. }
  336. /*[clinic input]
  337. @classmethod
  338. zoneinfo.ZoneInfo.from_file
  339. cls: defining_class
  340. file_obj: object
  341. /
  342. key: object = None
  343. Create a ZoneInfo file from a file object.
  344. [clinic start generated code]*/
  345. static PyObject *
  346. zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyTypeObject *cls,
  347. PyObject *file_obj, PyObject *key)
  348. /*[clinic end generated code: output=77887d1d56a48324 input=d26111f29eed6863]*/
  349. {
  350. PyObject *file_repr = NULL;
  351. PyZoneInfo_ZoneInfo *self = NULL;
  352. PyObject *obj_self = (PyObject *)(type->tp_alloc(type, 0));
  353. self = (PyZoneInfo_ZoneInfo *)obj_self;
  354. if (self == NULL) {
  355. return NULL;
  356. }
  357. file_repr = PyUnicode_FromFormat("%R", file_obj);
  358. if (file_repr == NULL) {
  359. goto error;
  360. }
  361. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  362. if (load_data(state, self, file_obj)) {
  363. goto error;
  364. }
  365. self->source = SOURCE_FILE;
  366. self->file_repr = file_repr;
  367. self->key = Py_NewRef(key);
  368. return obj_self;
  369. error:
  370. Py_XDECREF(file_repr);
  371. Py_XDECREF(self);
  372. return NULL;
  373. }
  374. /*[clinic input]
  375. @classmethod
  376. zoneinfo.ZoneInfo.no_cache
  377. cls: defining_class
  378. /
  379. key: object
  380. Get a new instance of ZoneInfo, bypassing the cache.
  381. [clinic start generated code]*/
  382. static PyObject *
  383. zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyTypeObject *cls,
  384. PyObject *key)
  385. /*[clinic end generated code: output=b0b09b3344c171b7 input=0238f3d56b1ea3f1]*/
  386. {
  387. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  388. PyObject *out = zoneinfo_new_instance(state, type, key);
  389. if (out != NULL) {
  390. ((PyZoneInfo_ZoneInfo *)out)->source = SOURCE_NOCACHE;
  391. }
  392. return out;
  393. }
  394. /*[clinic input]
  395. @classmethod
  396. zoneinfo.ZoneInfo.clear_cache
  397. cls: defining_class
  398. /
  399. *
  400. only_keys: object = None
  401. Clear the ZoneInfo cache.
  402. [clinic start generated code]*/
  403. static PyObject *
  404. zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
  405. PyObject *only_keys)
  406. /*[clinic end generated code: output=114d9b7c8a22e660 input=e32ca3bb396788ba]*/
  407. {
  408. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  409. PyObject *weak_cache = get_weak_cache(state, type);
  410. if (only_keys == NULL || only_keys == Py_None) {
  411. PyObject *rv = PyObject_CallMethod(weak_cache, "clear", NULL);
  412. if (rv != NULL) {
  413. Py_DECREF(rv);
  414. }
  415. clear_strong_cache(state, type);
  416. }
  417. else {
  418. PyObject *item = NULL;
  419. PyObject *pop = PyUnicode_FromString("pop");
  420. if (pop == NULL) {
  421. return NULL;
  422. }
  423. PyObject *iter = PyObject_GetIter(only_keys);
  424. if (iter == NULL) {
  425. Py_DECREF(pop);
  426. return NULL;
  427. }
  428. while ((item = PyIter_Next(iter))) {
  429. // Remove from strong cache
  430. if (eject_from_strong_cache(state, type, item) < 0) {
  431. Py_DECREF(item);
  432. break;
  433. }
  434. // Remove from weak cache
  435. PyObject *tmp = PyObject_CallMethodObjArgs(weak_cache, pop, item,
  436. Py_None, NULL);
  437. Py_DECREF(item);
  438. if (tmp == NULL) {
  439. break;
  440. }
  441. Py_DECREF(tmp);
  442. }
  443. Py_DECREF(iter);
  444. Py_DECREF(pop);
  445. }
  446. if (PyErr_Occurred()) {
  447. return NULL;
  448. }
  449. Py_RETURN_NONE;
  450. }
  451. /*[clinic input]
  452. zoneinfo.ZoneInfo.utcoffset
  453. cls: defining_class
  454. dt: object
  455. /
  456. Retrieve a timedelta representing the UTC offset in a zone at the given datetime.
  457. [clinic start generated code]*/
  458. static PyObject *
  459. zoneinfo_ZoneInfo_utcoffset_impl(PyObject *self, PyTypeObject *cls,
  460. PyObject *dt)
  461. /*[clinic end generated code: output=b71016c319ba1f91 input=2bb6c5364938f19c]*/
  462. {
  463. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  464. _ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
  465. if (tti == NULL) {
  466. return NULL;
  467. }
  468. return Py_NewRef(tti->utcoff);
  469. }
  470. /*[clinic input]
  471. zoneinfo.ZoneInfo.dst
  472. cls: defining_class
  473. dt: object
  474. /
  475. Retrieve a timedelta representing the amount of DST applied in a zone at the given datetime.
  476. [clinic start generated code]*/
  477. static PyObject *
  478. zoneinfo_ZoneInfo_dst_impl(PyObject *self, PyTypeObject *cls, PyObject *dt)
  479. /*[clinic end generated code: output=cb6168d7723a6ae6 input=2167fb80cf8645c6]*/
  480. {
  481. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  482. _ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
  483. if (tti == NULL) {
  484. return NULL;
  485. }
  486. return Py_NewRef(tti->dstoff);
  487. }
  488. /*[clinic input]
  489. zoneinfo.ZoneInfo.tzname
  490. cls: defining_class
  491. dt: object
  492. /
  493. Retrieve a string containing the abbreviation for the time zone that applies in a zone at a given datetime.
  494. [clinic start generated code]*/
  495. static PyObject *
  496. zoneinfo_ZoneInfo_tzname_impl(PyObject *self, PyTypeObject *cls,
  497. PyObject *dt)
  498. /*[clinic end generated code: output=3b6ae6c3053ea75a input=15a59a4f92ed1f1f]*/
  499. {
  500. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  501. _ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
  502. if (tti == NULL) {
  503. return NULL;
  504. }
  505. return Py_NewRef(tti->tzname);
  506. }
  507. #define GET_DT_TZINFO PyDateTime_DATE_GET_TZINFO
  508. static PyObject *
  509. zoneinfo_fromutc(PyObject *obj_self, PyObject *dt)
  510. {
  511. if (!PyDateTime_Check(dt)) {
  512. PyErr_SetString(PyExc_TypeError,
  513. "fromutc: argument must be a datetime");
  514. return NULL;
  515. }
  516. if (GET_DT_TZINFO(dt) != obj_self) {
  517. PyErr_SetString(PyExc_ValueError,
  518. "fromutc: dt.tzinfo "
  519. "is not self");
  520. return NULL;
  521. }
  522. PyZoneInfo_ZoneInfo *self = (PyZoneInfo_ZoneInfo *)obj_self;
  523. int64_t timestamp;
  524. if (get_local_timestamp(dt, &timestamp)) {
  525. return NULL;
  526. }
  527. size_t num_trans = self->num_transitions;
  528. _ttinfo *tti = NULL;
  529. unsigned char fold = 0;
  530. if (num_trans >= 1 && timestamp < self->trans_list_utc[0]) {
  531. tti = self->ttinfo_before;
  532. }
  533. else if (num_trans == 0 ||
  534. timestamp > self->trans_list_utc[num_trans - 1]) {
  535. tti = find_tzrule_ttinfo_fromutc(&(self->tzrule_after), timestamp,
  536. PyDateTime_GET_YEAR(dt), &fold);
  537. // Immediately after the last manual transition, the fold/gap is
  538. // between self->trans_ttinfos[num_transitions - 1] and whatever
  539. // ttinfo applies immediately after the last transition, not between
  540. // the STD and DST rules in the tzrule_after, so we may need to
  541. // adjust the fold value.
  542. if (num_trans) {
  543. _ttinfo *tti_prev = NULL;
  544. if (num_trans == 1) {
  545. tti_prev = self->ttinfo_before;
  546. }
  547. else {
  548. tti_prev = self->trans_ttinfos[num_trans - 2];
  549. }
  550. int64_t diff = tti_prev->utcoff_seconds - tti->utcoff_seconds;
  551. if (diff > 0 &&
  552. timestamp < (self->trans_list_utc[num_trans - 1] + diff)) {
  553. fold = 1;
  554. }
  555. }
  556. }
  557. else {
  558. size_t idx = _bisect(timestamp, self->trans_list_utc, num_trans);
  559. _ttinfo *tti_prev = NULL;
  560. if (idx >= 2) {
  561. tti_prev = self->trans_ttinfos[idx - 2];
  562. tti = self->trans_ttinfos[idx - 1];
  563. }
  564. else {
  565. tti_prev = self->ttinfo_before;
  566. tti = self->trans_ttinfos[0];
  567. }
  568. // Detect fold
  569. int64_t shift =
  570. (int64_t)(tti_prev->utcoff_seconds - tti->utcoff_seconds);
  571. if (shift > (timestamp - self->trans_list_utc[idx - 1])) {
  572. fold = 1;
  573. }
  574. }
  575. PyObject *tmp = PyNumber_Add(dt, tti->utcoff);
  576. if (tmp == NULL) {
  577. return NULL;
  578. }
  579. if (fold) {
  580. if (PyDateTime_CheckExact(tmp)) {
  581. ((PyDateTime_DateTime *)tmp)->fold = 1;
  582. dt = tmp;
  583. }
  584. else {
  585. PyObject *replace = PyObject_GetAttrString(tmp, "replace");
  586. Py_DECREF(tmp);
  587. if (replace == NULL) {
  588. return NULL;
  589. }
  590. PyObject *args = PyTuple_New(0);
  591. if (args == NULL) {
  592. Py_DECREF(replace);
  593. return NULL;
  594. }
  595. PyObject *kwargs = PyDict_New();
  596. if (kwargs == NULL) {
  597. Py_DECREF(replace);
  598. Py_DECREF(args);
  599. return NULL;
  600. }
  601. dt = NULL;
  602. if (!PyDict_SetItemString(kwargs, "fold", _PyLong_GetOne())) {
  603. dt = PyObject_Call(replace, args, kwargs);
  604. }
  605. Py_DECREF(args);
  606. Py_DECREF(kwargs);
  607. Py_DECREF(replace);
  608. if (dt == NULL) {
  609. return NULL;
  610. }
  611. }
  612. }
  613. else {
  614. dt = tmp;
  615. }
  616. return dt;
  617. }
  618. static PyObject *
  619. zoneinfo_repr(PyZoneInfo_ZoneInfo *self)
  620. {
  621. PyObject *rv = NULL;
  622. const char *type_name = Py_TYPE((PyObject *)self)->tp_name;
  623. if (!(self->key == Py_None)) {
  624. rv = PyUnicode_FromFormat("%s(key=%R)", type_name, self->key);
  625. }
  626. else {
  627. assert(PyUnicode_Check(self->file_repr));
  628. rv = PyUnicode_FromFormat("%s.from_file(%U)", type_name,
  629. self->file_repr);
  630. }
  631. return rv;
  632. }
  633. static PyObject *
  634. zoneinfo_str(PyZoneInfo_ZoneInfo *self)
  635. {
  636. if (!(self->key == Py_None)) {
  637. return Py_NewRef(self->key);
  638. }
  639. else {
  640. return zoneinfo_repr(self);
  641. }
  642. }
  643. /* Pickles the ZoneInfo object by key and source.
  644. *
  645. * ZoneInfo objects are pickled by reference to the TZif file that they came
  646. * from, which means that the exact transitions may be different or the file
  647. * may not un-pickle if the data has changed on disk in the interim.
  648. *
  649. * It is necessary to include a bit indicating whether or not the object
  650. * was constructed from the cache, because from-cache objects will hit the
  651. * unpickling process's cache, whereas no-cache objects will bypass it.
  652. *
  653. * Objects constructed from ZoneInfo.from_file cannot be pickled.
  654. */
  655. static PyObject *
  656. zoneinfo_reduce(PyObject *obj_self, PyObject *unused)
  657. {
  658. PyZoneInfo_ZoneInfo *self = (PyZoneInfo_ZoneInfo *)obj_self;
  659. if (self->source == SOURCE_FILE) {
  660. // Objects constructed from files cannot be pickled.
  661. PyObject *pickle_error =
  662. _PyImport_GetModuleAttrString("pickle", "PicklingError");
  663. if (pickle_error == NULL) {
  664. return NULL;
  665. }
  666. PyErr_Format(pickle_error,
  667. "Cannot pickle a ZoneInfo file from a file stream.");
  668. Py_DECREF(pickle_error);
  669. return NULL;
  670. }
  671. unsigned char from_cache = self->source == SOURCE_CACHE ? 1 : 0;
  672. PyObject *constructor = PyObject_GetAttrString(obj_self, "_unpickle");
  673. if (constructor == NULL) {
  674. return NULL;
  675. }
  676. PyObject *rv = Py_BuildValue("O(OB)", constructor, self->key, from_cache);
  677. Py_DECREF(constructor);
  678. return rv;
  679. }
  680. /*[clinic input]
  681. @classmethod
  682. zoneinfo.ZoneInfo._unpickle
  683. cls: defining_class
  684. key: object
  685. from_cache: unsigned_char(bitwise=True)
  686. /
  687. Private method used in unpickling.
  688. [clinic start generated code]*/
  689. static PyObject *
  690. zoneinfo_ZoneInfo__unpickle_impl(PyTypeObject *type, PyTypeObject *cls,
  691. PyObject *key, unsigned char from_cache)
  692. /*[clinic end generated code: output=556712fc709deecb input=6ac8c73eed3de316]*/
  693. {
  694. if (from_cache) {
  695. PyObject *val_args = Py_BuildValue("(O)", key);
  696. if (val_args == NULL) {
  697. return NULL;
  698. }
  699. PyObject *rv = zoneinfo_new(type, val_args, NULL);
  700. Py_DECREF(val_args);
  701. return rv;
  702. }
  703. else {
  704. zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
  705. return zoneinfo_new_instance(state, type, key);
  706. }
  707. }
  708. /* It is relatively expensive to construct new timedelta objects, and in most
  709. * cases we're looking at a relatively small number of timedeltas, such as
  710. * integer number of hours, etc. We will keep a cache so that we construct
  711. * a minimal number of these.
  712. *
  713. * Possibly this should be replaced with an LRU cache so that it's not possible
  714. * for the memory usage to explode from this, but in order for this to be a
  715. * serious problem, one would need to deliberately craft a malicious time zone
  716. * file with many distinct offsets. As of tzdb 2019c, loading every single zone
  717. * fills the cache with ~450 timedeltas for a total size of ~12kB.
  718. *
  719. * This returns a new reference to the timedelta.
  720. */
  721. static PyObject *
  722. load_timedelta(zoneinfo_state *state, long seconds)
  723. {
  724. PyObject *rv;
  725. PyObject *pyoffset = PyLong_FromLong(seconds);
  726. if (pyoffset == NULL) {
  727. return NULL;
  728. }
  729. rv = PyDict_GetItemWithError(state->TIMEDELTA_CACHE, pyoffset);
  730. if (rv == NULL) {
  731. if (PyErr_Occurred()) {
  732. goto error;
  733. }
  734. PyObject *tmp = PyDateTimeAPI->Delta_FromDelta(
  735. 0, seconds, 0, 1, PyDateTimeAPI->DeltaType);
  736. if (tmp == NULL) {
  737. goto error;
  738. }
  739. rv = PyDict_SetDefault(state->TIMEDELTA_CACHE, pyoffset, tmp);
  740. Py_DECREF(tmp);
  741. }
  742. Py_XINCREF(rv);
  743. Py_DECREF(pyoffset);
  744. return rv;
  745. error:
  746. Py_DECREF(pyoffset);
  747. return NULL;
  748. }
  749. /* Constructor for _ttinfo object - this starts by initializing the _ttinfo
  750. * to { NULL, NULL, NULL }, so that Py_XDECREF will work on partially
  751. * initialized _ttinfo objects.
  752. */
  753. static int
  754. build_ttinfo(zoneinfo_state *state, long utcoffset, long dstoffset,
  755. PyObject *tzname, _ttinfo *out)
  756. {
  757. out->utcoff = NULL;
  758. out->dstoff = NULL;
  759. out->tzname = NULL;
  760. out->utcoff_seconds = utcoffset;
  761. out->utcoff = load_timedelta(state, utcoffset);
  762. if (out->utcoff == NULL) {
  763. return -1;
  764. }
  765. out->dstoff = load_timedelta(state, dstoffset);
  766. if (out->dstoff == NULL) {
  767. return -1;
  768. }
  769. out->tzname = Py_NewRef(tzname);
  770. return 0;
  771. }
  772. /* Decrease reference count on any non-NULL members of a _ttinfo */
  773. static void
  774. xdecref_ttinfo(_ttinfo *ttinfo)
  775. {
  776. if (ttinfo != NULL) {
  777. Py_XDECREF(ttinfo->utcoff);
  778. Py_XDECREF(ttinfo->dstoff);
  779. Py_XDECREF(ttinfo->tzname);
  780. }
  781. }
  782. /* Equality function for _ttinfo. */
  783. static int
  784. ttinfo_eq(const _ttinfo *const tti0, const _ttinfo *const tti1)
  785. {
  786. int rv;
  787. if ((rv = PyObject_RichCompareBool(tti0->utcoff, tti1->utcoff, Py_EQ)) <
  788. 1) {
  789. goto end;
  790. }
  791. if ((rv = PyObject_RichCompareBool(tti0->dstoff, tti1->dstoff, Py_EQ)) <
  792. 1) {
  793. goto end;
  794. }
  795. if ((rv = PyObject_RichCompareBool(tti0->tzname, tti1->tzname, Py_EQ)) <
  796. 1) {
  797. goto end;
  798. }
  799. end:
  800. return rv;
  801. }
  802. /* Given a file-like object, this populates a ZoneInfo object
  803. *
  804. * The current version calls into a Python function to read the data from
  805. * file into Python objects, and this translates those Python objects into
  806. * C values and calculates derived values (e.g. dstoff) in C.
  807. *
  808. * This returns 0 on success and -1 on failure.
  809. *
  810. * The function will never return while `self` is partially initialized —
  811. * the object only needs to be freed / deallocated if this succeeds.
  812. */
  813. static int
  814. load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
  815. {
  816. PyObject *data_tuple = NULL;
  817. long *utcoff = NULL;
  818. long *dstoff = NULL;
  819. size_t *trans_idx = NULL;
  820. unsigned char *isdst = NULL;
  821. self->trans_list_utc = NULL;
  822. self->trans_list_wall[0] = NULL;
  823. self->trans_list_wall[1] = NULL;
  824. self->trans_ttinfos = NULL;
  825. self->_ttinfos = NULL;
  826. self->file_repr = NULL;
  827. size_t ttinfos_allocated = 0;
  828. data_tuple = PyObject_CallMethod(state->_common_mod, "load_data", "O",
  829. file_obj);
  830. if (data_tuple == NULL) {
  831. goto error;
  832. }
  833. if (!PyTuple_CheckExact(data_tuple)) {
  834. PyErr_Format(PyExc_TypeError, "Invalid data result type: %r",
  835. data_tuple);
  836. goto error;
  837. }
  838. // Unpack the data tuple
  839. PyObject *trans_idx_list = PyTuple_GetItem(data_tuple, 0);
  840. if (trans_idx_list == NULL) {
  841. goto error;
  842. }
  843. PyObject *trans_utc = PyTuple_GetItem(data_tuple, 1);
  844. if (trans_utc == NULL) {
  845. goto error;
  846. }
  847. PyObject *utcoff_list = PyTuple_GetItem(data_tuple, 2);
  848. if (utcoff_list == NULL) {
  849. goto error;
  850. }
  851. PyObject *isdst_list = PyTuple_GetItem(data_tuple, 3);
  852. if (isdst_list == NULL) {
  853. goto error;
  854. }
  855. PyObject *abbr = PyTuple_GetItem(data_tuple, 4);
  856. if (abbr == NULL) {
  857. goto error;
  858. }
  859. PyObject *tz_str = PyTuple_GetItem(data_tuple, 5);
  860. if (tz_str == NULL) {
  861. goto error;
  862. }
  863. // Load the relevant sizes
  864. Py_ssize_t num_transitions = PyTuple_Size(trans_utc);
  865. if (num_transitions < 0) {
  866. goto error;
  867. }
  868. Py_ssize_t num_ttinfos = PyTuple_Size(utcoff_list);
  869. if (num_ttinfos < 0) {
  870. goto error;
  871. }
  872. self->num_transitions = (size_t)num_transitions;
  873. self->num_ttinfos = (size_t)num_ttinfos;
  874. // Load the transition indices and list
  875. self->trans_list_utc =
  876. PyMem_Malloc(self->num_transitions * sizeof(int64_t));
  877. if (self->trans_list_utc == NULL) {
  878. goto error;
  879. }
  880. trans_idx = PyMem_Malloc(self->num_transitions * sizeof(Py_ssize_t));
  881. if (trans_idx == NULL) {
  882. goto error;
  883. }
  884. for (size_t i = 0; i < self->num_transitions; ++i) {
  885. PyObject *num = PyTuple_GetItem(trans_utc, i);
  886. if (num == NULL) {
  887. goto error;
  888. }
  889. self->trans_list_utc[i] = PyLong_AsLongLong(num);
  890. if (self->trans_list_utc[i] == -1 && PyErr_Occurred()) {
  891. goto error;
  892. }
  893. num = PyTuple_GetItem(trans_idx_list, i);
  894. if (num == NULL) {
  895. goto error;
  896. }
  897. Py_ssize_t cur_trans_idx = PyLong_AsSsize_t(num);
  898. if (cur_trans_idx == -1) {
  899. goto error;
  900. }
  901. trans_idx[i] = (size_t)cur_trans_idx;
  902. if (trans_idx[i] > self->num_ttinfos) {
  903. PyErr_Format(
  904. PyExc_ValueError,
  905. "Invalid transition index found while reading TZif: %zd",
  906. cur_trans_idx);
  907. goto error;
  908. }
  909. }
  910. // Load UTC offsets and isdst (size num_ttinfos)
  911. utcoff = PyMem_Malloc(self->num_ttinfos * sizeof(long));
  912. isdst = PyMem_Malloc(self->num_ttinfos * sizeof(unsigned char));
  913. if (utcoff == NULL || isdst == NULL) {
  914. goto error;
  915. }
  916. for (size_t i = 0; i < self->num_ttinfos; ++i) {
  917. PyObject *num = PyTuple_GetItem(utcoff_list, i);
  918. if (num == NULL) {
  919. goto error;
  920. }
  921. utcoff[i] = PyLong_AsLong(num);
  922. if (utcoff[i] == -1 && PyErr_Occurred()) {
  923. goto error;
  924. }
  925. num = PyTuple_GetItem(isdst_list, i);
  926. if (num == NULL) {
  927. goto error;
  928. }
  929. int isdst_with_error = PyObject_IsTrue(num);
  930. if (isdst_with_error == -1) {
  931. goto error;
  932. }
  933. else {
  934. isdst[i] = (unsigned char)isdst_with_error;
  935. }
  936. }
  937. dstoff = PyMem_Calloc(self->num_ttinfos, sizeof(long));
  938. if (dstoff == NULL) {
  939. goto error;
  940. }
  941. // Derive dstoff and trans_list_wall from the information we've loaded
  942. utcoff_to_dstoff(trans_idx, utcoff, dstoff, isdst, self->num_transitions,
  943. self->num_ttinfos);
  944. if (ts_to_local(trans_idx, self->trans_list_utc, utcoff,
  945. self->trans_list_wall, self->num_ttinfos,
  946. self->num_transitions)) {
  947. goto error;
  948. }
  949. // Build _ttinfo objects from utcoff, dstoff and abbr
  950. self->_ttinfos = PyMem_Malloc(self->num_ttinfos * sizeof(_ttinfo));
  951. if (self->_ttinfos == NULL) {
  952. goto error;
  953. }
  954. for (size_t i = 0; i < self->num_ttinfos; ++i) {
  955. PyObject *tzname = PyTuple_GetItem(abbr, i);
  956. if (tzname == NULL) {
  957. goto error;
  958. }
  959. ttinfos_allocated++;
  960. int rc = build_ttinfo(state, utcoff[i], dstoff[i], tzname,
  961. &(self->_ttinfos[i]));
  962. if (rc) {
  963. goto error;
  964. }
  965. }
  966. // Build our mapping from transition to the ttinfo that applies
  967. self->trans_ttinfos =
  968. PyMem_Calloc(self->num_transitions, sizeof(_ttinfo *));
  969. if (self->trans_ttinfos == NULL) {
  970. goto error;
  971. }
  972. for (size_t i = 0; i < self->num_transitions; ++i) {
  973. size_t ttinfo_idx = trans_idx[i];
  974. assert(ttinfo_idx < self->num_ttinfos);
  975. self->trans_ttinfos[i] = &(self->_ttinfos[ttinfo_idx]);
  976. }
  977. // Set ttinfo_before to the first non-DST transition
  978. for (size_t i = 0; i < self->num_ttinfos; ++i) {
  979. if (!isdst[i]) {
  980. self->ttinfo_before = &(self->_ttinfos[i]);
  981. break;
  982. }
  983. }
  984. // If there are only DST ttinfos, pick the first one, if there are no
  985. // ttinfos at all, set ttinfo_before to NULL
  986. if (self->ttinfo_before == NULL && self->num_ttinfos > 0) {
  987. self->ttinfo_before = &(self->_ttinfos[0]);
  988. }
  989. if (tz_str != Py_None && PyObject_IsTrue(tz_str)) {
  990. if (parse_tz_str(state, tz_str, &(self->tzrule_after))) {
  991. goto error;
  992. }
  993. }
  994. else {
  995. if (!self->num_ttinfos) {
  996. PyErr_Format(PyExc_ValueError, "No time zone information found.");
  997. goto error;
  998. }
  999. size_t idx;
  1000. if (!self->num_transitions) {
  1001. idx = self->num_ttinfos - 1;
  1002. }
  1003. else {
  1004. idx = trans_idx[self->num_transitions - 1];
  1005. }
  1006. _ttinfo *tti = &(self->_ttinfos[idx]);
  1007. build_tzrule(state, tti->tzname, NULL, tti->utcoff_seconds, 0, NULL,
  1008. NULL, &(self->tzrule_after));
  1009. // We've abused the build_tzrule constructor to construct an STD-only
  1010. // rule mimicking whatever ttinfo we've picked up, but it's possible
  1011. // that the one we've picked up is a DST zone, so we need to make sure
  1012. // that the dstoff is set correctly in that case.
  1013. if (PyObject_IsTrue(tti->dstoff)) {
  1014. _ttinfo *tti_after = &(self->tzrule_after.std);
  1015. Py_SETREF(tti_after->dstoff, Py_NewRef(tti->dstoff));
  1016. }
  1017. }
  1018. // Determine if this is a "fixed offset" zone, meaning that the output of
  1019. // the utcoffset, dst and tzname functions does not depend on the specific
  1020. // datetime passed.
  1021. //
  1022. // We make three simplifying assumptions here:
  1023. //
  1024. // 1. If tzrule_after is not std_only, it has transitions that might occur
  1025. // (it is possible to construct TZ strings that specify STD and DST but
  1026. // no transitions ever occur, such as AAA0BBB,0/0,J365/25).
  1027. // 2. If self->_ttinfos contains more than one _ttinfo object, the objects
  1028. // represent different offsets.
  1029. // 3. self->ttinfos contains no unused _ttinfos (in which case an otherwise
  1030. // fixed-offset zone with extra _ttinfos defined may appear to *not* be
  1031. // a fixed offset zone).
  1032. //
  1033. // Violations to these assumptions would be fairly exotic, and exotic
  1034. // zones should almost certainly not be used with datetime.time (the
  1035. // only thing that would be affected by this).
  1036. if (self->num_ttinfos > 1 || !self->tzrule_after.std_only) {
  1037. self->fixed_offset = 0;
  1038. }
  1039. else if (self->num_ttinfos == 0) {
  1040. self->fixed_offset = 1;
  1041. }
  1042. else {
  1043. int constant_offset =
  1044. ttinfo_eq(&(self->_ttinfos[0]), &self->tzrule_after.std);
  1045. if (constant_offset < 0) {
  1046. goto error;
  1047. }
  1048. else {
  1049. self->fixed_offset = constant_offset;
  1050. }
  1051. }
  1052. int rv = 0;
  1053. goto cleanup;
  1054. error:
  1055. // These resources only need to be freed if we have failed, if we succeed
  1056. // in initializing a PyZoneInfo_ZoneInfo object, we can rely on its dealloc
  1057. // method to free the relevant resources.
  1058. if (self->trans_list_utc != NULL) {
  1059. PyMem_Free(self->trans_list_utc);
  1060. self->trans_list_utc = NULL;
  1061. }
  1062. for (size_t i = 0; i < 2; ++i) {
  1063. if (self->trans_list_wall[i] != NULL) {
  1064. PyMem_Free(self->trans_list_wall[i]);
  1065. self->trans_list_wall[i] = NULL;
  1066. }
  1067. }
  1068. if (self->_ttinfos != NULL) {
  1069. for (size_t i = 0; i < ttinfos_allocated; ++i) {
  1070. xdecref_ttinfo(&(self->_ttinfos[i]));
  1071. }
  1072. PyMem_Free(self->_ttinfos);
  1073. self->_ttinfos = NULL;
  1074. }
  1075. if (self->trans_ttinfos != NULL) {
  1076. PyMem_Free(self->trans_ttinfos);
  1077. self->trans_ttinfos = NULL;
  1078. }
  1079. rv = -1;
  1080. cleanup:
  1081. Py_XDECREF(data_tuple);
  1082. if (utcoff != NULL) {
  1083. PyMem_Free(utcoff);
  1084. }
  1085. if (dstoff != NULL) {
  1086. PyMem_Free(dstoff);
  1087. }
  1088. if (isdst != NULL) {
  1089. PyMem_Free(isdst);
  1090. }
  1091. if (trans_idx != NULL) {
  1092. PyMem_Free(trans_idx);
  1093. }
  1094. return rv;
  1095. }
  1096. /* Function to calculate the local timestamp of a transition from the year. */
  1097. int64_t
  1098. calendarrule_year_to_timestamp(TransitionRuleType *base_self, int year)
  1099. {
  1100. CalendarRule *self = (CalendarRule *)base_self;
  1101. // We want (year, month, day of month); we have year and month, but we
  1102. // need to turn (week, day-of-week) into day-of-month
  1103. //
  1104. // Week 1 is the first week in which day `day` (where 0 = Sunday) appears.
  1105. // Week 5 represents the last occurrence of day `day`, so we need to know
  1106. // the first weekday of the month and the number of days in the month.
  1107. int8_t first_day = (ymd_to_ord(year, self->month, 1) + 6) % 7;
  1108. uint8_t days_in_month = DAYS_IN_MONTH[self->month];
  1109. if (self->month == 2 && is_leap_year(year)) {
  1110. days_in_month += 1;
  1111. }
  1112. // This equation seems magical, so I'll break it down:
  1113. // 1. calendar says 0 = Monday, POSIX says 0 = Sunday so we need first_day
  1114. // + 1 to get 1 = Monday -> 7 = Sunday, which is still equivalent
  1115. // because this math is mod 7
  1116. // 2. Get first day - desired day mod 7 (adjusting by 7 for negative
  1117. // numbers so that -1 % 7 = 6).
  1118. // 3. Add 1 because month days are a 1-based index.
  1119. int8_t month_day = ((int8_t)(self->day) - (first_day + 1)) % 7;
  1120. if (month_day < 0) {
  1121. month_day += 7;
  1122. }
  1123. month_day += 1;
  1124. // Now use a 0-based index version of `week` to calculate the w-th
  1125. // occurrence of `day`
  1126. month_day += ((int8_t)(self->week) - 1) * 7;
  1127. // month_day will only be > days_in_month if w was 5, and `w` means "last
  1128. // occurrence of `d`", so now we just check if we over-shot the end of the
  1129. // month and if so knock off 1 week.
  1130. if (month_day > days_in_month) {
  1131. month_day -= 7;
  1132. }
  1133. int64_t ordinal = ymd_to_ord(year, self->month, month_day) - EPOCHORDINAL;
  1134. return ordinal * 86400 + (int64_t)self->hour * 3600 +
  1135. (int64_t)self->minute * 60 + self->second;
  1136. }
  1137. /* Constructor for CalendarRule. */
  1138. int
  1139. calendarrule_new(int month, int week, int day, int hour,
  1140. int minute, int second, CalendarRule *out)
  1141. {
  1142. // These bounds come from the POSIX standard, which describes an Mm.n.d
  1143. // rule as:
  1144. //
  1145. // The d'th day (0 <= d <= 6) of week n of month m of the year (1 <= n <=
  1146. // 5, 1 <= m <= 12, where week 5 means "the last d day in month m" which
  1147. // may occur in either the fourth or the fifth week). Week 1 is the first
  1148. // week in which the d'th day occurs. Day zero is Sunday.
  1149. if (month < 1 || month > 12) {
  1150. PyErr_Format(PyExc_ValueError, "Month must be in [1, 12]");
  1151. return -1;
  1152. }
  1153. if (week < 1 || week > 5) {
  1154. PyErr_Format(PyExc_ValueError, "Week must be in [1, 5]");
  1155. return -1;
  1156. }
  1157. if (day < 0 || day > 6) {
  1158. PyErr_Format(PyExc_ValueError, "Day must be in [0, 6]");
  1159. return -1;
  1160. }
  1161. if (hour < -167 || hour > 167) {
  1162. PyErr_Format(PyExc_ValueError, "Hour must be in [0, 167]");
  1163. return -1;
  1164. }
  1165. TransitionRuleType base = {&calendarrule_year_to_timestamp};
  1166. CalendarRule new_offset = {
  1167. .base = base,
  1168. .month = (uint8_t)month,
  1169. .week = (uint8_t)week,
  1170. .day = (uint8_t)day,
  1171. .hour = (int16_t)hour,
  1172. .minute = (int8_t)minute,
  1173. .second = (int8_t)second,
  1174. };
  1175. *out = new_offset;
  1176. return 0;
  1177. }
  1178. /* Function to calculate the local timestamp of a transition from the year.
  1179. *
  1180. * This translates the day of the year into a local timestamp — either a
  1181. * 1-based Julian day, not including leap days, or the 0-based year-day,
  1182. * including leap days.
  1183. * */
  1184. int64_t
  1185. dayrule_year_to_timestamp(TransitionRuleType *base_self, int year)
  1186. {
  1187. // The function signature requires a TransitionRuleType pointer, but this
  1188. // function is only applicable to DayRule* objects.
  1189. DayRule *self = (DayRule *)base_self;
  1190. // ymd_to_ord calculates the number of days since 0001-01-01, but we want
  1191. // to know the number of days since 1970-01-01, so we must subtract off
  1192. // the equivalent of ymd_to_ord(1970, 1, 1).
  1193. //
  1194. // We subtract off an additional 1 day to account for January 1st (we want
  1195. // the number of full days *before* the date of the transition - partial
  1196. // days are accounted for in the hour, minute and second portions.
  1197. int64_t days_before_year = ymd_to_ord(year, 1, 1) - EPOCHORDINAL - 1;
  1198. // The Julian day specification skips over February 29th in leap years,
  1199. // from the POSIX standard:
  1200. //
  1201. // Leap days shall not be counted. That is, in all years-including leap
  1202. // years-February 28 is day 59 and March 1 is day 60. It is impossible to
  1203. // refer explicitly to the occasional February 29.
  1204. //
  1205. // This is actually more useful than you'd think — if you want a rule that
  1206. // always transitions on a given calendar day (other than February 29th),
  1207. // you would use a Julian day, e.g. J91 always refers to April 1st and J365
  1208. // always refers to December 31st.
  1209. uint16_t day = self->day;
  1210. if (self->julian && day >= 59 && is_leap_year(year)) {
  1211. day += 1;
  1212. }
  1213. return (days_before_year + day) * 86400 + (int64_t)self->hour * 3600 +
  1214. (int64_t)self->minute * 60 + self->second;
  1215. }
  1216. /* Constructor for DayRule. */
  1217. static int
  1218. dayrule_new(int julian, int day, int hour, int minute,
  1219. int second, DayRule *out)
  1220. {
  1221. // The POSIX standard specifies that Julian days must be in the range (1 <=
  1222. // n <= 365) and that non-Julian (they call it "0-based Julian") days must
  1223. // be in the range (0 <= n <= 365).
  1224. if (day < julian || day > 365) {
  1225. PyErr_Format(PyExc_ValueError, "day must be in [%d, 365], not: %d",
  1226. julian, day);
  1227. return -1;
  1228. }
  1229. if (hour < -167 || hour > 167) {
  1230. PyErr_Format(PyExc_ValueError, "Hour must be in [0, 167]");
  1231. return -1;
  1232. }
  1233. TransitionRuleType base = {
  1234. &dayrule_year_to_timestamp,
  1235. };
  1236. DayRule tmp = {
  1237. .base = base,
  1238. .julian = (uint8_t)julian,
  1239. .day = (int16_t)day,
  1240. .hour = (int16_t)hour,
  1241. .minute = (int8_t)minute,
  1242. .second = (int8_t)second,
  1243. };
  1244. *out = tmp;
  1245. return 0;
  1246. }
  1247. /* Calculate the start and end rules for a _tzrule in the given year. */
  1248. static void
  1249. tzrule_transitions(_tzrule *rule, int year, int64_t *start, int64_t *end)
  1250. {
  1251. assert(rule->start != NULL);
  1252. assert(rule->end != NULL);
  1253. *start = rule->start->year_to_timestamp(rule->start, year);
  1254. *end = rule->end->year_to_timestamp(rule->end, year);
  1255. }
  1256. /* Calculate the _ttinfo that applies at a given local time from a _tzrule.
  1257. *
  1258. * This takes a local timestamp and fold for disambiguation purposes; the year
  1259. * could technically be calculated from the timestamp, but given that the
  1260. * callers of this function already have the year information accessible from
  1261. * the datetime struct, it is taken as an additional parameter to reduce
  1262. * unnecessary calculation.
  1263. * */
  1264. static _ttinfo *
  1265. find_tzrule_ttinfo(_tzrule *rule, int64_t ts, unsigned char fold, int year)
  1266. {
  1267. if (rule->std_only) {
  1268. return &(rule->std);
  1269. }
  1270. int64_t start, end;
  1271. uint8_t isdst;
  1272. tzrule_transitions(rule, year, &start, &end);
  1273. // With fold = 0, the period (denominated in local time) with the smaller
  1274. // offset starts at the end of the gap and ends at the end of the fold;
  1275. // with fold = 1, it runs from the start of the gap to the beginning of the
  1276. // fold.
  1277. //
  1278. // So in order to determine the DST boundaries we need to know both the
  1279. // fold and whether DST is positive or negative (rare), and it turns out
  1280. // that this boils down to fold XOR is_positive.
  1281. if (fold == (rule->dst_diff >= 0)) {
  1282. end -= rule->dst_diff;
  1283. }
  1284. else {
  1285. start += rule->dst_diff;
  1286. }
  1287. if (start < end) {
  1288. isdst = (ts >= start) && (ts < end);
  1289. }
  1290. else {
  1291. isdst = (ts < end) || (ts >= start);
  1292. }
  1293. if (isdst) {
  1294. return &(rule->dst);
  1295. }
  1296. else {
  1297. return &(rule->std);
  1298. }
  1299. }
  1300. /* Calculate the ttinfo and fold that applies for a _tzrule at an epoch time.
  1301. *
  1302. * This function can determine the _ttinfo that applies at a given epoch time,
  1303. * (analogous to trans_list_utc), and whether or not the datetime is in a fold.
  1304. * This is to be used in the .fromutc() function.
  1305. *
  1306. * The year is technically a redundant parameter, because it can be calculated
  1307. * from the timestamp, but all callers of this function should have the year
  1308. * in the datetime struct anyway, so taking it as a parameter saves unnecessary
  1309. * calculation.
  1310. **/
  1311. static _ttinfo *
  1312. find_tzrule_ttinfo_fromutc(_tzrule *rule, int64_t ts, int year,
  1313. unsigned char *fold)
  1314. {
  1315. if (rule->std_only) {
  1316. *fold = 0;
  1317. return &(rule->std);
  1318. }
  1319. int64_t start, end;
  1320. uint8_t isdst;
  1321. tzrule_transitions(rule, year, &start, &end);
  1322. start -= rule->std.utcoff_seconds;
  1323. end -= rule->dst.utcoff_seconds;
  1324. if (start < end) {
  1325. isdst = (ts >= start) && (ts < end);
  1326. }
  1327. else {
  1328. isdst = (ts < end) || (ts >= start);
  1329. }
  1330. // For positive DST, the ambiguous period is one dst_diff after the end of
  1331. // DST; for negative DST, the ambiguous period is one dst_diff before the
  1332. // start of DST.
  1333. int64_t ambig_start, ambig_end;
  1334. if (rule->dst_diff > 0) {
  1335. ambig_start = end;
  1336. ambig_end = end + rule->dst_diff;
  1337. }
  1338. else {
  1339. ambig_start = start;
  1340. ambig_end = start - rule->dst_diff;
  1341. }
  1342. *fold = (ts >= ambig_start) && (ts < ambig_end);
  1343. if (isdst) {
  1344. return &(rule->dst);
  1345. }
  1346. else {
  1347. return &(rule->std);
  1348. }
  1349. }
  1350. /* Parse a TZ string in the format specified by the POSIX standard:
  1351. *
  1352. * std offset[dst[offset],start[/time],end[/time]]
  1353. *
  1354. * std and dst must be 3 or more characters long and must not contain a
  1355. * leading colon, embedded digits, commas, nor a plus or minus signs; The
  1356. * spaces between "std" and "offset" are only for display and are not actually
  1357. * present in the string.
  1358. *
  1359. * The format of the offset is ``[+|-]hh[:mm[:ss]]``
  1360. *
  1361. * See the POSIX.1 spec: IEE Std 1003.1-2018 §8.3:
  1362. *
  1363. * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
  1364. */
  1365. static int
  1366. parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out)
  1367. {
  1368. PyObject *std_abbr = NULL;
  1369. PyObject *dst_abbr = NULL;
  1370. TransitionRuleType *start = NULL;
  1371. TransitionRuleType *end = NULL;
  1372. // Initialize offsets to invalid value (> 24 hours)
  1373. long std_offset = 1 << 20;
  1374. long dst_offset = 1 << 20;
  1375. const char *tz_str = PyBytes_AsString(tz_str_obj);
  1376. if (tz_str == NULL) {
  1377. return -1;
  1378. }
  1379. const char *p = tz_str;
  1380. // Read the `std` abbreviation, which must be at least 3 characters long.
  1381. if (parse_abbr(&p, &std_abbr)) {
  1382. if (!PyErr_Occurred()) {
  1383. PyErr_Format(PyExc_ValueError, "Invalid STD format in %R", tz_str_obj);
  1384. }
  1385. goto error;
  1386. }
  1387. // Now read the STD offset, which is required
  1388. if (parse_tz_delta(&p, &std_offset)) {
  1389. PyErr_Format(PyExc_ValueError, "Invalid STD offset in %R", tz_str_obj);
  1390. goto error;
  1391. }
  1392. // If the string ends here, there is no DST, otherwise we must parse the
  1393. // DST abbreviation and start and end dates and times.
  1394. if (*p == '\0') {
  1395. goto complete;
  1396. }
  1397. if (parse_abbr(&p, &dst_abbr)) {
  1398. if (!PyErr_Occurred()) {
  1399. PyErr_Format(PyExc_ValueError, "Invalid DST format in %R", tz_str_obj);
  1400. }
  1401. goto error;
  1402. }
  1403. if (*p == ',') {
  1404. // From the POSIX standard:
  1405. //
  1406. // If no offset follows dst, the alternative time is assumed to be one
  1407. // hour ahead of standard time.
  1408. dst_offset = std_offset + 3600;
  1409. }
  1410. else {
  1411. if (parse_tz_delta(&p, &dst_offset)) {
  1412. PyErr_Format(PyExc_ValueError, "Invalid DST offset in %R",
  1413. tz_str_obj);
  1414. goto error;
  1415. }
  1416. }
  1417. TransitionRuleType **transitions[2] = {&start, &end};
  1418. for (size_t i = 0; i < 2; ++i) {
  1419. if (*p != ',') {
  1420. PyErr_Format(PyExc_ValueError,
  1421. "Missing transition rules in TZ string: %R",
  1422. tz_str_obj);
  1423. goto error;
  1424. }
  1425. p++;
  1426. if (parse_transition_rule(&p, transitions[i])) {
  1427. PyErr_Format(PyExc_ValueError,
  1428. "Malformed transition rule in TZ string: %R",
  1429. tz_str_obj);
  1430. goto error;
  1431. }
  1432. }
  1433. if (*p != '\0') {
  1434. PyErr_Format(PyExc_ValueError,
  1435. "Extraneous characters at end of TZ string: %R",
  1436. tz_str_obj);
  1437. goto error;
  1438. }
  1439. complete:
  1440. build_tzrule(state, std_abbr, dst_abbr, std_offset, dst_offset,
  1441. start, end, out);
  1442. Py_DECREF(std_abbr);
  1443. Py_XDECREF(dst_abbr);
  1444. return 0;
  1445. error:
  1446. Py_XDECREF(std_abbr);
  1447. if (dst_abbr != NULL && dst_abbr != Py_None) {
  1448. Py_DECREF(dst_abbr);
  1449. }
  1450. if (start != NULL) {
  1451. PyMem_Free(start);
  1452. }
  1453. if (end != NULL) {
  1454. PyMem_Free(end);
  1455. }
  1456. return -1;
  1457. }
  1458. static int
  1459. parse_digits(const char **p, int min, int max, int *value)
  1460. {
  1461. assert(max <= 3);
  1462. *value = 0;
  1463. for (int i = 0; i < max; i++, (*p)++) {
  1464. if (!Py_ISDIGIT(**p)) {
  1465. return (i < min) ? -1 : 0;
  1466. }
  1467. *value *= 10;
  1468. *value += (**p) - '0';
  1469. }
  1470. return 0;
  1471. }
  1472. /* Parse the STD and DST abbreviations from a TZ string. */
  1473. static int
  1474. parse_abbr(const char **p, PyObject **abbr)
  1475. {
  1476. const char *ptr = *p;
  1477. const char *str_start;
  1478. const char *str_end;
  1479. if (*ptr == '<') {
  1480. char buff;
  1481. ptr++;
  1482. str_start = ptr;
  1483. while ((buff = *ptr) != '>') {
  1484. // From the POSIX standard:
  1485. //
  1486. // In the quoted form, the first character shall be the less-than
  1487. // ( '<' ) character and the last character shall be the
  1488. // greater-than ( '>' ) character. All characters between these
  1489. // quoting characters shall be alphanumeric characters from the
  1490. // portable character set in the current locale, the plus-sign (
  1491. // '+' ) character, or the minus-sign ( '-' ) character. The std
  1492. // and dst fields in this case shall not include the quoting
  1493. // characters.
  1494. if (!isalpha(buff) && !isdigit(buff) && buff != '+' &&
  1495. buff != '-') {
  1496. return -1;
  1497. }
  1498. ptr++;
  1499. }
  1500. str_end = ptr;
  1501. ptr++;
  1502. }
  1503. else {
  1504. str_start = ptr;
  1505. // From the POSIX standard:
  1506. //
  1507. // In the unquoted form, all characters in these fields shall be
  1508. // alphabetic characters from the portable character set in the
  1509. // current locale.
  1510. while (isalpha(*ptr)) {
  1511. ptr++;
  1512. }
  1513. str_end = ptr;
  1514. if (str_end == str_start) {
  1515. return -1;
  1516. }
  1517. }
  1518. *abbr = PyUnicode_FromStringAndSize(str_start, str_end - str_start);
  1519. if (*abbr == NULL) {
  1520. return -1;
  1521. }
  1522. *p = ptr;
  1523. return 0;
  1524. }
  1525. /* Parse a UTC offset from a TZ str. */
  1526. static int
  1527. parse_tz_delta(const char **p, long *total_seconds)
  1528. {
  1529. // From the POSIX spec:
  1530. //
  1531. // Indicates the value added to the local time to arrive at Coordinated
  1532. // Universal Time. The offset has the form:
  1533. //
  1534. // hh[:mm[:ss]]
  1535. //
  1536. // One or more digits may be used; the value is always interpreted as a
  1537. // decimal number.
  1538. //
  1539. // The POSIX spec says that the values for `hour` must be between 0 and 24
  1540. // hours, but RFC 8536 §3.3.1 specifies that the hours part of the
  1541. // transition times may be signed and range from -167 to 167.
  1542. int hours = 0;
  1543. int minutes = 0;
  1544. int seconds = 0;
  1545. if (parse_transition_time(p, &hours, &minutes, &seconds)) {
  1546. return -1;
  1547. }
  1548. if (hours > 24 || hours < -24) {
  1549. return -1;
  1550. }
  1551. // Negative numbers correspond to *positive* offsets, from the spec:
  1552. //
  1553. // If preceded by a '-', the timezone shall be east of the Prime
  1554. // Meridian; otherwise, it shall be west (which may be indicated by
  1555. // an optional preceding '+' ).
  1556. *total_seconds = -((hours * 3600L) + (minutes * 60) + seconds);
  1557. return 0;
  1558. }
  1559. /* Parse the date portion of a transition rule. */
  1560. static int
  1561. parse_transition_rule(const char **p, TransitionRuleType **out)
  1562. {
  1563. // The full transition rule indicates when to change back and forth between
  1564. // STD and DST, and has the form:
  1565. //
  1566. // date[/time],date[/time]
  1567. //
  1568. // This function parses an individual date[/time] section, and returns
  1569. // the number of characters that contributed to the transition rule. This
  1570. // does not include the ',' at the end of the first rule.
  1571. //
  1572. // The POSIX spec states that if *time* is not given, the default is 02:00.
  1573. const char *ptr = *p;
  1574. int hour = 2;
  1575. int minute = 0;
  1576. int second = 0;
  1577. // Rules come in one of three flavors:
  1578. //
  1579. // 1. Jn: Julian day n, with no leap days.
  1580. // 2. n: Day of year (0-based, with leap days)
  1581. // 3. Mm.n.d: Specifying by month, week and day-of-week.
  1582. if (*ptr == 'M') {
  1583. int month, week, day;
  1584. ptr++;
  1585. if (parse_digits(&ptr, 1, 2, &month)) {
  1586. return -1;
  1587. }
  1588. if (*ptr++ != '.') {
  1589. return -1;
  1590. }
  1591. if (parse_digits(&ptr, 1, 1, &week)) {
  1592. return -1;
  1593. }
  1594. if (*ptr++ != '.') {
  1595. return -1;
  1596. }
  1597. if (parse_digits(&ptr, 1, 1, &day)) {
  1598. return -1;
  1599. }
  1600. if (*ptr == '/') {
  1601. ptr++;
  1602. if (parse_transition_time(&ptr, &hour, &minute, &second)) {
  1603. return -1;
  1604. }
  1605. }
  1606. CalendarRule *rv = PyMem_Calloc(1, sizeof(CalendarRule));
  1607. if (rv == NULL) {
  1608. return -1;
  1609. }
  1610. if (calendarrule_new(month, week, day, hour, minute, second, rv)) {
  1611. PyMem_Free(rv);
  1612. return -1;
  1613. }
  1614. *out = (TransitionRuleType *)rv;
  1615. }
  1616. else {
  1617. int julian = 0;
  1618. int day = 0;
  1619. if (*ptr == 'J') {
  1620. julian = 1;
  1621. ptr++;
  1622. }
  1623. if (parse_digits(&ptr, 1, 3, &day)) {
  1624. return -1;
  1625. }
  1626. if (*ptr == '/') {
  1627. ptr++;
  1628. if (parse_transition_time(&ptr, &hour, &minute, &second)) {
  1629. return -1;
  1630. }
  1631. }
  1632. DayRule *rv = PyMem_Calloc(1, sizeof(DayRule));
  1633. if (rv == NULL) {
  1634. return -1;
  1635. }
  1636. if (dayrule_new(julian, day, hour, minute, second, rv)) {
  1637. PyMem_Free(rv);
  1638. return -1;
  1639. }
  1640. *out = (TransitionRuleType *)rv;
  1641. }
  1642. *p = ptr;
  1643. return 0;
  1644. }
  1645. /* Parse the time portion of a transition rule (e.g. following an /) */
  1646. static int
  1647. parse_transition_time(const char **p, int *hour, int *minute, int *second)
  1648. {
  1649. // From the spec:
  1650. //
  1651. // The time has the same format as offset except that no leading sign
  1652. // ( '-' or '+' ) is allowed.
  1653. //
  1654. // The format for the offset is:
  1655. //
  1656. // h[h][:mm[:ss]]
  1657. //
  1658. // RFC 8536 also allows transition times to be signed and to range from
  1659. // -167 to +167.
  1660. const char *ptr = *p;
  1661. int sign = 1;
  1662. if (*ptr == '-' || *ptr == '+') {
  1663. if (*ptr == '-') {
  1664. sign = -1;
  1665. }
  1666. ptr++;
  1667. }
  1668. // The hour can be 1 to 3 numeric characters
  1669. if (parse_digits(&ptr, 1, 3, hour)) {
  1670. return -1;
  1671. }
  1672. *hour *= sign;
  1673. // Minutes and seconds always of the format ":dd"
  1674. if (*ptr == ':') {
  1675. ptr++;
  1676. if (parse_digits(&ptr, 2, 2, minute)) {
  1677. return -1;
  1678. }
  1679. *minute *= sign;
  1680. if (*ptr == ':') {
  1681. ptr++;
  1682. if (parse_digits(&ptr, 2, 2, second)) {
  1683. return -1;
  1684. }
  1685. *second *= sign;
  1686. }
  1687. }
  1688. *p = ptr;
  1689. return 0;
  1690. }
  1691. /* Constructor for a _tzrule.
  1692. *
  1693. * If `dst_abbr` is NULL, this will construct an "STD-only" _tzrule, in which
  1694. * case `dst_offset` will be ignored and `start` and `end` are expected to be
  1695. * NULL as well.
  1696. *
  1697. * Returns 0 on success.
  1698. */
  1699. static int
  1700. build_tzrule(zoneinfo_state *state, PyObject *std_abbr, PyObject *dst_abbr,
  1701. long std_offset, long dst_offset, TransitionRuleType *start,
  1702. TransitionRuleType *end, _tzrule *out)
  1703. {
  1704. _tzrule rv = {{0}};
  1705. rv.start = start;
  1706. rv.end = end;
  1707. if (build_ttinfo(state, std_offset, 0, std_abbr, &rv.std)) {
  1708. goto error;
  1709. }
  1710. if (dst_abbr != NULL) {
  1711. rv.dst_diff = dst_offset - std_offset;
  1712. if (build_ttinfo(state, dst_offset, rv.dst_diff, dst_abbr, &rv.dst)) {
  1713. goto error;
  1714. }
  1715. }
  1716. else {
  1717. rv.std_only = 1;
  1718. }
  1719. *out = rv;
  1720. return 0;
  1721. error:
  1722. xdecref_ttinfo(&rv.std);
  1723. xdecref_ttinfo(&rv.dst);
  1724. return -1;
  1725. }
  1726. /* Destructor for _tzrule. */
  1727. static void
  1728. free_tzrule(_tzrule *tzrule)
  1729. {
  1730. xdecref_ttinfo(&(tzrule->std));
  1731. if (!tzrule->std_only) {
  1732. xdecref_ttinfo(&(tzrule->dst));
  1733. }
  1734. if (tzrule->start != NULL) {
  1735. PyMem_Free(tzrule->start);
  1736. }
  1737. if (tzrule->end != NULL) {
  1738. PyMem_Free(tzrule->end);
  1739. }
  1740. }
  1741. /* Calculate DST offsets from transitions and UTC offsets
  1742. *
  1743. * This is necessary because each C `ttinfo` only contains the UTC offset,
  1744. * time zone abbreviation and an isdst boolean - it does not include the
  1745. * amount of the DST offset, but we need the amount for the dst() function.
  1746. *
  1747. * Thus function uses heuristics to infer what the offset should be, so it
  1748. * is not guaranteed that this will work for all zones. If we cannot assign
  1749. * a value for a given DST offset, we'll assume it's 1H rather than 0H, so
  1750. * bool(dt.dst()) will always match ttinfo.isdst.
  1751. */
  1752. static void
  1753. utcoff_to_dstoff(size_t *trans_idx, long *utcoffs, long *dstoffs,
  1754. unsigned char *isdsts, size_t num_transitions,
  1755. size_t num_ttinfos)
  1756. {
  1757. size_t dst_count = 0;
  1758. size_t dst_found = 0;
  1759. for (size_t i = 0; i < num_ttinfos; ++i) {
  1760. dst_count++;
  1761. }
  1762. for (size_t i = 1; i < num_transitions; ++i) {
  1763. if (dst_count == dst_found) {
  1764. break;
  1765. }
  1766. size_t idx = trans_idx[i];
  1767. size_t comp_idx = trans_idx[i - 1];
  1768. // Only look at DST offsets that have nto been assigned already
  1769. if (!isdsts[idx] || dstoffs[idx] != 0) {
  1770. continue;
  1771. }
  1772. long dstoff = 0;
  1773. long utcoff = utcoffs[idx];
  1774. if (!isdsts[comp_idx]) {
  1775. dstoff = utcoff - utcoffs[comp_idx];
  1776. }
  1777. if (!dstoff && idx < (num_ttinfos - 1)) {
  1778. comp_idx = trans_idx[i + 1];
  1779. // If the following transition is also DST and we couldn't find
  1780. // the DST offset by this point, we're going to have to skip it
  1781. // and hope this transition gets assigned later
  1782. if (isdsts[comp_idx]) {
  1783. continue;
  1784. }
  1785. dstoff = utcoff - utcoffs[comp_idx];
  1786. }
  1787. if (dstoff) {
  1788. dst_found++;
  1789. dstoffs[idx] = dstoff;
  1790. }
  1791. }
  1792. if (dst_found < dst_count) {
  1793. // If there are time zones we didn't find a value for, we'll end up
  1794. // with dstoff = 0 for something where isdst=1. This is obviously
  1795. // wrong — one hour will be a much better guess than 0.
  1796. for (size_t idx = 0; idx < num_ttinfos; ++idx) {
  1797. if (isdsts[idx] && !dstoffs[idx]) {
  1798. dstoffs[idx] = 3600;
  1799. }
  1800. }
  1801. }
  1802. }
  1803. #define _swap(x, y, buffer) \
  1804. buffer = x; \
  1805. x = y; \
  1806. y = buffer;
  1807. /* Calculate transitions in local time from UTC time and offsets.
  1808. *
  1809. * We want to know when each transition occurs, denominated in the number of
  1810. * nominal wall-time seconds between 1970-01-01T00:00:00 and the transition in
  1811. * *local time* (note: this is *not* equivalent to the output of
  1812. * datetime.timestamp, which is the total number of seconds actual elapsed
  1813. * since 1970-01-01T00:00:00Z in UTC).
  1814. *
  1815. * This is an ambiguous question because "local time" can be ambiguous — but it
  1816. * is disambiguated by the `fold` parameter, so we allocate two arrays:
  1817. *
  1818. * trans_local[0]: The wall-time transitions for fold=0
  1819. * trans_local[1]: The wall-time transitions for fold=1
  1820. *
  1821. * This returns 0 on success and a negative number of failure. The trans_local
  1822. * arrays must be freed if they are not NULL.
  1823. */
  1824. static int
  1825. ts_to_local(size_t *trans_idx, int64_t *trans_utc, long *utcoff,
  1826. int64_t *trans_local[2], size_t num_ttinfos,
  1827. size_t num_transitions)
  1828. {
  1829. if (num_transitions == 0) {
  1830. return 0;
  1831. }
  1832. // Copy the UTC transitions into each array to be modified in place later
  1833. for (size_t i = 0; i < 2; ++i) {
  1834. trans_local[i] = PyMem_Malloc(num_transitions * sizeof(int64_t));
  1835. if (trans_local[i] == NULL) {
  1836. return -1;
  1837. }
  1838. memcpy(trans_local[i], trans_utc, num_transitions * sizeof(int64_t));
  1839. }
  1840. int64_t offset_0, offset_1, buff;
  1841. if (num_ttinfos > 1) {
  1842. offset_0 = utcoff[0];
  1843. offset_1 = utcoff[trans_idx[0]];
  1844. if (offset_1 > offset_0) {
  1845. _swap(offset_0, offset_1, buff);
  1846. }
  1847. }
  1848. else {
  1849. offset_0 = utcoff[0];
  1850. offset_1 = utcoff[0];
  1851. }
  1852. trans_local[0][0] += offset_0;
  1853. trans_local[1][0] += offset_1;
  1854. for (size_t i = 1; i < num_transitions; ++i) {
  1855. offset_0 = utcoff[trans_idx[i - 1]];
  1856. offset_1 = utcoff[trans_idx[i]];
  1857. if (offset_1 > offset_0) {
  1858. _swap(offset_1, offset_0, buff);
  1859. }
  1860. trans_local[0][i] += offset_0;
  1861. trans_local[1][i] += offset_1;
  1862. }
  1863. return 0;
  1864. }
  1865. /* Simple bisect_right binary search implementation */
  1866. static size_t
  1867. _bisect(const int64_t value, const int64_t *arr, size_t size)
  1868. {
  1869. size_t lo = 0;
  1870. size_t hi = size;
  1871. size_t m;
  1872. while (lo < hi) {
  1873. m = (lo + hi) / 2;
  1874. if (arr[m] > value) {
  1875. hi = m;
  1876. }
  1877. else {
  1878. lo = m + 1;
  1879. }
  1880. }
  1881. return hi;
  1882. }
  1883. /* Find the ttinfo rules that apply at a given local datetime. */
  1884. static _ttinfo *
  1885. find_ttinfo(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *dt)
  1886. {
  1887. // datetime.time has a .tzinfo attribute that passes None as the dt
  1888. // argument; it only really has meaning for fixed-offset zones.
  1889. if (dt == Py_None) {
  1890. if (self->fixed_offset) {
  1891. return &(self->tzrule_after.std);
  1892. }
  1893. else {
  1894. return &(state->NO_TTINFO);
  1895. }
  1896. }
  1897. int64_t ts;
  1898. if (get_local_timestamp(dt, &ts)) {
  1899. return NULL;
  1900. }
  1901. unsigned char fold = PyDateTime_DATE_GET_FOLD(dt);
  1902. assert(fold < 2);
  1903. int64_t *local_transitions = self->trans_list_wall[fold];
  1904. size_t num_trans = self->num_transitions;
  1905. if (num_trans && ts < local_transitions[0]) {
  1906. return self->ttinfo_before;
  1907. }
  1908. else if (!num_trans || ts > local_transitions[self->num_transitions - 1]) {
  1909. return find_tzrule_ttinfo(&(self->tzrule_after), ts, fold,
  1910. PyDateTime_GET_YEAR(dt));
  1911. }
  1912. else {
  1913. size_t idx = _bisect(ts, local_transitions, self->num_transitions) - 1;
  1914. assert(idx < self->num_transitions);
  1915. return self->trans_ttinfos[idx];
  1916. }
  1917. }
  1918. static int
  1919. is_leap_year(int year)
  1920. {
  1921. const unsigned int ayear = (unsigned int)year;
  1922. return ayear % 4 == 0 && (ayear % 100 != 0 || ayear % 400 == 0);
  1923. }
  1924. /* Calculates ordinal datetime from year, month and day. */
  1925. static int
  1926. ymd_to_ord(int y, int m, int d)
  1927. {
  1928. y -= 1;
  1929. int days_before_year = (y * 365) + (y / 4) - (y / 100) + (y / 400);
  1930. int yearday = DAYS_BEFORE_MONTH[m];
  1931. if (m > 2 && is_leap_year(y + 1)) {
  1932. yearday += 1;
  1933. }
  1934. return days_before_year + yearday + d;
  1935. }
  1936. /* Calculate the number of seconds since 1970-01-01 in local time.
  1937. *
  1938. * This gets a datetime in the same "units" as self->trans_list_wall so that we
  1939. * can easily determine which transitions a datetime falls between. See the
  1940. * comment above ts_to_local for more information.
  1941. * */
  1942. static int
  1943. get_local_timestamp(PyObject *dt, int64_t *local_ts)
  1944. {
  1945. assert(local_ts != NULL);
  1946. int hour, minute, second;
  1947. int ord;
  1948. if (PyDateTime_CheckExact(dt)) {
  1949. int y = PyDateTime_GET_YEAR(dt);
  1950. int m = PyDateTime_GET_MONTH(dt);
  1951. int d = PyDateTime_GET_DAY(dt);
  1952. hour = PyDateTime_DATE_GET_HOUR(dt);
  1953. minute = PyDateTime_DATE_GET_MINUTE(dt);
  1954. second = PyDateTime_DATE_GET_SECOND(dt);
  1955. ord = ymd_to_ord(y, m, d);
  1956. }
  1957. else {
  1958. PyObject *num = PyObject_CallMethod(dt, "toordinal", NULL);
  1959. if (num == NULL) {
  1960. return -1;
  1961. }
  1962. ord = PyLong_AsLong(num);
  1963. Py_DECREF(num);
  1964. if (ord == -1 && PyErr_Occurred()) {
  1965. return -1;
  1966. }
  1967. num = PyObject_GetAttrString(dt, "hour");
  1968. if (num == NULL) {
  1969. return -1;
  1970. }
  1971. hour = PyLong_AsLong(num);
  1972. Py_DECREF(num);
  1973. if (hour == -1) {
  1974. return -1;
  1975. }
  1976. num = PyObject_GetAttrString(dt, "minute");
  1977. if (num == NULL) {
  1978. return -1;
  1979. }
  1980. minute = PyLong_AsLong(num);
  1981. Py_DECREF(num);
  1982. if (minute == -1) {
  1983. return -1;
  1984. }
  1985. num = PyObject_GetAttrString(dt, "second");
  1986. if (num == NULL) {
  1987. return -1;
  1988. }
  1989. second = PyLong_AsLong(num);
  1990. Py_DECREF(num);
  1991. if (second == -1) {
  1992. return -1;
  1993. }
  1994. }
  1995. *local_ts = (int64_t)(ord - EPOCHORDINAL) * 86400L +
  1996. (int64_t)(hour * 3600L + minute * 60 + second);
  1997. return 0;
  1998. }
  1999. /////
  2000. // Functions for cache handling
  2001. /* Constructor for StrongCacheNode */
  2002. static StrongCacheNode *
  2003. strong_cache_node_new(PyObject *key, PyObject *zone)
  2004. {
  2005. StrongCacheNode *node = PyMem_Malloc(sizeof(StrongCacheNode));
  2006. if (node == NULL) {
  2007. return NULL;
  2008. }
  2009. node->next = NULL;
  2010. node->prev = NULL;
  2011. node->key = Py_NewRef(key);
  2012. node->zone = Py_NewRef(zone);
  2013. return node;
  2014. }
  2015. /* Destructor for StrongCacheNode */
  2016. void
  2017. strong_cache_node_free(StrongCacheNode *node)
  2018. {
  2019. Py_XDECREF(node->key);
  2020. Py_XDECREF(node->zone);
  2021. PyMem_Free(node);
  2022. }
  2023. /* Frees all nodes at or after a specified root in the strong cache.
  2024. *
  2025. * This can be used on the root node to free the entire cache or it can be used
  2026. * to clear all nodes that have been expired (which, if everything is going
  2027. * right, will actually only be 1 node at a time).
  2028. */
  2029. void
  2030. strong_cache_free(StrongCacheNode *root)
  2031. {
  2032. StrongCacheNode *node = root;
  2033. StrongCacheNode *next_node;
  2034. while (node != NULL) {
  2035. next_node = node->next;
  2036. strong_cache_node_free(node);
  2037. node = next_node;
  2038. }
  2039. }
  2040. /* Removes a node from the cache and update its neighbors.
  2041. *
  2042. * This is used both when ejecting a node from the cache and when moving it to
  2043. * the front of the cache.
  2044. */
  2045. static void
  2046. remove_from_strong_cache(zoneinfo_state *state, StrongCacheNode *node)
  2047. {
  2048. if (state->ZONEINFO_STRONG_CACHE == node) {
  2049. state->ZONEINFO_STRONG_CACHE = node->next;
  2050. }
  2051. if (node->prev != NULL) {
  2052. node->prev->next = node->next;
  2053. }
  2054. if (node->next != NULL) {
  2055. node->next->prev = node->prev;
  2056. }
  2057. node->next = NULL;
  2058. node->prev = NULL;
  2059. }
  2060. /* Retrieves the node associated with a key, if it exists.
  2061. *
  2062. * This traverses the strong cache until it finds a matching key and returns a
  2063. * pointer to the relevant node if found. Returns NULL if no node is found.
  2064. *
  2065. * root may be NULL, indicating an empty cache.
  2066. */
  2067. static StrongCacheNode *
  2068. find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key)
  2069. {
  2070. const StrongCacheNode *node = root;
  2071. while (node != NULL) {
  2072. int rv = PyObject_RichCompareBool(key, node->key, Py_EQ);
  2073. if (rv < 0) {
  2074. return NULL;
  2075. }
  2076. if (rv) {
  2077. return (StrongCacheNode *)node;
  2078. }
  2079. node = node->next;
  2080. }
  2081. return NULL;
  2082. }
  2083. /* Ejects a given key from the class's strong cache, if applicable.
  2084. *
  2085. * This function is used to enable the per-key functionality in clear_cache.
  2086. */
  2087. static int
  2088. eject_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  2089. PyObject *key)
  2090. {
  2091. if (type != state->ZoneInfoType) {
  2092. return 0;
  2093. }
  2094. StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE;
  2095. StrongCacheNode *node = find_in_strong_cache(cache, key);
  2096. if (node != NULL) {
  2097. remove_from_strong_cache(state, node);
  2098. strong_cache_node_free(node);
  2099. }
  2100. else if (PyErr_Occurred()) {
  2101. return -1;
  2102. }
  2103. return 0;
  2104. }
  2105. /* Moves a node to the front of the LRU cache.
  2106. *
  2107. * The strong cache is an LRU cache, so whenever a given node is accessed, if
  2108. * it is not at the front of the cache, it needs to be moved there.
  2109. */
  2110. static void
  2111. move_strong_cache_node_to_front(zoneinfo_state *state, StrongCacheNode **root,
  2112. StrongCacheNode *node)
  2113. {
  2114. StrongCacheNode *root_p = *root;
  2115. if (root_p == node) {
  2116. return;
  2117. }
  2118. remove_from_strong_cache(state, node);
  2119. node->prev = NULL;
  2120. node->next = root_p;
  2121. if (root_p != NULL) {
  2122. root_p->prev = node;
  2123. }
  2124. *root = node;
  2125. }
  2126. /* Retrieves a ZoneInfo from the strong cache if it's present.
  2127. *
  2128. * This function finds the ZoneInfo by key and if found will move the node to
  2129. * the front of the LRU cache and return a new reference to it. It returns NULL
  2130. * if the key is not in the cache.
  2131. *
  2132. * The strong cache is currently only implemented for the base class, so this
  2133. * always returns a cache miss for subclasses.
  2134. */
  2135. static PyObject *
  2136. zone_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  2137. PyObject *const key)
  2138. {
  2139. if (type != state->ZoneInfoType) {
  2140. return NULL; // Strong cache currently only implemented for base class
  2141. }
  2142. StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE;
  2143. StrongCacheNode *node = find_in_strong_cache(cache, key);
  2144. if (node != NULL) {
  2145. StrongCacheNode **root = &(state->ZONEINFO_STRONG_CACHE);
  2146. move_strong_cache_node_to_front(state, root, node);
  2147. return Py_NewRef(node->zone);
  2148. }
  2149. return NULL; // Cache miss
  2150. }
  2151. /* Inserts a new key into the strong LRU cache.
  2152. *
  2153. * This function is only to be used after a cache miss — it creates a new node
  2154. * at the front of the cache and ejects any stale entries (keeping the size of
  2155. * the cache to at most ZONEINFO_STRONG_CACHE_MAX_SIZE).
  2156. */
  2157. static void
  2158. update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
  2159. PyObject *key, PyObject *zone)
  2160. {
  2161. if (type != state->ZoneInfoType) {
  2162. return;
  2163. }
  2164. StrongCacheNode *new_node = strong_cache_node_new(key, zone);
  2165. StrongCacheNode **root = &(state->ZONEINFO_STRONG_CACHE);
  2166. move_strong_cache_node_to_front(state, root, new_node);
  2167. StrongCacheNode *node = new_node->next;
  2168. for (size_t i = 1; i < ZONEINFO_STRONG_CACHE_MAX_SIZE; ++i) {
  2169. if (node == NULL) {
  2170. return;
  2171. }
  2172. node = node->next;
  2173. }
  2174. // Everything beyond this point needs to be freed
  2175. if (node != NULL) {
  2176. if (node->prev != NULL) {
  2177. node->prev->next = NULL;
  2178. }
  2179. strong_cache_free(node);
  2180. }
  2181. }
  2182. /* Clears all entries into a type's strong cache.
  2183. *
  2184. * Because the strong cache is not implemented for subclasses, this is a no-op
  2185. * for everything except the base class.
  2186. */
  2187. void
  2188. clear_strong_cache(zoneinfo_state *state, const PyTypeObject *const type)
  2189. {
  2190. if (type != state->ZoneInfoType) {
  2191. return;
  2192. }
  2193. strong_cache_free(state->ZONEINFO_STRONG_CACHE);
  2194. state->ZONEINFO_STRONG_CACHE = NULL;
  2195. }
  2196. static PyObject *
  2197. new_weak_cache(void)
  2198. {
  2199. PyObject *WeakValueDictionary =
  2200. _PyImport_GetModuleAttrString("weakref", "WeakValueDictionary");
  2201. if (WeakValueDictionary == NULL) {
  2202. return NULL;
  2203. }
  2204. PyObject *weak_cache = PyObject_CallNoArgs(WeakValueDictionary);
  2205. Py_DECREF(WeakValueDictionary);
  2206. return weak_cache;
  2207. }
  2208. // This function is not idempotent and must be called on a new module object.
  2209. static int
  2210. initialize_caches(zoneinfo_state *state)
  2211. {
  2212. state->TIMEDELTA_CACHE = PyDict_New();
  2213. if (state->TIMEDELTA_CACHE == NULL) {
  2214. return -1;
  2215. }
  2216. state->ZONEINFO_WEAK_CACHE = new_weak_cache();
  2217. if (state->ZONEINFO_WEAK_CACHE == NULL) {
  2218. return -1;
  2219. }
  2220. return 0;
  2221. }
  2222. static PyObject *
  2223. zoneinfo_init_subclass(PyTypeObject *cls, PyObject *args, PyObject **kwargs)
  2224. {
  2225. PyObject *weak_cache = new_weak_cache();
  2226. if (weak_cache == NULL) {
  2227. return NULL;
  2228. }
  2229. if (PyObject_SetAttrString((PyObject *)cls, "_weak_cache",
  2230. weak_cache) < 0) {
  2231. Py_DECREF(weak_cache);
  2232. return NULL;
  2233. }
  2234. Py_DECREF(weak_cache);
  2235. Py_RETURN_NONE;
  2236. }
  2237. /////
  2238. // Specify the ZoneInfo type
  2239. static PyMethodDef zoneinfo_methods[] = {
  2240. ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF
  2241. ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF
  2242. ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF
  2243. ZONEINFO_ZONEINFO_UTCOFFSET_METHODDEF
  2244. ZONEINFO_ZONEINFO_DST_METHODDEF
  2245. ZONEINFO_ZONEINFO_TZNAME_METHODDEF
  2246. {"fromutc", (PyCFunction)zoneinfo_fromutc, METH_O,
  2247. PyDoc_STR("Given a datetime with local time in UTC, retrieve an adjusted "
  2248. "datetime in local time.")},
  2249. {"__reduce__", (PyCFunction)zoneinfo_reduce, METH_NOARGS,
  2250. PyDoc_STR("Function for serialization with the pickle protocol.")},
  2251. ZONEINFO_ZONEINFO__UNPICKLE_METHODDEF
  2252. {"__init_subclass__", (PyCFunction)(void (*)(void))zoneinfo_init_subclass,
  2253. METH_VARARGS | METH_KEYWORDS | METH_CLASS,
  2254. PyDoc_STR("Function to initialize subclasses.")},
  2255. {NULL} /* Sentinel */
  2256. };
  2257. static PyMemberDef zoneinfo_members[] = {
  2258. {.name = "key",
  2259. .offset = offsetof(PyZoneInfo_ZoneInfo, key),
  2260. .type = T_OBJECT_EX,
  2261. .flags = READONLY,
  2262. .doc = NULL},
  2263. {.name = "__weaklistoffset__",
  2264. .offset = offsetof(PyZoneInfo_ZoneInfo, weakreflist),
  2265. .type = T_PYSSIZET,
  2266. .flags = READONLY},
  2267. {NULL}, /* Sentinel */
  2268. };
  2269. static PyType_Slot zoneinfo_slots[] = {
  2270. {Py_tp_repr, zoneinfo_repr},
  2271. {Py_tp_str, zoneinfo_str},
  2272. {Py_tp_getattro, PyObject_GenericGetAttr},
  2273. {Py_tp_methods, zoneinfo_methods},
  2274. {Py_tp_members, zoneinfo_members},
  2275. {Py_tp_new, zoneinfo_new},
  2276. {Py_tp_dealloc, zoneinfo_dealloc},
  2277. {Py_tp_traverse, zoneinfo_traverse},
  2278. {Py_tp_clear, zoneinfo_clear},
  2279. {0, NULL},
  2280. };
  2281. static PyType_Spec zoneinfo_spec = {
  2282. .name = "zoneinfo.ZoneInfo",
  2283. .basicsize = sizeof(PyZoneInfo_ZoneInfo),
  2284. .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
  2285. Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
  2286. .slots = zoneinfo_slots,
  2287. };
  2288. /////
  2289. // Specify the _zoneinfo module
  2290. static PyMethodDef module_methods[] = {{NULL, NULL}};
  2291. static int
  2292. module_traverse(PyObject *mod, visitproc visit, void *arg)
  2293. {
  2294. zoneinfo_state *state = zoneinfo_get_state(mod);
  2295. Py_VISIT(state->ZoneInfoType);
  2296. Py_VISIT(state->io_open);
  2297. Py_VISIT(state->_tzpath_find_tzfile);
  2298. Py_VISIT(state->_common_mod);
  2299. Py_VISIT(state->TIMEDELTA_CACHE);
  2300. Py_VISIT(state->ZONEINFO_WEAK_CACHE);
  2301. StrongCacheNode *node = state->ZONEINFO_STRONG_CACHE;
  2302. while (node != NULL) {
  2303. StrongCacheNode *next = node->next;
  2304. Py_VISIT(node->key);
  2305. Py_VISIT(node->zone);
  2306. node = next;
  2307. }
  2308. Py_VISIT(state->NO_TTINFO.utcoff);
  2309. Py_VISIT(state->NO_TTINFO.dstoff);
  2310. Py_VISIT(state->NO_TTINFO.tzname);
  2311. return 0;
  2312. }
  2313. static int
  2314. module_clear(PyObject *mod)
  2315. {
  2316. zoneinfo_state *state = zoneinfo_get_state(mod);
  2317. Py_CLEAR(state->ZoneInfoType);
  2318. Py_CLEAR(state->io_open);
  2319. Py_CLEAR(state->_tzpath_find_tzfile);
  2320. Py_CLEAR(state->_common_mod);
  2321. Py_CLEAR(state->TIMEDELTA_CACHE);
  2322. Py_CLEAR(state->ZONEINFO_WEAK_CACHE);
  2323. clear_strong_cache(state, state->ZoneInfoType);
  2324. Py_CLEAR(state->NO_TTINFO.utcoff);
  2325. Py_CLEAR(state->NO_TTINFO.dstoff);
  2326. Py_CLEAR(state->NO_TTINFO.tzname);
  2327. return 0;
  2328. }
  2329. static void
  2330. module_free(void *mod)
  2331. {
  2332. (void)module_clear((PyObject *)mod);
  2333. }
  2334. static int
  2335. zoneinfomodule_exec(PyObject *m)
  2336. {
  2337. PyDateTime_IMPORT;
  2338. if (PyDateTimeAPI == NULL) {
  2339. goto error;
  2340. }
  2341. zoneinfo_state *state = zoneinfo_get_state(m);
  2342. PyObject *base = (PyObject *)PyDateTimeAPI->TZInfoType;
  2343. state->ZoneInfoType = (PyTypeObject *)PyType_FromModuleAndSpec(m,
  2344. &zoneinfo_spec, base);
  2345. if (state->ZoneInfoType == NULL) {
  2346. goto error;
  2347. }
  2348. int rc = PyModule_AddObjectRef(m, "ZoneInfo",
  2349. (PyObject *)state->ZoneInfoType);
  2350. if (rc < 0) {
  2351. goto error;
  2352. }
  2353. /* Populate imports */
  2354. state->_tzpath_find_tzfile =
  2355. _PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile");
  2356. if (state->_tzpath_find_tzfile == NULL) {
  2357. goto error;
  2358. }
  2359. state->io_open = _PyImport_GetModuleAttrString("io", "open");
  2360. if (state->io_open == NULL) {
  2361. goto error;
  2362. }
  2363. state->_common_mod = PyImport_ImportModule("zoneinfo._common");
  2364. if (state->_common_mod == NULL) {
  2365. goto error;
  2366. }
  2367. if (state->NO_TTINFO.utcoff == NULL) {
  2368. state->NO_TTINFO.utcoff = Py_NewRef(Py_None);
  2369. state->NO_TTINFO.dstoff = Py_NewRef(Py_None);
  2370. state->NO_TTINFO.tzname = Py_NewRef(Py_None);
  2371. }
  2372. if (initialize_caches(state)) {
  2373. goto error;
  2374. }
  2375. return 0;
  2376. error:
  2377. return -1;
  2378. }
  2379. static PyModuleDef_Slot zoneinfomodule_slots[] = {
  2380. {Py_mod_exec, zoneinfomodule_exec},
  2381. {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
  2382. {0, NULL},
  2383. };
  2384. static struct PyModuleDef zoneinfomodule = {
  2385. .m_base = PyModuleDef_HEAD_INIT,
  2386. .m_name = "_zoneinfo",
  2387. .m_doc = "C implementation of the zoneinfo module",
  2388. .m_size = sizeof(zoneinfo_state),
  2389. .m_methods = module_methods,
  2390. .m_slots = zoneinfomodule_slots,
  2391. .m_traverse = module_traverse,
  2392. .m_clear = module_clear,
  2393. .m_free = module_free,
  2394. };
  2395. PyMODINIT_FUNC
  2396. PyInit__zoneinfo(void)
  2397. {
  2398. return PyModuleDef_Init(&zoneinfomodule);
  2399. }