Branch data Line data Source code
1 : : /* C implementation for the date/time type documented at
2 : : * https://www.zope.dev/Members/fdrake/DateTimeWiki/FrontPage
3 : : */
4 : :
5 : : /* bpo-35081: Defining this prevents including the C API capsule;
6 : : * internal versions of the Py*_Check macros which do not require
7 : : * the capsule are defined below */
8 : : #define _PY_DATETIME_IMPL
9 : :
10 : : #ifndef Py_BUILD_CORE_BUILTIN
11 : : # define Py_BUILD_CORE_MODULE 1
12 : : #endif
13 : :
14 : : #include "Python.h"
15 : : #include "pycore_long.h" // _PyLong_GetOne()
16 : : #include "pycore_object.h" // _PyObject_Init()
17 : : #include "datetime.h"
18 : : #include "structmember.h" // PyMemberDef
19 : :
20 : : #include <time.h>
21 : :
22 : : #ifdef MS_WINDOWS
23 : : # include <winsock2.h> /* struct timeval */
24 : : #endif
25 : :
26 : : #define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType)
27 : : #define PyDate_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateType)
28 : :
29 : : #define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType)
30 : : #define PyDateTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateTimeType)
31 : :
32 : : #define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType)
33 : : #define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType)
34 : :
35 : : #define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType)
36 : : #define PyDelta_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DeltaType)
37 : :
38 : : #define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType)
39 : : #define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TZInfoType)
40 : :
41 : : #define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType)
42 : :
43 : : /*[clinic input]
44 : : module datetime
45 : : class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
46 : : class datetime.date "PyDateTime_Date *" "&PyDateTime_DateType"
47 : : class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType"
48 : : [clinic start generated code]*/
49 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=81bec0fa19837f63]*/
50 : :
51 : : #include "clinic/_datetimemodule.c.h"
52 : :
53 : : /* We require that C int be at least 32 bits, and use int virtually
54 : : * everywhere. In just a few cases we use a temp long, where a Python
55 : : * API returns a C long. In such cases, we have to ensure that the
56 : : * final result fits in a C int (this can be an issue on 64-bit boxes).
57 : : */
58 : : #if SIZEOF_INT < 4
59 : : # error "_datetime.c requires that C int have at least 32 bits"
60 : : #endif
61 : :
62 : : #define MINYEAR 1
63 : : #define MAXYEAR 9999
64 : : #define MAXORDINAL 3652059 /* date(9999,12,31).toordinal() */
65 : :
66 : : /* Nine decimal digits is easy to communicate, and leaves enough room
67 : : * so that two delta days can be added w/o fear of overflowing a signed
68 : : * 32-bit int, and with plenty of room left over to absorb any possible
69 : : * carries from adding seconds.
70 : : */
71 : : #define MAX_DELTA_DAYS 999999999
72 : :
73 : : /* Rename the long macros in datetime.h to more reasonable short names. */
74 : : #define GET_YEAR PyDateTime_GET_YEAR
75 : : #define GET_MONTH PyDateTime_GET_MONTH
76 : : #define GET_DAY PyDateTime_GET_DAY
77 : : #define DATE_GET_HOUR PyDateTime_DATE_GET_HOUR
78 : : #define DATE_GET_MINUTE PyDateTime_DATE_GET_MINUTE
79 : : #define DATE_GET_SECOND PyDateTime_DATE_GET_SECOND
80 : : #define DATE_GET_MICROSECOND PyDateTime_DATE_GET_MICROSECOND
81 : : #define DATE_GET_FOLD PyDateTime_DATE_GET_FOLD
82 : :
83 : : /* Date accessors for date and datetime. */
84 : : #define SET_YEAR(o, v) (((o)->data[0] = ((v) & 0xff00) >> 8), \
85 : : ((o)->data[1] = ((v) & 0x00ff)))
86 : : #define SET_MONTH(o, v) (PyDateTime_GET_MONTH(o) = (v))
87 : : #define SET_DAY(o, v) (PyDateTime_GET_DAY(o) = (v))
88 : :
89 : : /* Date/Time accessors for datetime. */
90 : : #define DATE_SET_HOUR(o, v) (PyDateTime_DATE_GET_HOUR(o) = (v))
91 : : #define DATE_SET_MINUTE(o, v) (PyDateTime_DATE_GET_MINUTE(o) = (v))
92 : : #define DATE_SET_SECOND(o, v) (PyDateTime_DATE_GET_SECOND(o) = (v))
93 : : #define DATE_SET_MICROSECOND(o, v) \
94 : : (((o)->data[7] = ((v) & 0xff0000) >> 16), \
95 : : ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
96 : : ((o)->data[9] = ((v) & 0x0000ff)))
97 : : #define DATE_SET_FOLD(o, v) (PyDateTime_DATE_GET_FOLD(o) = (v))
98 : :
99 : : /* Time accessors for time. */
100 : : #define TIME_GET_HOUR PyDateTime_TIME_GET_HOUR
101 : : #define TIME_GET_MINUTE PyDateTime_TIME_GET_MINUTE
102 : : #define TIME_GET_SECOND PyDateTime_TIME_GET_SECOND
103 : : #define TIME_GET_MICROSECOND PyDateTime_TIME_GET_MICROSECOND
104 : : #define TIME_GET_FOLD PyDateTime_TIME_GET_FOLD
105 : : #define TIME_SET_HOUR(o, v) (PyDateTime_TIME_GET_HOUR(o) = (v))
106 : : #define TIME_SET_MINUTE(o, v) (PyDateTime_TIME_GET_MINUTE(o) = (v))
107 : : #define TIME_SET_SECOND(o, v) (PyDateTime_TIME_GET_SECOND(o) = (v))
108 : : #define TIME_SET_MICROSECOND(o, v) \
109 : : (((o)->data[3] = ((v) & 0xff0000) >> 16), \
110 : : ((o)->data[4] = ((v) & 0x00ff00) >> 8), \
111 : : ((o)->data[5] = ((v) & 0x0000ff)))
112 : : #define TIME_SET_FOLD(o, v) (PyDateTime_TIME_GET_FOLD(o) = (v))
113 : :
114 : : /* Delta accessors for timedelta. */
115 : : #define GET_TD_DAYS(o) (((PyDateTime_Delta *)(o))->days)
116 : : #define GET_TD_SECONDS(o) (((PyDateTime_Delta *)(o))->seconds)
117 : : #define GET_TD_MICROSECONDS(o) (((PyDateTime_Delta *)(o))->microseconds)
118 : :
119 : : #define SET_TD_DAYS(o, v) ((o)->days = (v))
120 : : #define SET_TD_SECONDS(o, v) ((o)->seconds = (v))
121 : : #define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
122 : :
123 : : #define HASTZINFO _PyDateTime_HAS_TZINFO
124 : : #define GET_TIME_TZINFO PyDateTime_TIME_GET_TZINFO
125 : : #define GET_DT_TZINFO PyDateTime_DATE_GET_TZINFO
126 : : /* M is a char or int claiming to be a valid month. The macro is equivalent
127 : : * to the two-sided Python test
128 : : * 1 <= M <= 12
129 : : */
130 : : #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)
131 : :
132 : : /* Forward declarations. */
133 : : static PyTypeObject PyDateTime_DateType;
134 : : static PyTypeObject PyDateTime_DateTimeType;
135 : : static PyTypeObject PyDateTime_DeltaType;
136 : : static PyTypeObject PyDateTime_IsoCalendarDateType;
137 : : static PyTypeObject PyDateTime_TimeType;
138 : : static PyTypeObject PyDateTime_TZInfoType;
139 : : static PyTypeObject PyDateTime_TimeZoneType;
140 : :
141 : : static int check_tzinfo_subclass(PyObject *p);
142 : :
143 : :
144 : : /* ---------------------------------------------------------------------------
145 : : * Math utilities.
146 : : */
147 : :
148 : : /* k = i+j overflows iff k differs in sign from both inputs,
149 : : * iff k^i has sign bit set and k^j has sign bit set,
150 : : * iff (k^i)&(k^j) has sign bit set.
151 : : */
152 : : #define SIGNED_ADD_OVERFLOWED(RESULT, I, J) \
153 : : ((((RESULT) ^ (I)) & ((RESULT) ^ (J))) < 0)
154 : :
155 : : /* Compute Python divmod(x, y), returning the quotient and storing the
156 : : * remainder into *r. The quotient is the floor of x/y, and that's
157 : : * the real point of this. C will probably truncate instead (C99
158 : : * requires truncation; C89 left it implementation-defined).
159 : : * Simplification: we *require* that y > 0 here. That's appropriate
160 : : * for all the uses made of it. This simplifies the code and makes
161 : : * the overflow case impossible (divmod(LONG_MIN, -1) is the only
162 : : * overflow case).
163 : : */
164 : : static int
165 : 0 : divmod(int x, int y, int *r)
166 : : {
167 : : int quo;
168 : :
169 : : assert(y > 0);
170 : 0 : quo = x / y;
171 : 0 : *r = x - quo * y;
172 [ # # ]: 0 : if (*r < 0) {
173 : 0 : --quo;
174 : 0 : *r += y;
175 : : }
176 : : assert(0 <= *r && *r < y);
177 : 0 : return quo;
178 : : }
179 : :
180 : : /* Nearest integer to m / n for integers m and n. Half-integer results
181 : : * are rounded to even.
182 : : */
183 : : static PyObject *
184 : 0 : divide_nearest(PyObject *m, PyObject *n)
185 : : {
186 : : PyObject *result;
187 : : PyObject *temp;
188 : :
189 : 0 : temp = _PyLong_DivmodNear(m, n);
190 [ # # ]: 0 : if (temp == NULL)
191 : 0 : return NULL;
192 : 0 : result = Py_NewRef(PyTuple_GET_ITEM(temp, 0));
193 : 0 : Py_DECREF(temp);
194 : :
195 : 0 : return result;
196 : : }
197 : :
198 : : /* ---------------------------------------------------------------------------
199 : : * General calendrical helper functions
200 : : */
201 : :
202 : : /* For each month ordinal in 1..12, the number of days in that month,
203 : : * and the number of days before that month in the same year. These
204 : : * are correct for non-leap years only.
205 : : */
206 : : static const int _days_in_month[] = {
207 : : 0, /* unused; this vector uses 1-based indexing */
208 : : 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
209 : : };
210 : :
211 : : static const int _days_before_month[] = {
212 : : 0, /* unused; this vector uses 1-based indexing */
213 : : 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
214 : : };
215 : :
216 : : /* year -> 1 if leap year, else 0. */
217 : : static int
218 : 0 : is_leap(int year)
219 : : {
220 : : /* Cast year to unsigned. The result is the same either way, but
221 : : * C can generate faster code for unsigned mod than for signed
222 : : * mod (especially for % 4 -- a good compiler should just grab
223 : : * the last 2 bits when the LHS is unsigned).
224 : : */
225 : 0 : const unsigned int ayear = (unsigned int)year;
226 [ # # # # : 0 : return ayear % 4 == 0 && (ayear % 100 != 0 || ayear % 400 == 0);
# # ]
227 : : }
228 : :
229 : : /* year, month -> number of days in that month in that year */
230 : : static int
231 : 5 : days_in_month(int year, int month)
232 : : {
233 : : assert(month >= 1);
234 : : assert(month <= 12);
235 [ - + - - ]: 5 : if (month == 2 && is_leap(year))
236 : 0 : return 29;
237 : : else
238 : 5 : return _days_in_month[month];
239 : : }
240 : :
241 : : /* year, month -> number of days in year preceding first day of month */
242 : : static int
243 : 0 : days_before_month(int year, int month)
244 : : {
245 : : int days;
246 : :
247 : : assert(month >= 1);
248 : : assert(month <= 12);
249 : 0 : days = _days_before_month[month];
250 [ # # # # ]: 0 : if (month > 2 && is_leap(year))
251 : 0 : ++days;
252 : 0 : return days;
253 : : }
254 : :
255 : : /* year -> number of days before January 1st of year. Remember that we
256 : : * start with year 1, so days_before_year(1) == 0.
257 : : */
258 : : static int
259 : 0 : days_before_year(int year)
260 : : {
261 : 0 : int y = year - 1;
262 : : /* This is incorrect if year <= 0; we really want the floor
263 : : * here. But so long as MINYEAR is 1, the smallest year this
264 : : * can see is 1.
265 : : */
266 : : assert (year >= 1);
267 : 0 : return y*365 + y/4 - y/100 + y/400;
268 : : }
269 : :
270 : : /* Number of days in 4, 100, and 400 year cycles. That these have
271 : : * the correct values is asserted in the module init function.
272 : : */
273 : : #define DI4Y 1461 /* days_before_year(5); days in 4 years */
274 : : #define DI100Y 36524 /* days_before_year(101); days in 100 years */
275 : : #define DI400Y 146097 /* days_before_year(401); days in 400 years */
276 : :
277 : : /* ordinal -> year, month, day, considering 01-Jan-0001 as day 1. */
278 : : static void
279 : 0 : ord_to_ymd(int ordinal, int *year, int *month, int *day)
280 : : {
281 : : int n, n1, n4, n100, n400, leapyear, preceding;
282 : :
283 : : /* ordinal is a 1-based index, starting at 1-Jan-1. The pattern of
284 : : * leap years repeats exactly every 400 years. The basic strategy is
285 : : * to find the closest 400-year boundary at or before ordinal, then
286 : : * work with the offset from that boundary to ordinal. Life is much
287 : : * clearer if we subtract 1 from ordinal first -- then the values
288 : : * of ordinal at 400-year boundaries are exactly those divisible
289 : : * by DI400Y:
290 : : *
291 : : * D M Y n n-1
292 : : * -- --- ---- ---------- ----------------
293 : : * 31 Dec -400 -DI400Y -DI400Y -1
294 : : * 1 Jan -399 -DI400Y +1 -DI400Y 400-year boundary
295 : : * ...
296 : : * 30 Dec 000 -1 -2
297 : : * 31 Dec 000 0 -1
298 : : * 1 Jan 001 1 0 400-year boundary
299 : : * 2 Jan 001 2 1
300 : : * 3 Jan 001 3 2
301 : : * ...
302 : : * 31 Dec 400 DI400Y DI400Y -1
303 : : * 1 Jan 401 DI400Y +1 DI400Y 400-year boundary
304 : : */
305 : : assert(ordinal >= 1);
306 : 0 : --ordinal;
307 : 0 : n400 = ordinal / DI400Y;
308 : 0 : n = ordinal % DI400Y;
309 : 0 : *year = n400 * 400 + 1;
310 : :
311 : : /* Now n is the (non-negative) offset, in days, from January 1 of
312 : : * year, to the desired date. Now compute how many 100-year cycles
313 : : * precede n.
314 : : * Note that it's possible for n100 to equal 4! In that case 4 full
315 : : * 100-year cycles precede the desired day, which implies the
316 : : * desired day is December 31 at the end of a 400-year cycle.
317 : : */
318 : 0 : n100 = n / DI100Y;
319 : 0 : n = n % DI100Y;
320 : :
321 : : /* Now compute how many 4-year cycles precede it. */
322 : 0 : n4 = n / DI4Y;
323 : 0 : n = n % DI4Y;
324 : :
325 : : /* And now how many single years. Again n1 can be 4, and again
326 : : * meaning that the desired day is December 31 at the end of the
327 : : * 4-year cycle.
328 : : */
329 : 0 : n1 = n / 365;
330 : 0 : n = n % 365;
331 : :
332 : 0 : *year += n100 * 100 + n4 * 4 + n1;
333 [ # # # # ]: 0 : if (n1 == 4 || n100 == 4) {
334 : : assert(n == 0);
335 : 0 : *year -= 1;
336 : 0 : *month = 12;
337 : 0 : *day = 31;
338 : 0 : return;
339 : : }
340 : :
341 : : /* Now the year is correct, and n is the offset from January 1. We
342 : : * find the month via an estimate that's either exact or one too
343 : : * large.
344 : : */
345 [ # # # # : 0 : leapyear = n1 == 3 && (n4 != 24 || n100 == 3);
# # ]
346 : : assert(leapyear == is_leap(*year));
347 : 0 : *month = (n + 50) >> 5;
348 [ # # # # ]: 0 : preceding = (_days_before_month[*month] + (*month > 2 && leapyear));
349 [ # # ]: 0 : if (preceding > n) {
350 : : /* estimate is too large */
351 : 0 : *month -= 1;
352 : 0 : preceding -= days_in_month(*year, *month);
353 : : }
354 : 0 : n -= preceding;
355 : : assert(0 <= n);
356 : : assert(n < days_in_month(*year, *month));
357 : :
358 : 0 : *day = n + 1;
359 : : }
360 : :
361 : : /* year, month, day -> ordinal, considering 01-Jan-0001 as day 1. */
362 : : static int
363 : 0 : ymd_to_ord(int year, int month, int day)
364 : : {
365 : 0 : return days_before_year(year) + days_before_month(year, month) + day;
366 : : }
367 : :
368 : : /* Day of week, where Monday==0, ..., Sunday==6. 1/1/1 was a Monday. */
369 : : static int
370 : 0 : weekday(int year, int month, int day)
371 : : {
372 : 0 : return (ymd_to_ord(year, month, day) + 6) % 7;
373 : : }
374 : :
375 : : /* Ordinal of the Monday starting week 1 of the ISO year. Week 1 is the
376 : : * first calendar week containing a Thursday.
377 : : */
378 : : static int
379 : 0 : iso_week1_monday(int year)
380 : : {
381 : 0 : int first_day = ymd_to_ord(year, 1, 1); /* ord of 1/1 */
382 : : /* 0 if 1/1 is a Monday, 1 if a Tue, etc. */
383 : 0 : int first_weekday = (first_day + 6) % 7;
384 : : /* ordinal of closest Monday at or before 1/1 */
385 : 0 : int week1_monday = first_day - first_weekday;
386 : :
387 [ # # ]: 0 : if (first_weekday > 3) /* if 1/1 was Fri, Sat, Sun */
388 : 0 : week1_monday += 7;
389 : 0 : return week1_monday;
390 : : }
391 : :
392 : : static int
393 : 0 : iso_to_ymd(const int iso_year, const int iso_week, const int iso_day,
394 : : int *year, int *month, int *day) {
395 [ # # # # ]: 0 : if (iso_week <= 0 || iso_week >= 53) {
396 : 0 : int out_of_range = 1;
397 [ # # ]: 0 : if (iso_week == 53) {
398 : : // ISO years have 53 weeks in it on years starting with a Thursday
399 : : // and on leap years starting on Wednesday
400 : 0 : int first_weekday = weekday(iso_year, 1, 1);
401 [ # # # # : 0 : if (first_weekday == 3 || (first_weekday == 2 && is_leap(iso_year))) {
# # ]
402 : 0 : out_of_range = 0;
403 : : }
404 : : }
405 : :
406 [ # # ]: 0 : if (out_of_range) {
407 : 0 : return -2;
408 : : }
409 : : }
410 : :
411 [ # # # # ]: 0 : if (iso_day <= 0 || iso_day >= 8) {
412 : 0 : return -3;
413 : : }
414 : :
415 : : // Convert (Y, W, D) to (Y, M, D) in-place
416 : 0 : int day_1 = iso_week1_monday(iso_year);
417 : :
418 : 0 : int day_offset = (iso_week - 1)*7 + iso_day - 1;
419 : :
420 : 0 : ord_to_ymd(day_1 + day_offset, year, month, day);
421 : 0 : return 0;
422 : : }
423 : :
424 : :
425 : : /* ---------------------------------------------------------------------------
426 : : * Range checkers.
427 : : */
428 : :
429 : : /* Check that -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS. If so, return 0.
430 : : * If not, raise OverflowError and return -1.
431 : : */
432 : : static int
433 : 9 : check_delta_day_range(int days)
434 : : {
435 [ + - + - ]: 9 : if (-MAX_DELTA_DAYS <= days && days <= MAX_DELTA_DAYS)
436 : 9 : return 0;
437 : 0 : PyErr_Format(PyExc_OverflowError,
438 : : "days=%d; must have magnitude <= %d",
439 : : days, MAX_DELTA_DAYS);
440 : 0 : return -1;
441 : : }
442 : :
443 : : /* Check that date arguments are in range. Return 0 if they are. If they
444 : : * aren't, raise ValueError and return -1.
445 : : */
446 : : static int
447 : 5 : check_date_args(int year, int month, int day)
448 : : {
449 : :
450 [ + - - + ]: 5 : if (year < MINYEAR || year > MAXYEAR) {
451 : 0 : PyErr_Format(PyExc_ValueError, "year %i is out of range", year);
452 : 0 : return -1;
453 : : }
454 [ + - - + ]: 5 : if (month < 1 || month > 12) {
455 : 0 : PyErr_SetString(PyExc_ValueError,
456 : : "month must be in 1..12");
457 : 0 : return -1;
458 : : }
459 [ + - - + ]: 5 : if (day < 1 || day > days_in_month(year, month)) {
460 : 0 : PyErr_SetString(PyExc_ValueError,
461 : : "day is out of range for month");
462 : 0 : return -1;
463 : : }
464 : 5 : return 0;
465 : : }
466 : :
467 : : /* Check that time arguments are in range. Return 0 if they are. If they
468 : : * aren't, raise ValueError and return -1.
469 : : */
470 : : static int
471 : 5 : check_time_args(int h, int m, int s, int us, int fold)
472 : : {
473 [ + - - + ]: 5 : if (h < 0 || h > 23) {
474 : 0 : PyErr_SetString(PyExc_ValueError,
475 : : "hour must be in 0..23");
476 : 0 : return -1;
477 : : }
478 [ + - - + ]: 5 : if (m < 0 || m > 59) {
479 : 0 : PyErr_SetString(PyExc_ValueError,
480 : : "minute must be in 0..59");
481 : 0 : return -1;
482 : : }
483 [ + - - + ]: 5 : if (s < 0 || s > 59) {
484 : 0 : PyErr_SetString(PyExc_ValueError,
485 : : "second must be in 0..59");
486 : 0 : return -1;
487 : : }
488 [ + - - + ]: 5 : if (us < 0 || us > 999999) {
489 : 0 : PyErr_SetString(PyExc_ValueError,
490 : : "microsecond must be in 0..999999");
491 : 0 : return -1;
492 : : }
493 [ - + - - ]: 5 : if (fold != 0 && fold != 1) {
494 : 0 : PyErr_SetString(PyExc_ValueError,
495 : : "fold must be either 0 or 1");
496 : 0 : return -1;
497 : : }
498 : 5 : return 0;
499 : : }
500 : :
501 : : /* ---------------------------------------------------------------------------
502 : : * Normalization utilities.
503 : : */
504 : :
505 : : /* One step of a mixed-radix conversion. A "hi" unit is equivalent to
506 : : * factor "lo" units. factor must be > 0. If *lo is less than 0, or
507 : : * at least factor, enough of *lo is converted into "hi" units so that
508 : : * 0 <= *lo < factor. The input values must be such that int overflow
509 : : * is impossible.
510 : : */
511 : : static void
512 : 0 : normalize_pair(int *hi, int *lo, int factor)
513 : : {
514 : : assert(factor > 0);
515 : : assert(lo != hi);
516 [ # # # # ]: 0 : if (*lo < 0 || *lo >= factor) {
517 : 0 : const int num_hi = divmod(*lo, factor, lo);
518 : 0 : const int new_hi = *hi + num_hi;
519 : : assert(! SIGNED_ADD_OVERFLOWED(new_hi, *hi, num_hi));
520 : 0 : *hi = new_hi;
521 : : }
522 : : assert(0 <= *lo && *lo < factor);
523 : 0 : }
524 : :
525 : : /* Fiddle days (d), seconds (s), and microseconds (us) so that
526 : : * 0 <= *s < 24*3600
527 : : * 0 <= *us < 1000000
528 : : * The input values must be such that the internals don't overflow.
529 : : * The way this routine is used, we don't get close.
530 : : */
531 : : static void
532 : 1 : normalize_d_s_us(int *d, int *s, int *us)
533 : : {
534 [ + - - + ]: 1 : if (*us < 0 || *us >= 1000000) {
535 : 0 : normalize_pair(s, us, 1000000);
536 : : /* |s| can't be bigger than about
537 : : * |original s| + |original us|/1000000 now.
538 : : */
539 : :
540 : : }
541 [ + - - + ]: 1 : if (*s < 0 || *s >= 24*3600) {
542 : 0 : normalize_pair(d, s, 24*3600);
543 : : /* |d| can't be bigger than about
544 : : * |original d| +
545 : : * (|original s| + |original us|/1000000) / (24*3600) now.
546 : : */
547 : : }
548 : : assert(0 <= *s && *s < 24*3600);
549 : : assert(0 <= *us && *us < 1000000);
550 : 1 : }
551 : :
552 : : /* Fiddle years (y), months (m), and days (d) so that
553 : : * 1 <= *m <= 12
554 : : * 1 <= *d <= days_in_month(*y, *m)
555 : : * The input values must be such that the internals don't overflow.
556 : : * The way this routine is used, we don't get close.
557 : : */
558 : : static int
559 : 0 : normalize_y_m_d(int *y, int *m, int *d)
560 : : {
561 : : int dim; /* # of days in month */
562 : :
563 : : /* In actual use, m is always the month component extracted from a
564 : : * date/datetime object. Therefore it is always in [1, 12] range.
565 : : */
566 : :
567 : : assert(1 <= *m && *m <= 12);
568 : :
569 : : /* Now only day can be out of bounds (year may also be out of bounds
570 : : * for a datetime object, but we don't care about that here).
571 : : * If day is out of bounds, what to do is arguable, but at least the
572 : : * method here is principled and explainable.
573 : : */
574 : 0 : dim = days_in_month(*y, *m);
575 [ # # # # ]: 0 : if (*d < 1 || *d > dim) {
576 : : /* Move day-1 days from the first of the month. First try to
577 : : * get off cheap if we're only one day out of range
578 : : * (adjustments for timezone alone can't be worse than that).
579 : : */
580 [ # # ]: 0 : if (*d == 0) {
581 : 0 : --*m;
582 [ # # ]: 0 : if (*m > 0)
583 : 0 : *d = days_in_month(*y, *m);
584 : : else {
585 : 0 : --*y;
586 : 0 : *m = 12;
587 : 0 : *d = 31;
588 : : }
589 : : }
590 [ # # ]: 0 : else if (*d == dim + 1) {
591 : : /* move forward a day */
592 : 0 : ++*m;
593 : 0 : *d = 1;
594 [ # # ]: 0 : if (*m > 12) {
595 : 0 : *m = 1;
596 : 0 : ++*y;
597 : : }
598 : : }
599 : : else {
600 : 0 : int ordinal = ymd_to_ord(*y, *m, 1) +
601 : 0 : *d - 1;
602 [ # # # # ]: 0 : if (ordinal < 1 || ordinal > MAXORDINAL) {
603 : 0 : goto error;
604 : : } else {
605 : 0 : ord_to_ymd(ordinal, y, m, d);
606 : 0 : return 0;
607 : : }
608 : : }
609 : : }
610 : : assert(*m > 0);
611 : : assert(*d > 0);
612 [ # # # # ]: 0 : if (MINYEAR <= *y && *y <= MAXYEAR)
613 : 0 : return 0;
614 : 0 : error:
615 : 0 : PyErr_SetString(PyExc_OverflowError,
616 : : "date value out of range");
617 : 0 : return -1;
618 : :
619 : : }
620 : :
621 : : /* Fiddle out-of-bounds months and days so that the result makes some kind
622 : : * of sense. The parameters are both inputs and outputs. Returns < 0 on
623 : : * failure, where failure means the adjusted year is out of bounds.
624 : : */
625 : : static int
626 : 0 : normalize_date(int *year, int *month, int *day)
627 : : {
628 : 0 : return normalize_y_m_d(year, month, day);
629 : : }
630 : :
631 : : /* Force all the datetime fields into range. The parameters are both
632 : : * inputs and outputs. Returns < 0 on error.
633 : : */
634 : : static int
635 : 0 : normalize_datetime(int *year, int *month, int *day,
636 : : int *hour, int *minute, int *second,
637 : : int *microsecond)
638 : : {
639 : 0 : normalize_pair(second, microsecond, 1000000);
640 : 0 : normalize_pair(minute, second, 60);
641 : 0 : normalize_pair(hour, minute, 60);
642 : 0 : normalize_pair(day, hour, 24);
643 : 0 : return normalize_date(year, month, day);
644 : : }
645 : :
646 : : /* ---------------------------------------------------------------------------
647 : : * Basic object allocation: tp_alloc implementations. These allocate
648 : : * Python objects of the right size and type, and do the Python object-
649 : : * initialization bit. If there's not enough memory, they return NULL after
650 : : * setting MemoryError. All data members remain uninitialized trash.
651 : : *
652 : : * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo
653 : : * member is needed. This is ugly, imprecise, and possibly insecure.
654 : : * tp_basicsize for the time and datetime types is set to the size of the
655 : : * struct that has room for the tzinfo member, so subclasses in Python will
656 : : * allocate enough space for a tzinfo member whether or not one is actually
657 : : * needed. That's the "ugly and imprecise" parts. The "possibly insecure"
658 : : * part is that PyType_GenericAlloc() (which subclasses in Python end up
659 : : * using) just happens today to effectively ignore the nitems argument
660 : : * when tp_itemsize is 0, which it is for these type objects. If that
661 : : * changes, perhaps the callers of tp_alloc slots in this file should
662 : : * be changed to force a 0 nitems argument unless the type being allocated
663 : : * is a base type implemented in this file (so that tp_alloc is time_alloc
664 : : * or datetime_alloc below, which know about the nitems abuse).
665 : : */
666 : :
667 : : static PyObject *
668 : 2 : time_alloc(PyTypeObject *type, Py_ssize_t aware)
669 : : {
670 [ - + ]: 2 : size_t size = aware ? sizeof(PyDateTime_Time) : sizeof(_PyDateTime_BaseTime);
671 : 2 : PyObject *self = (PyObject *)PyObject_Malloc(size);
672 [ - + ]: 2 : if (self == NULL) {
673 : 0 : return PyErr_NoMemory();
674 : : }
675 : 2 : _PyObject_Init(self, type);
676 : 2 : return self;
677 : : }
678 : :
679 : : static PyObject *
680 : 3 : datetime_alloc(PyTypeObject *type, Py_ssize_t aware)
681 : : {
682 [ + + ]: 3 : size_t size = aware ? sizeof(PyDateTime_DateTime) : sizeof(_PyDateTime_BaseDateTime);
683 : 3 : PyObject *self = (PyObject *)PyObject_Malloc(size);
684 [ - + ]: 3 : if (self == NULL) {
685 : 0 : return PyErr_NoMemory();
686 : : }
687 : 3 : _PyObject_Init(self, type);
688 : 3 : return self;
689 : : }
690 : :
691 : : /* ---------------------------------------------------------------------------
692 : : * Helpers for setting object fields. These work on pointers to the
693 : : * appropriate base class.
694 : : */
695 : :
696 : : /* For date and datetime. */
697 : : static void
698 : 5 : set_date_fields(PyDateTime_Date *self, int y, int m, int d)
699 : : {
700 : 5 : self->hashcode = -1;
701 : 5 : SET_YEAR(self, y);
702 : 5 : SET_MONTH(self, m);
703 : 5 : SET_DAY(self, d);
704 : 5 : }
705 : :
706 : : /* ---------------------------------------------------------------------------
707 : : * String parsing utilities and helper functions
708 : : */
709 : :
710 : : static unsigned char
711 : 0 : is_digit(const char c) {
712 : 0 : return ((unsigned int)(c - '0')) < 10;
713 : : }
714 : :
715 : : static const char *
716 : 0 : parse_digits(const char *ptr, int *var, size_t num_digits)
717 : : {
718 [ # # ]: 0 : for (size_t i = 0; i < num_digits; ++i) {
719 : 0 : unsigned int tmp = (unsigned int)(*(ptr++) - '0');
720 [ # # ]: 0 : if (tmp > 9) {
721 : 0 : return NULL;
722 : : }
723 : 0 : *var *= 10;
724 : 0 : *var += (signed int)tmp;
725 : : }
726 : :
727 : 0 : return ptr;
728 : : }
729 : :
730 : : static int
731 : 0 : parse_isoformat_date(const char *dtstr, const size_t len, int *year, int *month, int *day)
732 : : {
733 : : /* Parse the date components of the result of date.isoformat()
734 : : *
735 : : * Return codes:
736 : : * 0: Success
737 : : * -1: Failed to parse date component
738 : : * -2: Inconsistent date separator usage
739 : : * -3: Failed to parse ISO week.
740 : : * -4: Failed to parse ISO day.
741 : : * -5, -6: Failure in iso_to_ymd
742 : : */
743 : 0 : const char *p = dtstr;
744 : 0 : p = parse_digits(p, year, 4);
745 [ # # ]: 0 : if (NULL == p) {
746 : 0 : return -1;
747 : : }
748 : :
749 : 0 : const unsigned char uses_separator = (*p == '-');
750 [ # # ]: 0 : if (uses_separator) {
751 : 0 : ++p;
752 : : }
753 : :
754 [ # # ]: 0 : if(*p == 'W') {
755 : : // This is an isocalendar-style date string
756 : 0 : p++;
757 : 0 : int iso_week = 0;
758 : 0 : int iso_day = 0;
759 : :
760 : 0 : p = parse_digits(p, &iso_week, 2);
761 [ # # ]: 0 : if (NULL == p) {
762 : 0 : return -3;
763 : : }
764 : :
765 : : assert(p > dtstr);
766 [ # # ]: 0 : if ((size_t)(p - dtstr) < len) {
767 [ # # # # ]: 0 : if (uses_separator && *(p++) != '-') {
768 : 0 : return -2;
769 : : }
770 : :
771 : 0 : p = parse_digits(p, &iso_day, 1);
772 [ # # ]: 0 : if (NULL == p) {
773 : 0 : return -4;
774 : : }
775 : : } else {
776 : 0 : iso_day = 1;
777 : : }
778 : :
779 : 0 : int rv = iso_to_ymd(*year, iso_week, iso_day, year, month, day);
780 [ # # ]: 0 : if (rv) {
781 : 0 : return -3 + rv;
782 : : } else {
783 : 0 : return 0;
784 : : }
785 : : }
786 : :
787 : 0 : p = parse_digits(p, month, 2);
788 [ # # ]: 0 : if (NULL == p) {
789 : 0 : return -1;
790 : : }
791 : :
792 [ # # # # ]: 0 : if (uses_separator && *(p++) != '-') {
793 : 0 : return -2;
794 : : }
795 : 0 : p = parse_digits(p, day, 2);
796 [ # # ]: 0 : if (p == NULL) {
797 : 0 : return -1;
798 : : }
799 : 0 : return 0;
800 : : }
801 : :
802 : : static int
803 : 0 : parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
804 : : int *minute, int *second, int *microsecond)
805 : : {
806 : 0 : *hour = *minute = *second = *microsecond = 0;
807 : 0 : const char *p = tstr;
808 : 0 : const char *p_end = tstr_end;
809 : 0 : int *vals[3] = {hour, minute, second};
810 : : // This is initialized to satisfy an erroneous compiler warning.
811 : 0 : unsigned char has_separator = 1;
812 : :
813 : : // Parse [HH[:?MM[:?SS]]]
814 [ # # ]: 0 : for (size_t i = 0; i < 3; ++i) {
815 : 0 : p = parse_digits(p, vals[i], 2);
816 [ # # ]: 0 : if (NULL == p) {
817 : 0 : return -3;
818 : : }
819 : :
820 : 0 : char c = *(p++);
821 [ # # ]: 0 : if (i == 0) {
822 : 0 : has_separator = (c == ':');
823 : : }
824 : :
825 [ # # ]: 0 : if (p >= p_end) {
826 : 0 : return c != '\0';
827 : : }
828 [ # # # # ]: 0 : else if (has_separator && (c == ':')) {
829 : 0 : continue;
830 : : }
831 [ # # # # ]: 0 : else if (c == '.' || c == ',') {
832 : : break;
833 [ # # ]: 0 : } else if (!has_separator) {
834 : 0 : --p;
835 : : } else {
836 : 0 : return -4; // Malformed time separator
837 : : }
838 : : }
839 : :
840 : : // Parse fractional components
841 : 0 : size_t len_remains = p_end - p;
842 : 0 : size_t to_parse = len_remains;
843 [ # # ]: 0 : if (len_remains >= 6) {
844 : 0 : to_parse = 6;
845 : : }
846 : :
847 : 0 : p = parse_digits(p, microsecond, to_parse);
848 [ # # ]: 0 : if (NULL == p) {
849 : 0 : return -3;
850 : : }
851 : :
852 : : static int correction[] = {
853 : : 100000, 10000, 1000, 100, 10
854 : : };
855 : :
856 [ # # ]: 0 : if (to_parse < 6) {
857 : 0 : *microsecond *= correction[to_parse-1];
858 : : }
859 : :
860 [ # # ]: 0 : while (is_digit(*p)){
861 : 0 : ++p; // skip truncated digits
862 : : }
863 : :
864 : : // Return 1 if it's not the end of the string
865 : 0 : return *p != '\0';
866 : : }
867 : :
868 : : static int
869 : 0 : parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
870 : : int *second, int *microsecond, int *tzoffset,
871 : : int *tzmicrosecond)
872 : : {
873 : : // Parse the time portion of a datetime.isoformat() string
874 : : //
875 : : // Return codes:
876 : : // 0: Success (no tzoffset)
877 : : // 1: Success (with tzoffset)
878 : : // -3: Failed to parse time component
879 : : // -4: Failed to parse time separator
880 : : // -5: Malformed timezone string
881 : :
882 : 0 : const char *p = dtstr;
883 : 0 : const char *p_end = dtstr + dtlen;
884 : :
885 : 0 : const char *tzinfo_pos = p;
886 : : do {
887 [ # # # # : 0 : if (*tzinfo_pos == 'Z' || *tzinfo_pos == '+' || *tzinfo_pos == '-') {
# # ]
888 : : break;
889 : : }
890 [ # # ]: 0 : } while (++tzinfo_pos < p_end);
891 : :
892 : 0 : int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos, hour, minute, second,
893 : : microsecond);
894 : :
895 [ # # ]: 0 : if (rv < 0) {
896 : 0 : return rv;
897 : : }
898 [ # # ]: 0 : else if (tzinfo_pos == p_end) {
899 : : // We know that there's no time zone, so if there's stuff at the
900 : : // end of the string it's an error.
901 [ # # ]: 0 : if (rv == 1) {
902 : 0 : return -5;
903 : : }
904 : : else {
905 : 0 : return 0;
906 : : }
907 : : }
908 : :
909 : : // Special case UTC / Zulu time.
910 [ # # ]: 0 : if (*tzinfo_pos == 'Z') {
911 : 0 : *tzoffset = 0;
912 : 0 : *tzmicrosecond = 0;
913 : :
914 [ # # ]: 0 : if (*(tzinfo_pos + 1) != '\0') {
915 : 0 : return -5;
916 : : } else {
917 : 0 : return 1;
918 : : }
919 : : }
920 : :
921 [ # # ]: 0 : int tzsign = (*tzinfo_pos == '-') ? -1 : 1;
922 : 0 : tzinfo_pos++;
923 : 0 : int tzhour = 0, tzminute = 0, tzsecond = 0;
924 : 0 : rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
925 : : tzmicrosecond);
926 : :
927 : 0 : *tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
928 : 0 : *tzmicrosecond *= tzsign;
929 : :
930 [ # # ]: 0 : return rv ? -5 : 1;
931 : : }
932 : :
933 : : /* ---------------------------------------------------------------------------
934 : : * Create various objects, mostly without range checking.
935 : : */
936 : :
937 : : /* Create a date instance with no range checking. */
938 : : static PyObject *
939 : 2 : new_date_ex(int year, int month, int day, PyTypeObject *type)
940 : : {
941 : : PyDateTime_Date *self;
942 : :
943 [ - + ]: 2 : if (check_date_args(year, month, day) < 0) {
944 : 0 : return NULL;
945 : : }
946 : :
947 : 2 : self = (PyDateTime_Date *)(type->tp_alloc(type, 0));
948 [ + - ]: 2 : if (self != NULL)
949 : 2 : set_date_fields(self, year, month, day);
950 : 2 : return (PyObject *)self;
951 : : }
952 : :
953 : : #define new_date(year, month, day) \
954 : : new_date_ex(year, month, day, &PyDateTime_DateType)
955 : :
956 : : // Forward declaration
957 : : static PyObject *
958 : : new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *);
959 : :
960 : : /* Create date instance with no range checking, or call subclass constructor */
961 : : static PyObject *
962 : 0 : new_date_subclass_ex(int year, int month, int day, PyObject *cls)
963 : : {
964 : : PyObject *result;
965 : : // We have "fast path" constructors for two subclasses: date and datetime
966 [ # # ]: 0 : if ((PyTypeObject *)cls == &PyDateTime_DateType) {
967 : 0 : result = new_date_ex(year, month, day, (PyTypeObject *)cls);
968 : : }
969 [ # # ]: 0 : else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
970 : 0 : result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
971 : : (PyTypeObject *)cls);
972 : : }
973 : : else {
974 : 0 : result = PyObject_CallFunction(cls, "iii", year, month, day);
975 : : }
976 : :
977 : 0 : return result;
978 : : }
979 : :
980 : : /* Create a datetime instance with no range checking. */
981 : : static PyObject *
982 : 3 : new_datetime_ex2(int year, int month, int day, int hour, int minute,
983 : : int second, int usecond, PyObject *tzinfo, int fold, PyTypeObject *type)
984 : : {
985 : : PyDateTime_DateTime *self;
986 : 3 : char aware = tzinfo != Py_None;
987 : :
988 [ - + ]: 3 : if (check_date_args(year, month, day) < 0) {
989 : 0 : return NULL;
990 : : }
991 [ - + ]: 3 : if (check_time_args(hour, minute, second, usecond, fold) < 0) {
992 : 0 : return NULL;
993 : : }
994 [ - + ]: 3 : if (check_tzinfo_subclass(tzinfo) < 0) {
995 : 0 : return NULL;
996 : : }
997 : :
998 : 3 : self = (PyDateTime_DateTime *) (type->tp_alloc(type, aware));
999 [ + - ]: 3 : if (self != NULL) {
1000 : 3 : self->hastzinfo = aware;
1001 : 3 : set_date_fields((PyDateTime_Date *)self, year, month, day);
1002 : 3 : DATE_SET_HOUR(self, hour);
1003 : 3 : DATE_SET_MINUTE(self, minute);
1004 : 3 : DATE_SET_SECOND(self, second);
1005 : 3 : DATE_SET_MICROSECOND(self, usecond);
1006 [ + + ]: 3 : if (aware) {
1007 : 1 : self->tzinfo = Py_NewRef(tzinfo);
1008 : : }
1009 : 3 : DATE_SET_FOLD(self, fold);
1010 : : }
1011 : 3 : return (PyObject *)self;
1012 : : }
1013 : :
1014 : : static PyObject *
1015 : 0 : new_datetime_ex(int year, int month, int day, int hour, int minute,
1016 : : int second, int usecond, PyObject *tzinfo, PyTypeObject *type)
1017 : : {
1018 : 0 : return new_datetime_ex2(year, month, day, hour, minute, second, usecond,
1019 : : tzinfo, 0, type);
1020 : : }
1021 : :
1022 : : #define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \
1023 : : new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \
1024 : : &PyDateTime_DateTimeType)
1025 : :
1026 : : static PyObject *
1027 : 0 : new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute,
1028 : : int second, int usecond, PyObject *tzinfo,
1029 : : int fold, PyObject *cls) {
1030 : : PyObject* dt;
1031 [ # # ]: 0 : if ((PyTypeObject*)cls == &PyDateTime_DateTimeType) {
1032 : : // Use the fast path constructor
1033 : 0 : dt = new_datetime(year, month, day, hour, minute, second, usecond,
1034 : : tzinfo, fold);
1035 : : } else {
1036 : : // Subclass
1037 : 0 : dt = PyObject_CallFunction(cls, "iiiiiiiO",
1038 : : year,
1039 : : month,
1040 : : day,
1041 : : hour,
1042 : : minute,
1043 : : second,
1044 : : usecond,
1045 : : tzinfo);
1046 : : }
1047 : :
1048 : 0 : return dt;
1049 : : }
1050 : :
1051 : : static PyObject *
1052 : 0 : new_datetime_subclass_ex(int year, int month, int day, int hour, int minute,
1053 : : int second, int usecond, PyObject *tzinfo,
1054 : : PyObject *cls) {
1055 : 0 : return new_datetime_subclass_fold_ex(year, month, day, hour, minute,
1056 : : second, usecond, tzinfo, 0,
1057 : : cls);
1058 : : }
1059 : :
1060 : : /* Create a time instance with no range checking. */
1061 : : static PyObject *
1062 : 2 : new_time_ex2(int hour, int minute, int second, int usecond,
1063 : : PyObject *tzinfo, int fold, PyTypeObject *type)
1064 : : {
1065 : : PyDateTime_Time *self;
1066 : 2 : char aware = tzinfo != Py_None;
1067 : :
1068 [ - + ]: 2 : if (check_time_args(hour, minute, second, usecond, fold) < 0) {
1069 : 0 : return NULL;
1070 : : }
1071 [ - + ]: 2 : if (check_tzinfo_subclass(tzinfo) < 0) {
1072 : 0 : return NULL;
1073 : : }
1074 : :
1075 : 2 : self = (PyDateTime_Time *) (type->tp_alloc(type, aware));
1076 [ + - ]: 2 : if (self != NULL) {
1077 : 2 : self->hastzinfo = aware;
1078 : 2 : self->hashcode = -1;
1079 : 2 : TIME_SET_HOUR(self, hour);
1080 : 2 : TIME_SET_MINUTE(self, minute);
1081 : 2 : TIME_SET_SECOND(self, second);
1082 : 2 : TIME_SET_MICROSECOND(self, usecond);
1083 [ - + ]: 2 : if (aware) {
1084 : 0 : self->tzinfo = Py_NewRef(tzinfo);
1085 : : }
1086 : 2 : TIME_SET_FOLD(self, fold);
1087 : : }
1088 : 2 : return (PyObject *)self;
1089 : : }
1090 : :
1091 : : static PyObject *
1092 : 0 : new_time_ex(int hour, int minute, int second, int usecond,
1093 : : PyObject *tzinfo, PyTypeObject *type)
1094 : : {
1095 : 0 : return new_time_ex2(hour, minute, second, usecond, tzinfo, 0, type);
1096 : : }
1097 : :
1098 : : #define new_time(hh, mm, ss, us, tzinfo, fold) \
1099 : : new_time_ex2(hh, mm, ss, us, tzinfo, fold, &PyDateTime_TimeType)
1100 : :
1101 : : /* Create a timedelta instance. Normalize the members iff normalize is
1102 : : * true. Passing false is a speed optimization, if you know for sure
1103 : : * that seconds and microseconds are already in their proper ranges. In any
1104 : : * case, raises OverflowError and returns NULL if the normalized days is out
1105 : : * of range.
1106 : : */
1107 : : static PyObject *
1108 : 9 : new_delta_ex(int days, int seconds, int microseconds, int normalize,
1109 : : PyTypeObject *type)
1110 : : {
1111 : : PyDateTime_Delta *self;
1112 : :
1113 [ + + ]: 9 : if (normalize)
1114 : 1 : normalize_d_s_us(&days, &seconds, µseconds);
1115 : : assert(0 <= seconds && seconds < 24*3600);
1116 : : assert(0 <= microseconds && microseconds < 1000000);
1117 : :
1118 [ - + ]: 9 : if (check_delta_day_range(days) < 0)
1119 : 0 : return NULL;
1120 : :
1121 : 9 : self = (PyDateTime_Delta *) (type->tp_alloc(type, 0));
1122 [ + - ]: 9 : if (self != NULL) {
1123 : 9 : self->hashcode = -1;
1124 : 9 : SET_TD_DAYS(self, days);
1125 : 9 : SET_TD_SECONDS(self, seconds);
1126 : 9 : SET_TD_MICROSECONDS(self, microseconds);
1127 : : }
1128 : 9 : return (PyObject *) self;
1129 : : }
1130 : :
1131 : : #define new_delta(d, s, us, normalize) \
1132 : : new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)
1133 : :
1134 : :
1135 : : typedef struct
1136 : : {
1137 : : PyObject_HEAD
1138 : : PyObject *offset;
1139 : : PyObject *name;
1140 : : } PyDateTime_TimeZone;
1141 : :
1142 : : /* The interned UTC timezone instance */
1143 : : static PyObject *PyDateTime_TimeZone_UTC;
1144 : : /* The interned Epoch datetime instance */
1145 : : static PyObject *PyDateTime_Epoch;
1146 : :
1147 : : /* Create new timezone instance checking offset range. This
1148 : : function does not check the name argument. Caller must assure
1149 : : that offset is a timedelta instance and name is either NULL
1150 : : or a unicode object. */
1151 : : static PyObject *
1152 : 3 : create_timezone(PyObject *offset, PyObject *name)
1153 : : {
1154 : : PyDateTime_TimeZone *self;
1155 : 3 : PyTypeObject *type = &PyDateTime_TimeZoneType;
1156 : :
1157 : : assert(offset != NULL);
1158 : : assert(PyDelta_Check(offset));
1159 : : assert(name == NULL || PyUnicode_Check(name));
1160 : :
1161 : 3 : self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0));
1162 [ - + ]: 3 : if (self == NULL) {
1163 : 0 : return NULL;
1164 : : }
1165 : 3 : self->offset = Py_NewRef(offset);
1166 : 3 : self->name = Py_XNewRef(name);
1167 : 3 : return (PyObject *)self;
1168 : : }
1169 : :
1170 : : static int delta_bool(PyDateTime_Delta *self);
1171 : :
1172 : : static PyObject *
1173 : 0 : new_timezone(PyObject *offset, PyObject *name)
1174 : : {
1175 : : assert(offset != NULL);
1176 : : assert(PyDelta_Check(offset));
1177 : : assert(name == NULL || PyUnicode_Check(name));
1178 : :
1179 [ # # # # ]: 0 : if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
1180 : 0 : return Py_NewRef(PyDateTime_TimeZone_UTC);
1181 : : }
1182 [ # # ]: 0 : if ((GET_TD_DAYS(offset) == -1 &&
1183 [ # # ]: 0 : GET_TD_SECONDS(offset) == 0 &&
1184 [ # # ]: 0 : GET_TD_MICROSECONDS(offset) < 1) ||
1185 [ # # # # ]: 0 : GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
1186 : 0 : PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
1187 : : " strictly between -timedelta(hours=24) and"
1188 : : " timedelta(hours=24),"
1189 : : " not %R.", offset);
1190 : 0 : return NULL;
1191 : : }
1192 : :
1193 : 0 : return create_timezone(offset, name);
1194 : : }
1195 : :
1196 : : /* ---------------------------------------------------------------------------
1197 : : * tzinfo helpers.
1198 : : */
1199 : :
1200 : : /* Ensure that p is None or of a tzinfo subclass. Return 0 if OK; if not
1201 : : * raise TypeError and return -1.
1202 : : */
1203 : : static int
1204 : 5 : check_tzinfo_subclass(PyObject *p)
1205 : : {
1206 [ + + + - ]: 5 : if (p == Py_None || PyTZInfo_Check(p))
1207 : 5 : return 0;
1208 : 0 : PyErr_Format(PyExc_TypeError,
1209 : : "tzinfo argument must be None or of a tzinfo subclass, "
1210 : : "not type '%s'",
1211 : 0 : Py_TYPE(p)->tp_name);
1212 : 0 : return -1;
1213 : : }
1214 : :
1215 : : /* If self has a tzinfo member, return a BORROWED reference to it. Else
1216 : : * return NULL, which is NOT AN ERROR. There are no error returns here,
1217 : : * and the caller must not decref the result.
1218 : : */
1219 : : static PyObject *
1220 : 0 : get_tzinfo_member(PyObject *self)
1221 : : {
1222 : 0 : PyObject *tzinfo = NULL;
1223 : :
1224 [ # # # # ]: 0 : if (PyDateTime_Check(self) && HASTZINFO(self))
1225 : 0 : tzinfo = ((PyDateTime_DateTime *)self)->tzinfo;
1226 [ # # # # ]: 0 : else if (PyTime_Check(self) && HASTZINFO(self))
1227 : 0 : tzinfo = ((PyDateTime_Time *)self)->tzinfo;
1228 : :
1229 : 0 : return tzinfo;
1230 : : }
1231 : :
1232 : : /* Call getattr(tzinfo, name)(tzinfoarg), and check the result. tzinfo must
1233 : : * be an instance of the tzinfo class. If the method returns None, this
1234 : : * returns None. If the method doesn't return None or timedelta, TypeError is
1235 : : * raised and this returns NULL. If it returns a timedelta and the value is
1236 : : * out of range or isn't a whole number of minutes, ValueError is raised and
1237 : : * this returns NULL. Else result is returned.
1238 : : */
1239 : : static PyObject *
1240 : 0 : call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg)
1241 : : {
1242 : : PyObject *offset;
1243 : :
1244 : : assert(tzinfo != NULL);
1245 : : assert(PyTZInfo_Check(tzinfo) || tzinfo == Py_None);
1246 : : assert(tzinfoarg != NULL);
1247 : :
1248 [ # # ]: 0 : if (tzinfo == Py_None)
1249 : 0 : Py_RETURN_NONE;
1250 : 0 : offset = PyObject_CallMethod(tzinfo, name, "O", tzinfoarg);
1251 [ # # # # ]: 0 : if (offset == Py_None || offset == NULL)
1252 : 0 : return offset;
1253 [ # # ]: 0 : if (PyDelta_Check(offset)) {
1254 [ # # ]: 0 : if ((GET_TD_DAYS(offset) == -1 &&
1255 [ # # ]: 0 : GET_TD_SECONDS(offset) == 0 &&
1256 [ # # ]: 0 : GET_TD_MICROSECONDS(offset) < 1) ||
1257 [ # # # # ]: 0 : GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
1258 : 0 : Py_DECREF(offset);
1259 : 0 : PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
1260 : : " strictly between -timedelta(hours=24) and"
1261 : : " timedelta(hours=24).");
1262 : 0 : return NULL;
1263 : : }
1264 : : }
1265 : : else {
1266 : 0 : PyErr_Format(PyExc_TypeError,
1267 : : "tzinfo.%s() must return None or "
1268 : : "timedelta, not '%.200s'",
1269 : 0 : name, Py_TYPE(offset)->tp_name);
1270 : 0 : Py_DECREF(offset);
1271 : 0 : return NULL;
1272 : : }
1273 : :
1274 : 0 : return offset;
1275 : : }
1276 : :
1277 : : /* Call tzinfo.utcoffset(tzinfoarg), and extract an integer from the
1278 : : * result. tzinfo must be an instance of the tzinfo class. If utcoffset()
1279 : : * returns None, call_utcoffset returns 0 and sets *none to 1. If uctoffset()
1280 : : * doesn't return None or timedelta, TypeError is raised and this returns -1.
1281 : : * If utcoffset() returns an out of range timedelta,
1282 : : * ValueError is raised and this returns -1. Else *none is
1283 : : * set to 0 and the offset is returned (as timedelta, positive east of UTC).
1284 : : */
1285 : : static PyObject *
1286 : 0 : call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg)
1287 : : {
1288 : 0 : return call_tzinfo_method(tzinfo, "utcoffset", tzinfoarg);
1289 : : }
1290 : :
1291 : : /* Call tzinfo.dst(tzinfoarg), and extract an integer from the
1292 : : * result. tzinfo must be an instance of the tzinfo class. If dst()
1293 : : * returns None, call_dst returns 0 and sets *none to 1. If dst()
1294 : : * doesn't return None or timedelta, TypeError is raised and this
1295 : : * returns -1. If dst() returns an invalid timedelta for a UTC offset,
1296 : : * ValueError is raised and this returns -1. Else *none is set to 0 and
1297 : : * the offset is returned (as timedelta, positive east of UTC).
1298 : : */
1299 : : static PyObject *
1300 : 0 : call_dst(PyObject *tzinfo, PyObject *tzinfoarg)
1301 : : {
1302 : 0 : return call_tzinfo_method(tzinfo, "dst", tzinfoarg);
1303 : : }
1304 : :
1305 : : /* Call tzinfo.tzname(tzinfoarg), and return the result. tzinfo must be
1306 : : * an instance of the tzinfo class or None. If tzinfo isn't None, and
1307 : : * tzname() doesn't return None or a string, TypeError is raised and this
1308 : : * returns NULL. If the result is a string, we ensure it is a Unicode
1309 : : * string.
1310 : : */
1311 : : static PyObject *
1312 : 0 : call_tzname(PyObject *tzinfo, PyObject *tzinfoarg)
1313 : : {
1314 : : PyObject *result;
1315 : : assert(tzinfo != NULL);
1316 : : assert(check_tzinfo_subclass(tzinfo) >= 0);
1317 : : assert(tzinfoarg != NULL);
1318 : :
1319 [ # # ]: 0 : if (tzinfo == Py_None)
1320 : 0 : Py_RETURN_NONE;
1321 : :
1322 : 0 : result = PyObject_CallMethodOneArg(tzinfo, &_Py_ID(tzname), tzinfoarg);
1323 : :
1324 [ # # # # ]: 0 : if (result == NULL || result == Py_None)
1325 : 0 : return result;
1326 : :
1327 [ # # ]: 0 : if (!PyUnicode_Check(result)) {
1328 : 0 : PyErr_Format(PyExc_TypeError, "tzinfo.tzname() must "
1329 : : "return None or a string, not '%s'",
1330 : 0 : Py_TYPE(result)->tp_name);
1331 : 0 : Py_SETREF(result, NULL);
1332 : : }
1333 : :
1334 : 0 : return result;
1335 : : }
1336 : :
1337 : : /* repr is like "someclass(arg1, arg2)". If tzinfo isn't None,
1338 : : * stuff
1339 : : * ", tzinfo=" + repr(tzinfo)
1340 : : * before the closing ")".
1341 : : */
1342 : : static PyObject *
1343 : 0 : append_keyword_tzinfo(PyObject *repr, PyObject *tzinfo)
1344 : : {
1345 : : PyObject *temp;
1346 : :
1347 : : assert(PyUnicode_Check(repr));
1348 : : assert(tzinfo);
1349 [ # # ]: 0 : if (tzinfo == Py_None)
1350 : 0 : return repr;
1351 : : /* Get rid of the trailing ')'. */
1352 : : assert(PyUnicode_READ_CHAR(repr, PyUnicode_GET_LENGTH(repr)-1) == ')');
1353 : 0 : temp = PyUnicode_Substring(repr, 0, PyUnicode_GET_LENGTH(repr) - 1);
1354 : 0 : Py_DECREF(repr);
1355 [ # # ]: 0 : if (temp == NULL)
1356 : 0 : return NULL;
1357 : 0 : repr = PyUnicode_FromFormat("%U, tzinfo=%R)", temp, tzinfo);
1358 : 0 : Py_DECREF(temp);
1359 : 0 : return repr;
1360 : : }
1361 : :
1362 : : /* repr is like "someclass(arg1, arg2)". If fold isn't 0,
1363 : : * stuff
1364 : : * ", fold=" + repr(tzinfo)
1365 : : * before the closing ")".
1366 : : */
1367 : : static PyObject *
1368 : 0 : append_keyword_fold(PyObject *repr, int fold)
1369 : : {
1370 : : PyObject *temp;
1371 : :
1372 : : assert(PyUnicode_Check(repr));
1373 [ # # ]: 0 : if (fold == 0)
1374 : 0 : return repr;
1375 : : /* Get rid of the trailing ')'. */
1376 : : assert(PyUnicode_READ_CHAR(repr, PyUnicode_GET_LENGTH(repr)-1) == ')');
1377 : 0 : temp = PyUnicode_Substring(repr, 0, PyUnicode_GET_LENGTH(repr) - 1);
1378 : 0 : Py_DECREF(repr);
1379 [ # # ]: 0 : if (temp == NULL)
1380 : 0 : return NULL;
1381 : 0 : repr = PyUnicode_FromFormat("%U, fold=%d)", temp, fold);
1382 : 0 : Py_DECREF(temp);
1383 : 0 : return repr;
1384 : : }
1385 : :
1386 : : static inline PyObject *
1387 : 0 : tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
1388 : : {
1389 : : PyObject *tzinfo;
1390 [ # # ]: 0 : if (rv == 1) {
1391 : : // Create a timezone from offset in seconds (0 returns UTC)
1392 [ # # ]: 0 : if (tzoffset == 0) {
1393 : 0 : return Py_NewRef(PyDateTime_TimeZone_UTC);
1394 : : }
1395 : :
1396 : 0 : PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
1397 [ # # ]: 0 : if (delta == NULL) {
1398 : 0 : return NULL;
1399 : : }
1400 : 0 : tzinfo = new_timezone(delta, NULL);
1401 : 0 : Py_DECREF(delta);
1402 : : }
1403 : : else {
1404 : 0 : tzinfo = Py_NewRef(Py_None);
1405 : : }
1406 : :
1407 : 0 : return tzinfo;
1408 : : }
1409 : :
1410 : : /* ---------------------------------------------------------------------------
1411 : : * String format helpers.
1412 : : */
1413 : :
1414 : : static PyObject *
1415 : 0 : format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds)
1416 : : {
1417 : : static const char * const DayNames[] = {
1418 : : "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
1419 : : };
1420 : : static const char * const MonthNames[] = {
1421 : : "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1422 : : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1423 : : };
1424 : :
1425 : 0 : int wday = weekday(GET_YEAR(date), GET_MONTH(date), GET_DAY(date));
1426 : :
1427 : 0 : return PyUnicode_FromFormat("%s %s %2d %02d:%02d:%02d %04d",
1428 : 0 : DayNames[wday], MonthNames[GET_MONTH(date)-1],
1429 : 0 : GET_DAY(date), hours, minutes, seconds,
1430 : 0 : GET_YEAR(date));
1431 : : }
1432 : :
1433 : : static PyObject *delta_negative(PyDateTime_Delta *self);
1434 : :
1435 : : /* Add formatted UTC offset string to buf. buf has no more than
1436 : : * buflen bytes remaining. The UTC offset is gotten by calling
1437 : : * tzinfo.uctoffset(tzinfoarg). If that returns None, \0 is stored into
1438 : : * *buf, and that's all. Else the returned value is checked for sanity (an
1439 : : * integer in range), and if that's OK it's converted to an hours & minutes
1440 : : * string of the form
1441 : : * sign HH sep MM [sep SS [. UUUUUU]]
1442 : : * Returns 0 if everything is OK. If the return value from utcoffset() is
1443 : : * bogus, an appropriate exception is set and -1 is returned.
1444 : : */
1445 : : static int
1446 : 0 : format_utcoffset(char *buf, size_t buflen, const char *sep,
1447 : : PyObject *tzinfo, PyObject *tzinfoarg)
1448 : : {
1449 : : PyObject *offset;
1450 : : int hours, minutes, seconds, microseconds;
1451 : : char sign;
1452 : :
1453 : : assert(buflen >= 1);
1454 : :
1455 : 0 : offset = call_utcoffset(tzinfo, tzinfoarg);
1456 [ # # ]: 0 : if (offset == NULL)
1457 : 0 : return -1;
1458 [ # # ]: 0 : if (offset == Py_None) {
1459 : 0 : Py_DECREF(offset);
1460 : 0 : *buf = '\0';
1461 : 0 : return 0;
1462 : : }
1463 : : /* Offset is normalized, so it is negative if days < 0 */
1464 [ # # ]: 0 : if (GET_TD_DAYS(offset) < 0) {
1465 : 0 : sign = '-';
1466 : 0 : Py_SETREF(offset, delta_negative((PyDateTime_Delta *)offset));
1467 [ # # ]: 0 : if (offset == NULL)
1468 : 0 : return -1;
1469 : : }
1470 : : else {
1471 : 0 : sign = '+';
1472 : : }
1473 : : /* Offset is not negative here. */
1474 : 0 : microseconds = GET_TD_MICROSECONDS(offset);
1475 : 0 : seconds = GET_TD_SECONDS(offset);
1476 : 0 : Py_DECREF(offset);
1477 : 0 : minutes = divmod(seconds, 60, &seconds);
1478 : 0 : hours = divmod(minutes, 60, &minutes);
1479 [ # # ]: 0 : if (microseconds) {
1480 : 0 : PyOS_snprintf(buf, buflen, "%c%02d%s%02d%s%02d.%06d", sign,
1481 : : hours, sep, minutes, sep, seconds, microseconds);
1482 : 0 : return 0;
1483 : : }
1484 [ # # ]: 0 : if (seconds) {
1485 : 0 : PyOS_snprintf(buf, buflen, "%c%02d%s%02d%s%02d", sign, hours,
1486 : : sep, minutes, sep, seconds);
1487 : 0 : return 0;
1488 : : }
1489 : 0 : PyOS_snprintf(buf, buflen, "%c%02d%s%02d", sign, hours, sep, minutes);
1490 : 0 : return 0;
1491 : : }
1492 : :
1493 : : static PyObject *
1494 : 0 : make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg)
1495 : : {
1496 : : char buf[100];
1497 : 0 : PyObject *tzinfo = get_tzinfo_member(object);
1498 : :
1499 [ # # # # ]: 0 : if (tzinfo == Py_None || tzinfo == NULL) {
1500 : 0 : return PyBytes_FromStringAndSize(NULL, 0);
1501 : : }
1502 : :
1503 : : assert(tzinfoarg != NULL);
1504 [ # # ]: 0 : if (format_utcoffset(buf,
1505 : : sizeof(buf),
1506 : : sep,
1507 : : tzinfo,
1508 : : tzinfoarg) < 0)
1509 : 0 : return NULL;
1510 : :
1511 : 0 : return PyBytes_FromStringAndSize(buf, strlen(buf));
1512 : : }
1513 : :
1514 : : static PyObject *
1515 : 0 : make_Zreplacement(PyObject *object, PyObject *tzinfoarg)
1516 : : {
1517 : : PyObject *temp;
1518 : 0 : PyObject *tzinfo = get_tzinfo_member(object);
1519 : 0 : PyObject *Zreplacement = PyUnicode_FromStringAndSize(NULL, 0);
1520 : :
1521 [ # # ]: 0 : if (Zreplacement == NULL)
1522 : 0 : return NULL;
1523 [ # # # # ]: 0 : if (tzinfo == Py_None || tzinfo == NULL)
1524 : 0 : return Zreplacement;
1525 : :
1526 : : assert(tzinfoarg != NULL);
1527 : 0 : temp = call_tzname(tzinfo, tzinfoarg);
1528 [ # # ]: 0 : if (temp == NULL)
1529 : 0 : goto Error;
1530 [ # # ]: 0 : if (temp == Py_None) {
1531 : 0 : Py_DECREF(temp);
1532 : 0 : return Zreplacement;
1533 : : }
1534 : :
1535 : : assert(PyUnicode_Check(temp));
1536 : : /* Since the tzname is getting stuffed into the
1537 : : * format, we have to double any % signs so that
1538 : : * strftime doesn't treat them as format codes.
1539 : : */
1540 : 0 : Py_DECREF(Zreplacement);
1541 : 0 : Zreplacement = PyObject_CallMethod(temp, "replace", "ss", "%", "%%");
1542 : 0 : Py_DECREF(temp);
1543 [ # # ]: 0 : if (Zreplacement == NULL)
1544 : 0 : return NULL;
1545 [ # # ]: 0 : if (!PyUnicode_Check(Zreplacement)) {
1546 : 0 : PyErr_SetString(PyExc_TypeError,
1547 : : "tzname.replace() did not return a string");
1548 : 0 : goto Error;
1549 : : }
1550 : 0 : return Zreplacement;
1551 : :
1552 : 0 : Error:
1553 : 0 : Py_DECREF(Zreplacement);
1554 : 0 : return NULL;
1555 : : }
1556 : :
1557 : : static PyObject *
1558 : 0 : make_freplacement(PyObject *object)
1559 : : {
1560 : : char freplacement[64];
1561 [ # # ]: 0 : if (PyTime_Check(object))
1562 : 0 : sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object));
1563 [ # # ]: 0 : else if (PyDateTime_Check(object))
1564 : 0 : sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object));
1565 : : else
1566 : 0 : sprintf(freplacement, "%06d", 0);
1567 : :
1568 : 0 : return PyBytes_FromStringAndSize(freplacement, strlen(freplacement));
1569 : : }
1570 : :
1571 : : /* I sure don't want to reproduce the strftime code from the time module,
1572 : : * so this imports the module and calls it. All the hair is due to
1573 : : * giving special meanings to the %z, %:z, %Z and %f format codes via a
1574 : : * preprocessing step on the format string.
1575 : : * tzinfoarg is the argument to pass to the object's tzinfo method, if
1576 : : * needed.
1577 : : */
1578 : : static PyObject *
1579 : 0 : wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
1580 : : PyObject *tzinfoarg)
1581 : : {
1582 : 0 : PyObject *result = NULL; /* guilty until proved innocent */
1583 : :
1584 : 0 : PyObject *zreplacement = NULL; /* py string, replacement for %z */
1585 : 0 : PyObject *colonzreplacement = NULL; /* py string, replacement for %:z */
1586 : 0 : PyObject *Zreplacement = NULL; /* py string, replacement for %Z */
1587 : 0 : PyObject *freplacement = NULL; /* py string, replacement for %f */
1588 : :
1589 : : const char *pin; /* pointer to next char in input format */
1590 : : Py_ssize_t flen; /* length of input format */
1591 : : char ch; /* next char in input format */
1592 : :
1593 : 0 : PyObject *newfmt = NULL; /* py string, the output format */
1594 : : char *pnew; /* pointer to available byte in output format */
1595 : : size_t totalnew; /* number bytes total in output format buffer,
1596 : : exclusive of trailing \0 */
1597 : : size_t usednew; /* number bytes used so far in output format buffer */
1598 : :
1599 : : const char *ptoappend; /* ptr to string to append to output buffer */
1600 : : Py_ssize_t ntoappend; /* # of bytes to append to output buffer */
1601 : :
1602 : : assert(object && format && timetuple);
1603 : : assert(PyUnicode_Check(format));
1604 : : /* Convert the input format to a C string and size */
1605 : 0 : pin = PyUnicode_AsUTF8AndSize(format, &flen);
1606 [ # # ]: 0 : if (!pin)
1607 : 0 : return NULL;
1608 : :
1609 : : /* Scan the input format, looking for %z/%Z/%f escapes, building
1610 : : * a new format. Since computing the replacements for those codes
1611 : : * is expensive, don't unless they're actually used.
1612 : : */
1613 [ # # ]: 0 : if (flen > INT_MAX - 1) {
1614 : 0 : PyErr_NoMemory();
1615 : 0 : goto Done;
1616 : : }
1617 : :
1618 : 0 : totalnew = flen + 1; /* realistic if no %z/%Z */
1619 : 0 : newfmt = PyBytes_FromStringAndSize(NULL, totalnew);
1620 [ # # ]: 0 : if (newfmt == NULL) goto Done;
1621 : 0 : pnew = PyBytes_AsString(newfmt);
1622 : 0 : usednew = 0;
1623 : :
1624 [ # # ]: 0 : while ((ch = *pin++) != '\0') {
1625 [ # # ]: 0 : if (ch != '%') {
1626 : 0 : ptoappend = pin - 1;
1627 : 0 : ntoappend = 1;
1628 : : }
1629 [ # # ]: 0 : else if ((ch = *pin++) == '\0') {
1630 : : /* Null byte follows %, copy only '%'.
1631 : : *
1632 : : * Back the pin up one char so that we catch the null check
1633 : : * the next time through the loop.*/
1634 : 0 : pin--;
1635 : 0 : ptoappend = pin - 1;
1636 : 0 : ntoappend = 1;
1637 : : }
1638 : : /* A % has been seen and ch is the character after it. */
1639 [ # # ]: 0 : else if (ch == 'z') {
1640 : : /* %z -> +HHMM */
1641 [ # # ]: 0 : if (zreplacement == NULL) {
1642 : 0 : zreplacement = make_somezreplacement(object, "", tzinfoarg);
1643 [ # # ]: 0 : if (zreplacement == NULL)
1644 : 0 : goto Done;
1645 : : }
1646 : : assert(zreplacement != NULL);
1647 : : assert(PyBytes_Check(zreplacement));
1648 : 0 : ptoappend = PyBytes_AS_STRING(zreplacement);
1649 : 0 : ntoappend = PyBytes_GET_SIZE(zreplacement);
1650 : : }
1651 [ # # # # : 0 : else if (ch == ':' && *pin == 'z' && pin++) {
# # ]
1652 : : /* %:z -> +HH:MM */
1653 [ # # ]: 0 : if (colonzreplacement == NULL) {
1654 : 0 : colonzreplacement = make_somezreplacement(object, ":", tzinfoarg);
1655 [ # # ]: 0 : if (colonzreplacement == NULL)
1656 : 0 : goto Done;
1657 : : }
1658 : : assert(colonzreplacement != NULL);
1659 : : assert(PyBytes_Check(colonzreplacement));
1660 : 0 : ptoappend = PyBytes_AS_STRING(colonzreplacement);
1661 : 0 : ntoappend = PyBytes_GET_SIZE(colonzreplacement);
1662 : : }
1663 [ # # ]: 0 : else if (ch == 'Z') {
1664 : : /* format tzname */
1665 [ # # ]: 0 : if (Zreplacement == NULL) {
1666 : 0 : Zreplacement = make_Zreplacement(object,
1667 : : tzinfoarg);
1668 [ # # ]: 0 : if (Zreplacement == NULL)
1669 : 0 : goto Done;
1670 : : }
1671 : : assert(Zreplacement != NULL);
1672 : : assert(PyUnicode_Check(Zreplacement));
1673 : 0 : ptoappend = PyUnicode_AsUTF8AndSize(Zreplacement,
1674 : : &ntoappend);
1675 [ # # ]: 0 : if (ptoappend == NULL)
1676 : 0 : goto Done;
1677 : : }
1678 [ # # ]: 0 : else if (ch == 'f') {
1679 : : /* format microseconds */
1680 [ # # ]: 0 : if (freplacement == NULL) {
1681 : 0 : freplacement = make_freplacement(object);
1682 [ # # ]: 0 : if (freplacement == NULL)
1683 : 0 : goto Done;
1684 : : }
1685 : : assert(freplacement != NULL);
1686 : : assert(PyBytes_Check(freplacement));
1687 : 0 : ptoappend = PyBytes_AS_STRING(freplacement);
1688 : 0 : ntoappend = PyBytes_GET_SIZE(freplacement);
1689 : : }
1690 : : else {
1691 : : /* percent followed by something else */
1692 : 0 : ptoappend = pin - 2;
1693 : 0 : ntoappend = 2;
1694 : : }
1695 : :
1696 : : /* Append the ntoappend chars starting at ptoappend to
1697 : : * the new format.
1698 : : */
1699 [ # # ]: 0 : if (ntoappend == 0)
1700 : 0 : continue;
1701 : : assert(ptoappend != NULL);
1702 : : assert(ntoappend > 0);
1703 [ # # ]: 0 : while (usednew + ntoappend > totalnew) {
1704 [ # # ]: 0 : if (totalnew > (PY_SSIZE_T_MAX >> 1)) { /* overflow */
1705 : 0 : PyErr_NoMemory();
1706 : 0 : goto Done;
1707 : : }
1708 : 0 : totalnew <<= 1;
1709 [ # # ]: 0 : if (_PyBytes_Resize(&newfmt, totalnew) < 0)
1710 : 0 : goto Done;
1711 : 0 : pnew = PyBytes_AsString(newfmt) + usednew;
1712 : : }
1713 : 0 : memcpy(pnew, ptoappend, ntoappend);
1714 : 0 : pnew += ntoappend;
1715 : 0 : usednew += ntoappend;
1716 : : assert(usednew <= totalnew);
1717 : : } /* end while() */
1718 : :
1719 [ # # ]: 0 : if (_PyBytes_Resize(&newfmt, usednew) < 0)
1720 : 0 : goto Done;
1721 : : {
1722 : : PyObject *format;
1723 : 0 : PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime");
1724 : :
1725 [ # # ]: 0 : if (strftime == NULL)
1726 : 0 : goto Done;
1727 : 0 : format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt));
1728 [ # # ]: 0 : if (format != NULL) {
1729 : 0 : result = PyObject_CallFunctionObjArgs(strftime,
1730 : : format, timetuple, NULL);
1731 : 0 : Py_DECREF(format);
1732 : : }
1733 : 0 : Py_DECREF(strftime);
1734 : : }
1735 : 0 : Done:
1736 : 0 : Py_XDECREF(freplacement);
1737 : 0 : Py_XDECREF(zreplacement);
1738 : 0 : Py_XDECREF(colonzreplacement);
1739 : 0 : Py_XDECREF(Zreplacement);
1740 : 0 : Py_XDECREF(newfmt);
1741 : 0 : return result;
1742 : : }
1743 : :
1744 : : /* ---------------------------------------------------------------------------
1745 : : * Wrap functions from the time module. These aren't directly available
1746 : : * from C. Perhaps they should be.
1747 : : */
1748 : :
1749 : : /* Call time.time() and return its result (a Python float). */
1750 : : static PyObject *
1751 : 0 : time_time(void)
1752 : : {
1753 : 0 : PyObject *result = NULL;
1754 : 0 : PyObject *time = _PyImport_GetModuleAttrString("time", "time");
1755 : :
1756 [ # # ]: 0 : if (time != NULL) {
1757 : 0 : result = PyObject_CallNoArgs(time);
1758 : 0 : Py_DECREF(time);
1759 : : }
1760 : 0 : return result;
1761 : : }
1762 : :
1763 : : /* Build a time.struct_time. The weekday and day number are automatically
1764 : : * computed from the y,m,d args.
1765 : : */
1766 : : static PyObject *
1767 : 0 : build_struct_time(int y, int m, int d, int hh, int mm, int ss, int dstflag)
1768 : : {
1769 : : PyObject *struct_time;
1770 : : PyObject *result;
1771 : :
1772 : 0 : struct_time = _PyImport_GetModuleAttrString("time", "struct_time");
1773 [ # # ]: 0 : if (struct_time == NULL) {
1774 : 0 : return NULL;
1775 : : }
1776 : :
1777 : 0 : result = PyObject_CallFunction(struct_time, "((iiiiiiiii))",
1778 : : y, m, d,
1779 : : hh, mm, ss,
1780 : : weekday(y, m, d),
1781 : 0 : days_before_month(y, m) + d,
1782 : : dstflag);
1783 : 0 : Py_DECREF(struct_time);
1784 : 0 : return result;
1785 : : }
1786 : :
1787 : : /* ---------------------------------------------------------------------------
1788 : : * Miscellaneous helpers.
1789 : : */
1790 : :
1791 : : /* The comparisons here all most naturally compute a cmp()-like result.
1792 : : * This little helper turns that into a bool result for rich comparisons.
1793 : : */
1794 : : static PyObject *
1795 : 0 : diff_to_bool(int diff, int op)
1796 : : {
1797 [ # # # # : 0 : Py_RETURN_RICHCOMPARE(diff, 0, op);
# # # # #
# # # # #
# # # #
# ]
1798 : : }
1799 : :
1800 : : /* Raises a "can't compare" TypeError and returns NULL. */
1801 : : static PyObject *
1802 : 0 : cmperror(PyObject *a, PyObject *b)
1803 : : {
1804 : 0 : PyErr_Format(PyExc_TypeError,
1805 : : "can't compare %s to %s",
1806 : 0 : Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
1807 : 0 : return NULL;
1808 : : }
1809 : :
1810 : : /* ---------------------------------------------------------------------------
1811 : : * Cached Python objects; these are set by the module init function.
1812 : : */
1813 : :
1814 : : /* Conversion factors. */
1815 : : static PyObject *us_per_ms = NULL; /* 1000 */
1816 : : static PyObject *us_per_second = NULL; /* 1000000 */
1817 : : static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */
1818 : : static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */
1819 : : static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */
1820 : : static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */
1821 : : static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */
1822 : :
1823 : : /* ---------------------------------------------------------------------------
1824 : : * Class implementations.
1825 : : */
1826 : :
1827 : : /*
1828 : : * PyDateTime_Delta implementation.
1829 : : */
1830 : :
1831 : : /* Convert a timedelta to a number of us,
1832 : : * (24*3600*self.days + self.seconds)*1000000 + self.microseconds
1833 : : * as a Python int.
1834 : : * Doing mixed-radix arithmetic by hand instead is excruciating in C,
1835 : : * due to ubiquitous overflow possibilities.
1836 : : */
1837 : : static PyObject *
1838 : 0 : delta_to_microseconds(PyDateTime_Delta *self)
1839 : : {
1840 : 0 : PyObject *x1 = NULL;
1841 : 0 : PyObject *x2 = NULL;
1842 : 0 : PyObject *x3 = NULL;
1843 : 0 : PyObject *result = NULL;
1844 : :
1845 : 0 : x1 = PyLong_FromLong(GET_TD_DAYS(self));
1846 [ # # ]: 0 : if (x1 == NULL)
1847 : 0 : goto Done;
1848 : 0 : x2 = PyNumber_Multiply(x1, seconds_per_day); /* days in seconds */
1849 [ # # ]: 0 : if (x2 == NULL)
1850 : 0 : goto Done;
1851 : 0 : Py_SETREF(x1, NULL);
1852 : :
1853 : : /* x2 has days in seconds */
1854 : 0 : x1 = PyLong_FromLong(GET_TD_SECONDS(self)); /* seconds */
1855 [ # # ]: 0 : if (x1 == NULL)
1856 : 0 : goto Done;
1857 : 0 : x3 = PyNumber_Add(x1, x2); /* days and seconds in seconds */
1858 [ # # ]: 0 : if (x3 == NULL)
1859 : 0 : goto Done;
1860 : 0 : Py_DECREF(x1);
1861 : 0 : Py_DECREF(x2);
1862 : 0 : /* x1 = */ x2 = NULL;
1863 : :
1864 : : /* x3 has days+seconds in seconds */
1865 : 0 : x1 = PyNumber_Multiply(x3, us_per_second); /* us */
1866 [ # # ]: 0 : if (x1 == NULL)
1867 : 0 : goto Done;
1868 : 0 : Py_SETREF(x3, NULL);
1869 : :
1870 : : /* x1 has days+seconds in us */
1871 : 0 : x2 = PyLong_FromLong(GET_TD_MICROSECONDS(self));
1872 [ # # ]: 0 : if (x2 == NULL)
1873 : 0 : goto Done;
1874 : 0 : result = PyNumber_Add(x1, x2);
1875 : : assert(result == NULL || PyLong_CheckExact(result));
1876 : :
1877 : 0 : Done:
1878 : 0 : Py_XDECREF(x1);
1879 : 0 : Py_XDECREF(x2);
1880 : 0 : Py_XDECREF(x3);
1881 : 0 : return result;
1882 : : }
1883 : :
1884 : : static PyObject *
1885 : 0 : checked_divmod(PyObject *a, PyObject *b)
1886 : : {
1887 : 0 : PyObject *result = PyNumber_Divmod(a, b);
1888 [ # # ]: 0 : if (result != NULL) {
1889 [ # # ]: 0 : if (!PyTuple_Check(result)) {
1890 : 0 : PyErr_Format(PyExc_TypeError,
1891 : : "divmod() returned non-tuple (type %.200s)",
1892 : 0 : Py_TYPE(result)->tp_name);
1893 : 0 : Py_DECREF(result);
1894 : 0 : return NULL;
1895 : : }
1896 [ # # ]: 0 : if (PyTuple_GET_SIZE(result) != 2) {
1897 : 0 : PyErr_Format(PyExc_TypeError,
1898 : : "divmod() returned a tuple of size %zd",
1899 : : PyTuple_GET_SIZE(result));
1900 : 0 : Py_DECREF(result);
1901 : 0 : return NULL;
1902 : : }
1903 : : }
1904 : 0 : return result;
1905 : : }
1906 : :
1907 : : /* Convert a number of us (as a Python int) to a timedelta.
1908 : : */
1909 : : static PyObject *
1910 : 0 : microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
1911 : : {
1912 : : int us;
1913 : : int s;
1914 : : int d;
1915 : :
1916 : 0 : PyObject *tuple = NULL;
1917 : 0 : PyObject *num = NULL;
1918 : 0 : PyObject *result = NULL;
1919 : :
1920 : 0 : tuple = checked_divmod(pyus, us_per_second);
1921 [ # # ]: 0 : if (tuple == NULL) {
1922 : 0 : goto Done;
1923 : : }
1924 : :
1925 : 0 : num = PyTuple_GET_ITEM(tuple, 1); /* us */
1926 : 0 : us = _PyLong_AsInt(num);
1927 : 0 : num = NULL;
1928 [ # # # # ]: 0 : if (us == -1 && PyErr_Occurred()) {
1929 : 0 : goto Done;
1930 : : }
1931 [ # # # # ]: 0 : if (!(0 <= us && us < 1000000)) {
1932 : 0 : goto BadDivmod;
1933 : : }
1934 : :
1935 : 0 : num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
1936 : 0 : Py_DECREF(tuple);
1937 : :
1938 : 0 : tuple = checked_divmod(num, seconds_per_day);
1939 [ # # ]: 0 : if (tuple == NULL)
1940 : 0 : goto Done;
1941 : 0 : Py_DECREF(num);
1942 : :
1943 : 0 : num = PyTuple_GET_ITEM(tuple, 1); /* seconds */
1944 : 0 : s = _PyLong_AsInt(num);
1945 : 0 : num = NULL;
1946 [ # # # # ]: 0 : if (s == -1 && PyErr_Occurred()) {
1947 : 0 : goto Done;
1948 : : }
1949 [ # # # # ]: 0 : if (!(0 <= s && s < 24*3600)) {
1950 : 0 : goto BadDivmod;
1951 : : }
1952 : :
1953 : 0 : num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover days */
1954 : 0 : d = _PyLong_AsInt(num);
1955 [ # # # # ]: 0 : if (d == -1 && PyErr_Occurred()) {
1956 : 0 : goto Done;
1957 : : }
1958 : 0 : result = new_delta_ex(d, s, us, 0, type);
1959 : :
1960 : 0 : Done:
1961 : 0 : Py_XDECREF(tuple);
1962 : 0 : Py_XDECREF(num);
1963 : 0 : return result;
1964 : :
1965 : 0 : BadDivmod:
1966 : 0 : PyErr_SetString(PyExc_TypeError,
1967 : : "divmod() returned a value out of range");
1968 : 0 : goto Done;
1969 : : }
1970 : :
1971 : : #define microseconds_to_delta(pymicros) \
1972 : : microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType)
1973 : :
1974 : : static PyObject *
1975 : 0 : multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
1976 : : {
1977 : : PyObject *pyus_in;
1978 : : PyObject *pyus_out;
1979 : : PyObject *result;
1980 : :
1981 : 0 : pyus_in = delta_to_microseconds(delta);
1982 [ # # ]: 0 : if (pyus_in == NULL)
1983 : 0 : return NULL;
1984 : :
1985 : 0 : pyus_out = PyNumber_Multiply(intobj, pyus_in);
1986 : 0 : Py_DECREF(pyus_in);
1987 [ # # ]: 0 : if (pyus_out == NULL)
1988 : 0 : return NULL;
1989 : :
1990 : 0 : result = microseconds_to_delta(pyus_out);
1991 : 0 : Py_DECREF(pyus_out);
1992 : 0 : return result;
1993 : : }
1994 : :
1995 : : static PyObject *
1996 : 0 : get_float_as_integer_ratio(PyObject *floatobj)
1997 : : {
1998 : : PyObject *ratio;
1999 : :
2000 : : assert(floatobj && PyFloat_Check(floatobj));
2001 : 0 : ratio = PyObject_CallMethodNoArgs(floatobj, &_Py_ID(as_integer_ratio));
2002 [ # # ]: 0 : if (ratio == NULL) {
2003 : 0 : return NULL;
2004 : : }
2005 [ # # ]: 0 : if (!PyTuple_Check(ratio)) {
2006 : 0 : PyErr_Format(PyExc_TypeError,
2007 : : "unexpected return type from as_integer_ratio(): "
2008 : : "expected tuple, got '%.200s'",
2009 : 0 : Py_TYPE(ratio)->tp_name);
2010 : 0 : Py_DECREF(ratio);
2011 : 0 : return NULL;
2012 : : }
2013 [ # # ]: 0 : if (PyTuple_Size(ratio) != 2) {
2014 : 0 : PyErr_SetString(PyExc_ValueError,
2015 : : "as_integer_ratio() must return a 2-tuple");
2016 : 0 : Py_DECREF(ratio);
2017 : 0 : return NULL;
2018 : : }
2019 : 0 : return ratio;
2020 : : }
2021 : :
2022 : : /* op is 0 for multiplication, 1 for division */
2023 : : static PyObject *
2024 : 0 : multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, int op)
2025 : : {
2026 : 0 : PyObject *result = NULL;
2027 : 0 : PyObject *pyus_in = NULL, *temp, *pyus_out;
2028 : 0 : PyObject *ratio = NULL;
2029 : :
2030 : 0 : pyus_in = delta_to_microseconds(delta);
2031 [ # # ]: 0 : if (pyus_in == NULL)
2032 : 0 : return NULL;
2033 : 0 : ratio = get_float_as_integer_ratio(floatobj);
2034 [ # # ]: 0 : if (ratio == NULL) {
2035 : 0 : goto error;
2036 : : }
2037 : 0 : temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, op));
2038 : 0 : Py_SETREF(pyus_in, NULL);
2039 [ # # ]: 0 : if (temp == NULL)
2040 : 0 : goto error;
2041 : 0 : pyus_out = divide_nearest(temp, PyTuple_GET_ITEM(ratio, !op));
2042 : 0 : Py_DECREF(temp);
2043 [ # # ]: 0 : if (pyus_out == NULL)
2044 : 0 : goto error;
2045 : 0 : result = microseconds_to_delta(pyus_out);
2046 : 0 : Py_DECREF(pyus_out);
2047 : 0 : error:
2048 : 0 : Py_XDECREF(pyus_in);
2049 : 0 : Py_XDECREF(ratio);
2050 : :
2051 : 0 : return result;
2052 : : }
2053 : :
2054 : : static PyObject *
2055 : 0 : divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj)
2056 : : {
2057 : : PyObject *pyus_in;
2058 : : PyObject *pyus_out;
2059 : : PyObject *result;
2060 : :
2061 : 0 : pyus_in = delta_to_microseconds(delta);
2062 [ # # ]: 0 : if (pyus_in == NULL)
2063 : 0 : return NULL;
2064 : :
2065 : 0 : pyus_out = PyNumber_FloorDivide(pyus_in, intobj);
2066 : 0 : Py_DECREF(pyus_in);
2067 [ # # ]: 0 : if (pyus_out == NULL)
2068 : 0 : return NULL;
2069 : :
2070 : 0 : result = microseconds_to_delta(pyus_out);
2071 : 0 : Py_DECREF(pyus_out);
2072 : 0 : return result;
2073 : : }
2074 : :
2075 : : static PyObject *
2076 : 0 : divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
2077 : : {
2078 : : PyObject *pyus_left;
2079 : : PyObject *pyus_right;
2080 : : PyObject *result;
2081 : :
2082 : 0 : pyus_left = delta_to_microseconds(left);
2083 [ # # ]: 0 : if (pyus_left == NULL)
2084 : 0 : return NULL;
2085 : :
2086 : 0 : pyus_right = delta_to_microseconds(right);
2087 [ # # ]: 0 : if (pyus_right == NULL) {
2088 : 0 : Py_DECREF(pyus_left);
2089 : 0 : return NULL;
2090 : : }
2091 : :
2092 : 0 : result = PyNumber_FloorDivide(pyus_left, pyus_right);
2093 : 0 : Py_DECREF(pyus_left);
2094 : 0 : Py_DECREF(pyus_right);
2095 : 0 : return result;
2096 : : }
2097 : :
2098 : : static PyObject *
2099 : 0 : truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
2100 : : {
2101 : : PyObject *pyus_left;
2102 : : PyObject *pyus_right;
2103 : : PyObject *result;
2104 : :
2105 : 0 : pyus_left = delta_to_microseconds(left);
2106 [ # # ]: 0 : if (pyus_left == NULL)
2107 : 0 : return NULL;
2108 : :
2109 : 0 : pyus_right = delta_to_microseconds(right);
2110 [ # # ]: 0 : if (pyus_right == NULL) {
2111 : 0 : Py_DECREF(pyus_left);
2112 : 0 : return NULL;
2113 : : }
2114 : :
2115 : 0 : result = PyNumber_TrueDivide(pyus_left, pyus_right);
2116 : 0 : Py_DECREF(pyus_left);
2117 : 0 : Py_DECREF(pyus_right);
2118 : 0 : return result;
2119 : : }
2120 : :
2121 : : static PyObject *
2122 : 0 : truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i)
2123 : : {
2124 : : PyObject *result;
2125 : : PyObject *pyus_in, *pyus_out;
2126 : 0 : pyus_in = delta_to_microseconds(delta);
2127 [ # # ]: 0 : if (pyus_in == NULL)
2128 : 0 : return NULL;
2129 : 0 : pyus_out = divide_nearest(pyus_in, i);
2130 : 0 : Py_DECREF(pyus_in);
2131 [ # # ]: 0 : if (pyus_out == NULL)
2132 : 0 : return NULL;
2133 : 0 : result = microseconds_to_delta(pyus_out);
2134 : 0 : Py_DECREF(pyus_out);
2135 : :
2136 : 0 : return result;
2137 : : }
2138 : :
2139 : : static PyObject *
2140 : 0 : delta_add(PyObject *left, PyObject *right)
2141 : : {
2142 : 0 : PyObject *result = Py_NotImplemented;
2143 : :
2144 [ # # # # ]: 0 : if (PyDelta_Check(left) && PyDelta_Check(right)) {
2145 : : /* delta + delta */
2146 : : /* The C-level additions can't overflow because of the
2147 : : * invariant bounds.
2148 : : */
2149 : 0 : int days = GET_TD_DAYS(left) + GET_TD_DAYS(right);
2150 : 0 : int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right);
2151 : 0 : int microseconds = GET_TD_MICROSECONDS(left) +
2152 : 0 : GET_TD_MICROSECONDS(right);
2153 : 0 : result = new_delta(days, seconds, microseconds, 1);
2154 : : }
2155 : :
2156 [ # # ]: 0 : if (result == Py_NotImplemented)
2157 : 0 : Py_INCREF(result);
2158 : 0 : return result;
2159 : : }
2160 : :
2161 : : static PyObject *
2162 : 0 : delta_negative(PyDateTime_Delta *self)
2163 : : {
2164 : 0 : return new_delta(-GET_TD_DAYS(self),
2165 : : -GET_TD_SECONDS(self),
2166 : : -GET_TD_MICROSECONDS(self),
2167 : : 1);
2168 : : }
2169 : :
2170 : : static PyObject *
2171 : 0 : delta_positive(PyDateTime_Delta *self)
2172 : : {
2173 : : /* Could optimize this (by returning self) if this isn't a
2174 : : * subclass -- but who uses unary + ? Approximately nobody.
2175 : : */
2176 : 0 : return new_delta(GET_TD_DAYS(self),
2177 : : GET_TD_SECONDS(self),
2178 : : GET_TD_MICROSECONDS(self),
2179 : : 0);
2180 : : }
2181 : :
2182 : : static PyObject *
2183 : 0 : delta_abs(PyDateTime_Delta *self)
2184 : : {
2185 : : PyObject *result;
2186 : :
2187 : : assert(GET_TD_MICROSECONDS(self) >= 0);
2188 : : assert(GET_TD_SECONDS(self) >= 0);
2189 : :
2190 [ # # ]: 0 : if (GET_TD_DAYS(self) < 0)
2191 : 0 : result = delta_negative(self);
2192 : : else
2193 : 0 : result = delta_positive(self);
2194 : :
2195 : 0 : return result;
2196 : : }
2197 : :
2198 : : static PyObject *
2199 : 0 : delta_subtract(PyObject *left, PyObject *right)
2200 : : {
2201 : 0 : PyObject *result = Py_NotImplemented;
2202 : :
2203 [ # # # # ]: 0 : if (PyDelta_Check(left) && PyDelta_Check(right)) {
2204 : : /* delta - delta */
2205 : : /* The C-level additions can't overflow because of the
2206 : : * invariant bounds.
2207 : : */
2208 : 0 : int days = GET_TD_DAYS(left) - GET_TD_DAYS(right);
2209 : 0 : int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right);
2210 : 0 : int microseconds = GET_TD_MICROSECONDS(left) -
2211 : 0 : GET_TD_MICROSECONDS(right);
2212 : 0 : result = new_delta(days, seconds, microseconds, 1);
2213 : : }
2214 : :
2215 [ # # ]: 0 : if (result == Py_NotImplemented)
2216 : 0 : Py_INCREF(result);
2217 : 0 : return result;
2218 : : }
2219 : :
2220 : : static int
2221 : 0 : delta_cmp(PyObject *self, PyObject *other)
2222 : : {
2223 : 0 : int diff = GET_TD_DAYS(self) - GET_TD_DAYS(other);
2224 [ # # ]: 0 : if (diff == 0) {
2225 : 0 : diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other);
2226 [ # # ]: 0 : if (diff == 0)
2227 : 0 : diff = GET_TD_MICROSECONDS(self) -
2228 : 0 : GET_TD_MICROSECONDS(other);
2229 : : }
2230 : 0 : return diff;
2231 : : }
2232 : :
2233 : : static PyObject *
2234 : 0 : delta_richcompare(PyObject *self, PyObject *other, int op)
2235 : : {
2236 [ # # ]: 0 : if (PyDelta_Check(other)) {
2237 : 0 : int diff = delta_cmp(self, other);
2238 : 0 : return diff_to_bool(diff, op);
2239 : : }
2240 : : else {
2241 : 0 : Py_RETURN_NOTIMPLEMENTED;
2242 : : }
2243 : : }
2244 : :
2245 : : static PyObject *delta_getstate(PyDateTime_Delta *self);
2246 : :
2247 : : static Py_hash_t
2248 : 0 : delta_hash(PyDateTime_Delta *self)
2249 : : {
2250 [ # # ]: 0 : if (self->hashcode == -1) {
2251 : 0 : PyObject *temp = delta_getstate(self);
2252 [ # # ]: 0 : if (temp != NULL) {
2253 : 0 : self->hashcode = PyObject_Hash(temp);
2254 : 0 : Py_DECREF(temp);
2255 : : }
2256 : : }
2257 : 0 : return self->hashcode;
2258 : : }
2259 : :
2260 : : static PyObject *
2261 : 0 : delta_multiply(PyObject *left, PyObject *right)
2262 : : {
2263 : 0 : PyObject *result = Py_NotImplemented;
2264 : :
2265 [ # # ]: 0 : if (PyDelta_Check(left)) {
2266 : : /* delta * ??? */
2267 [ # # ]: 0 : if (PyLong_Check(right))
2268 : 0 : result = multiply_int_timedelta(right,
2269 : : (PyDateTime_Delta *) left);
2270 [ # # ]: 0 : else if (PyFloat_Check(right))
2271 : 0 : result = multiply_truedivide_timedelta_float(
2272 : : (PyDateTime_Delta *) left, right, 0);
2273 : : }
2274 [ # # ]: 0 : else if (PyLong_Check(left))
2275 : 0 : result = multiply_int_timedelta(left,
2276 : : (PyDateTime_Delta *) right);
2277 [ # # ]: 0 : else if (PyFloat_Check(left))
2278 : 0 : result = multiply_truedivide_timedelta_float(
2279 : : (PyDateTime_Delta *) right, left, 0);
2280 : :
2281 [ # # ]: 0 : if (result == Py_NotImplemented)
2282 : 0 : Py_INCREF(result);
2283 : 0 : return result;
2284 : : }
2285 : :
2286 : : static PyObject *
2287 : 0 : delta_divide(PyObject *left, PyObject *right)
2288 : : {
2289 : 0 : PyObject *result = Py_NotImplemented;
2290 : :
2291 [ # # ]: 0 : if (PyDelta_Check(left)) {
2292 : : /* delta * ??? */
2293 [ # # ]: 0 : if (PyLong_Check(right))
2294 : 0 : result = divide_timedelta_int(
2295 : : (PyDateTime_Delta *)left,
2296 : : right);
2297 [ # # ]: 0 : else if (PyDelta_Check(right))
2298 : 0 : result = divide_timedelta_timedelta(
2299 : : (PyDateTime_Delta *)left,
2300 : : (PyDateTime_Delta *)right);
2301 : : }
2302 : :
2303 [ # # ]: 0 : if (result == Py_NotImplemented)
2304 : 0 : Py_INCREF(result);
2305 : 0 : return result;
2306 : : }
2307 : :
2308 : : static PyObject *
2309 : 0 : delta_truedivide(PyObject *left, PyObject *right)
2310 : : {
2311 : 0 : PyObject *result = Py_NotImplemented;
2312 : :
2313 [ # # ]: 0 : if (PyDelta_Check(left)) {
2314 [ # # ]: 0 : if (PyDelta_Check(right))
2315 : 0 : result = truedivide_timedelta_timedelta(
2316 : : (PyDateTime_Delta *)left,
2317 : : (PyDateTime_Delta *)right);
2318 [ # # ]: 0 : else if (PyFloat_Check(right))
2319 : 0 : result = multiply_truedivide_timedelta_float(
2320 : : (PyDateTime_Delta *)left, right, 1);
2321 [ # # ]: 0 : else if (PyLong_Check(right))
2322 : 0 : result = truedivide_timedelta_int(
2323 : : (PyDateTime_Delta *)left, right);
2324 : : }
2325 : :
2326 [ # # ]: 0 : if (result == Py_NotImplemented)
2327 : 0 : Py_INCREF(result);
2328 : 0 : return result;
2329 : : }
2330 : :
2331 : : static PyObject *
2332 : 0 : delta_remainder(PyObject *left, PyObject *right)
2333 : : {
2334 : : PyObject *pyus_left;
2335 : : PyObject *pyus_right;
2336 : : PyObject *pyus_remainder;
2337 : : PyObject *remainder;
2338 : :
2339 [ # # # # ]: 0 : if (!PyDelta_Check(left) || !PyDelta_Check(right))
2340 : 0 : Py_RETURN_NOTIMPLEMENTED;
2341 : :
2342 : 0 : pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
2343 [ # # ]: 0 : if (pyus_left == NULL)
2344 : 0 : return NULL;
2345 : :
2346 : 0 : pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
2347 [ # # ]: 0 : if (pyus_right == NULL) {
2348 : 0 : Py_DECREF(pyus_left);
2349 : 0 : return NULL;
2350 : : }
2351 : :
2352 : 0 : pyus_remainder = PyNumber_Remainder(pyus_left, pyus_right);
2353 : 0 : Py_DECREF(pyus_left);
2354 : 0 : Py_DECREF(pyus_right);
2355 [ # # ]: 0 : if (pyus_remainder == NULL)
2356 : 0 : return NULL;
2357 : :
2358 : 0 : remainder = microseconds_to_delta(pyus_remainder);
2359 : 0 : Py_DECREF(pyus_remainder);
2360 [ # # ]: 0 : if (remainder == NULL)
2361 : 0 : return NULL;
2362 : :
2363 : 0 : return remainder;
2364 : : }
2365 : :
2366 : : static PyObject *
2367 : 0 : delta_divmod(PyObject *left, PyObject *right)
2368 : : {
2369 : : PyObject *pyus_left;
2370 : : PyObject *pyus_right;
2371 : : PyObject *divmod;
2372 : : PyObject *delta;
2373 : : PyObject *result;
2374 : :
2375 [ # # # # ]: 0 : if (!PyDelta_Check(left) || !PyDelta_Check(right))
2376 : 0 : Py_RETURN_NOTIMPLEMENTED;
2377 : :
2378 : 0 : pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
2379 [ # # ]: 0 : if (pyus_left == NULL)
2380 : 0 : return NULL;
2381 : :
2382 : 0 : pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
2383 [ # # ]: 0 : if (pyus_right == NULL) {
2384 : 0 : Py_DECREF(pyus_left);
2385 : 0 : return NULL;
2386 : : }
2387 : :
2388 : 0 : divmod = checked_divmod(pyus_left, pyus_right);
2389 : 0 : Py_DECREF(pyus_left);
2390 : 0 : Py_DECREF(pyus_right);
2391 [ # # ]: 0 : if (divmod == NULL)
2392 : 0 : return NULL;
2393 : :
2394 : 0 : delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1));
2395 [ # # ]: 0 : if (delta == NULL) {
2396 : 0 : Py_DECREF(divmod);
2397 : 0 : return NULL;
2398 : : }
2399 : 0 : result = PyTuple_Pack(2, PyTuple_GET_ITEM(divmod, 0), delta);
2400 : 0 : Py_DECREF(delta);
2401 : 0 : Py_DECREF(divmod);
2402 : 0 : return result;
2403 : : }
2404 : :
2405 : : /* Fold in the value of the tag ("seconds", "weeks", etc) component of a
2406 : : * timedelta constructor. sofar is the # of microseconds accounted for
2407 : : * so far, and there are factor microseconds per current unit, the number
2408 : : * of which is given by num. num * factor is added to sofar in a
2409 : : * numerically careful way, and that's the result. Any fractional
2410 : : * microseconds left over (this can happen if num is a float type) are
2411 : : * added into *leftover.
2412 : : * Note that there are many ways this can give an error (NULL) return.
2413 : : */
2414 : : static PyObject *
2415 : 0 : accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor,
2416 : : double *leftover)
2417 : : {
2418 : : PyObject *prod;
2419 : : PyObject *sum;
2420 : :
2421 : : assert(num != NULL);
2422 : :
2423 [ # # ]: 0 : if (PyLong_Check(num)) {
2424 : 0 : prod = PyNumber_Multiply(num, factor);
2425 [ # # ]: 0 : if (prod == NULL)
2426 : 0 : return NULL;
2427 : 0 : sum = PyNumber_Add(sofar, prod);
2428 : 0 : Py_DECREF(prod);
2429 : 0 : return sum;
2430 : : }
2431 : :
2432 [ # # ]: 0 : if (PyFloat_Check(num)) {
2433 : : double dnum;
2434 : : double fracpart;
2435 : : double intpart;
2436 : : PyObject *x;
2437 : : PyObject *y;
2438 : :
2439 : : /* The Plan: decompose num into an integer part and a
2440 : : * fractional part, num = intpart + fracpart.
2441 : : * Then num * factor ==
2442 : : * intpart * factor + fracpart * factor
2443 : : * and the LHS can be computed exactly in long arithmetic.
2444 : : * The RHS is again broken into an int part and frac part.
2445 : : * and the frac part is added into *leftover.
2446 : : */
2447 : 0 : dnum = PyFloat_AsDouble(num);
2448 [ # # # # ]: 0 : if (dnum == -1.0 && PyErr_Occurred())
2449 : 0 : return NULL;
2450 : 0 : fracpart = modf(dnum, &intpart);
2451 : 0 : x = PyLong_FromDouble(intpart);
2452 [ # # ]: 0 : if (x == NULL)
2453 : 0 : return NULL;
2454 : :
2455 : 0 : prod = PyNumber_Multiply(x, factor);
2456 : 0 : Py_DECREF(x);
2457 [ # # ]: 0 : if (prod == NULL)
2458 : 0 : return NULL;
2459 : :
2460 : 0 : sum = PyNumber_Add(sofar, prod);
2461 : 0 : Py_DECREF(prod);
2462 [ # # ]: 0 : if (sum == NULL)
2463 : 0 : return NULL;
2464 : :
2465 [ # # ]: 0 : if (fracpart == 0.0)
2466 : 0 : return sum;
2467 : : /* So far we've lost no information. Dealing with the
2468 : : * fractional part requires float arithmetic, and may
2469 : : * lose a little info.
2470 : : */
2471 : : assert(PyLong_CheckExact(factor));
2472 : 0 : dnum = PyLong_AsDouble(factor);
2473 : :
2474 : 0 : dnum *= fracpart;
2475 : 0 : fracpart = modf(dnum, &intpart);
2476 : 0 : x = PyLong_FromDouble(intpart);
2477 [ # # ]: 0 : if (x == NULL) {
2478 : 0 : Py_DECREF(sum);
2479 : 0 : return NULL;
2480 : : }
2481 : :
2482 : 0 : y = PyNumber_Add(sum, x);
2483 : 0 : Py_DECREF(sum);
2484 : 0 : Py_DECREF(x);
2485 : 0 : *leftover += fracpart;
2486 : 0 : return y;
2487 : : }
2488 : :
2489 : 0 : PyErr_Format(PyExc_TypeError,
2490 : : "unsupported type for timedelta %s component: %s",
2491 : 0 : tag, Py_TYPE(num)->tp_name);
2492 : 0 : return NULL;
2493 : : }
2494 : :
2495 : : static PyObject *
2496 : 0 : delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
2497 : : {
2498 : 0 : PyObject *self = NULL;
2499 : :
2500 : : /* Argument objects. */
2501 : 0 : PyObject *day = NULL;
2502 : 0 : PyObject *second = NULL;
2503 : 0 : PyObject *us = NULL;
2504 : 0 : PyObject *ms = NULL;
2505 : 0 : PyObject *minute = NULL;
2506 : 0 : PyObject *hour = NULL;
2507 : 0 : PyObject *week = NULL;
2508 : :
2509 : 0 : PyObject *x = NULL; /* running sum of microseconds */
2510 : 0 : PyObject *y = NULL; /* temp sum of microseconds */
2511 : 0 : double leftover_us = 0.0;
2512 : :
2513 : : static char *keywords[] = {
2514 : : "days", "seconds", "microseconds", "milliseconds",
2515 : : "minutes", "hours", "weeks", NULL
2516 : : };
2517 : :
2518 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__",
2519 : : keywords,
2520 : : &day, &second, &us,
2521 : : &ms, &minute, &hour, &week) == 0)
2522 : 0 : goto Done;
2523 : :
2524 : 0 : x = PyLong_FromLong(0);
2525 [ # # ]: 0 : if (x == NULL)
2526 : 0 : goto Done;
2527 : :
2528 : : #define CLEANUP \
2529 : : Py_DECREF(x); \
2530 : : x = y; \
2531 : : if (x == NULL) \
2532 : : goto Done
2533 : :
2534 [ # # ]: 0 : if (us) {
2535 : 0 : y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
2536 [ # # ]: 0 : CLEANUP;
2537 : : }
2538 [ # # ]: 0 : if (ms) {
2539 : 0 : y = accum("milliseconds", x, ms, us_per_ms, &leftover_us);
2540 [ # # ]: 0 : CLEANUP;
2541 : : }
2542 [ # # ]: 0 : if (second) {
2543 : 0 : y = accum("seconds", x, second, us_per_second, &leftover_us);
2544 [ # # ]: 0 : CLEANUP;
2545 : : }
2546 [ # # ]: 0 : if (minute) {
2547 : 0 : y = accum("minutes", x, minute, us_per_minute, &leftover_us);
2548 [ # # ]: 0 : CLEANUP;
2549 : : }
2550 [ # # ]: 0 : if (hour) {
2551 : 0 : y = accum("hours", x, hour, us_per_hour, &leftover_us);
2552 [ # # ]: 0 : CLEANUP;
2553 : : }
2554 [ # # ]: 0 : if (day) {
2555 : 0 : y = accum("days", x, day, us_per_day, &leftover_us);
2556 [ # # ]: 0 : CLEANUP;
2557 : : }
2558 [ # # ]: 0 : if (week) {
2559 : 0 : y = accum("weeks", x, week, us_per_week, &leftover_us);
2560 [ # # ]: 0 : CLEANUP;
2561 : : }
2562 [ # # ]: 0 : if (leftover_us) {
2563 : : /* Round to nearest whole # of us, and add into x. */
2564 : 0 : double whole_us = round(leftover_us);
2565 : : int x_is_odd;
2566 : : PyObject *temp;
2567 : :
2568 [ # # ]: 0 : if (fabs(whole_us - leftover_us) == 0.5) {
2569 : : /* We're exactly halfway between two integers. In order
2570 : : * to do round-half-to-even, we must determine whether x
2571 : : * is odd. Note that x is odd when it's last bit is 1. The
2572 : : * code below uses bitwise and operation to check the last
2573 : : * bit. */
2574 : 0 : temp = PyNumber_And(x, _PyLong_GetOne()); /* temp <- x & 1 */
2575 [ # # ]: 0 : if (temp == NULL) {
2576 : 0 : Py_DECREF(x);
2577 : 0 : goto Done;
2578 : : }
2579 : 0 : x_is_odd = PyObject_IsTrue(temp);
2580 : 0 : Py_DECREF(temp);
2581 [ # # ]: 0 : if (x_is_odd == -1) {
2582 : 0 : Py_DECREF(x);
2583 : 0 : goto Done;
2584 : : }
2585 : 0 : whole_us = 2.0 * round((leftover_us + x_is_odd) * 0.5) - x_is_odd;
2586 : : }
2587 : :
2588 : 0 : temp = PyLong_FromLong((long)whole_us);
2589 : :
2590 [ # # ]: 0 : if (temp == NULL) {
2591 : 0 : Py_DECREF(x);
2592 : 0 : goto Done;
2593 : : }
2594 : 0 : y = PyNumber_Add(x, temp);
2595 : 0 : Py_DECREF(temp);
2596 [ # # ]: 0 : CLEANUP;
2597 : : }
2598 : :
2599 : 0 : self = microseconds_to_delta_ex(x, type);
2600 : 0 : Py_DECREF(x);
2601 : 0 : Done:
2602 : 0 : return self;
2603 : :
2604 : : #undef CLEANUP
2605 : : }
2606 : :
2607 : : static int
2608 : 0 : delta_bool(PyDateTime_Delta *self)
2609 : : {
2610 : 0 : return (GET_TD_DAYS(self) != 0
2611 [ # # ]: 0 : || GET_TD_SECONDS(self) != 0
2612 [ # # # # ]: 0 : || GET_TD_MICROSECONDS(self) != 0);
2613 : : }
2614 : :
2615 : : static PyObject *
2616 : 0 : delta_repr(PyDateTime_Delta *self)
2617 : : {
2618 : 0 : PyObject *args = PyUnicode_FromString("");
2619 : :
2620 [ # # ]: 0 : if (args == NULL) {
2621 : 0 : return NULL;
2622 : : }
2623 : :
2624 : 0 : const char *sep = "";
2625 : :
2626 [ # # ]: 0 : if (GET_TD_DAYS(self) != 0) {
2627 : 0 : Py_SETREF(args, PyUnicode_FromFormat("days=%d", GET_TD_DAYS(self)));
2628 [ # # ]: 0 : if (args == NULL) {
2629 : 0 : return NULL;
2630 : : }
2631 : 0 : sep = ", ";
2632 : : }
2633 : :
2634 [ # # ]: 0 : if (GET_TD_SECONDS(self) != 0) {
2635 : 0 : Py_SETREF(args, PyUnicode_FromFormat("%U%sseconds=%d", args, sep,
2636 : : GET_TD_SECONDS(self)));
2637 [ # # ]: 0 : if (args == NULL) {
2638 : 0 : return NULL;
2639 : : }
2640 : 0 : sep = ", ";
2641 : : }
2642 : :
2643 [ # # ]: 0 : if (GET_TD_MICROSECONDS(self) != 0) {
2644 : 0 : Py_SETREF(args, PyUnicode_FromFormat("%U%smicroseconds=%d", args, sep,
2645 : : GET_TD_MICROSECONDS(self)));
2646 [ # # ]: 0 : if (args == NULL) {
2647 : 0 : return NULL;
2648 : : }
2649 : : }
2650 : :
2651 [ # # ]: 0 : if (PyUnicode_GET_LENGTH(args) == 0) {
2652 : 0 : Py_SETREF(args, PyUnicode_FromString("0"));
2653 [ # # ]: 0 : if (args == NULL) {
2654 : 0 : return NULL;
2655 : : }
2656 : : }
2657 : :
2658 : 0 : PyObject *repr = PyUnicode_FromFormat("%s(%S)", Py_TYPE(self)->tp_name,
2659 : : args);
2660 : 0 : Py_DECREF(args);
2661 : 0 : return repr;
2662 : : }
2663 : :
2664 : : static PyObject *
2665 : 0 : delta_str(PyDateTime_Delta *self)
2666 : : {
2667 : 0 : int us = GET_TD_MICROSECONDS(self);
2668 : 0 : int seconds = GET_TD_SECONDS(self);
2669 : 0 : int minutes = divmod(seconds, 60, &seconds);
2670 : 0 : int hours = divmod(minutes, 60, &minutes);
2671 : 0 : int days = GET_TD_DAYS(self);
2672 : :
2673 [ # # ]: 0 : if (days) {
2674 [ # # ]: 0 : if (us)
2675 [ # # ]: 0 : return PyUnicode_FromFormat("%d day%s, %d:%02d:%02d.%06d",
2676 [ # # ]: 0 : days, (days == 1 || days == -1) ? "" : "s",
2677 : : hours, minutes, seconds, us);
2678 : : else
2679 [ # # ]: 0 : return PyUnicode_FromFormat("%d day%s, %d:%02d:%02d",
2680 [ # # ]: 0 : days, (days == 1 || days == -1) ? "" : "s",
2681 : : hours, minutes, seconds);
2682 : : } else {
2683 [ # # ]: 0 : if (us)
2684 : 0 : return PyUnicode_FromFormat("%d:%02d:%02d.%06d",
2685 : : hours, minutes, seconds, us);
2686 : : else
2687 : 0 : return PyUnicode_FromFormat("%d:%02d:%02d",
2688 : : hours, minutes, seconds);
2689 : : }
2690 : :
2691 : : }
2692 : :
2693 : : /* Pickle support, a simple use of __reduce__. */
2694 : :
2695 : : /* __getstate__ isn't exposed */
2696 : : static PyObject *
2697 : 0 : delta_getstate(PyDateTime_Delta *self)
2698 : : {
2699 : 0 : return Py_BuildValue("iii", GET_TD_DAYS(self),
2700 : : GET_TD_SECONDS(self),
2701 : : GET_TD_MICROSECONDS(self));
2702 : : }
2703 : :
2704 : : static PyObject *
2705 : 0 : delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored))
2706 : : {
2707 : : PyObject *total_seconds;
2708 : : PyObject *total_microseconds;
2709 : :
2710 : 0 : total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self);
2711 [ # # ]: 0 : if (total_microseconds == NULL)
2712 : 0 : return NULL;
2713 : :
2714 : 0 : total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second);
2715 : :
2716 : 0 : Py_DECREF(total_microseconds);
2717 : 0 : return total_seconds;
2718 : : }
2719 : :
2720 : : static PyObject *
2721 : 0 : delta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored))
2722 : : {
2723 : 0 : return Py_BuildValue("ON", Py_TYPE(self), delta_getstate(self));
2724 : : }
2725 : :
2726 : : #define OFFSET(field) offsetof(PyDateTime_Delta, field)
2727 : :
2728 : : static PyMemberDef delta_members[] = {
2729 : :
2730 : : {"days", T_INT, OFFSET(days), READONLY,
2731 : : PyDoc_STR("Number of days.")},
2732 : :
2733 : : {"seconds", T_INT, OFFSET(seconds), READONLY,
2734 : : PyDoc_STR("Number of seconds (>= 0 and less than 1 day).")},
2735 : :
2736 : : {"microseconds", T_INT, OFFSET(microseconds), READONLY,
2737 : : PyDoc_STR("Number of microseconds (>= 0 and less than 1 second).")},
2738 : : {NULL}
2739 : : };
2740 : :
2741 : : static PyMethodDef delta_methods[] = {
2742 : : {"total_seconds", delta_total_seconds, METH_NOARGS,
2743 : : PyDoc_STR("Total seconds in the duration.")},
2744 : :
2745 : : {"__reduce__", (PyCFunction)delta_reduce, METH_NOARGS,
2746 : : PyDoc_STR("__reduce__() -> (cls, state)")},
2747 : :
2748 : : {NULL, NULL},
2749 : : };
2750 : :
2751 : : static const char delta_doc[] =
2752 : : PyDoc_STR("Difference between two datetime values.\n\n"
2753 : : "timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, "
2754 : : "minutes=0, hours=0, weeks=0)\n\n"
2755 : : "All arguments are optional and default to 0.\n"
2756 : : "Arguments may be integers or floats, and may be positive or negative.");
2757 : :
2758 : : static PyNumberMethods delta_as_number = {
2759 : : delta_add, /* nb_add */
2760 : : delta_subtract, /* nb_subtract */
2761 : : delta_multiply, /* nb_multiply */
2762 : : delta_remainder, /* nb_remainder */
2763 : : delta_divmod, /* nb_divmod */
2764 : : 0, /* nb_power */
2765 : : (unaryfunc)delta_negative, /* nb_negative */
2766 : : (unaryfunc)delta_positive, /* nb_positive */
2767 : : (unaryfunc)delta_abs, /* nb_absolute */
2768 : : (inquiry)delta_bool, /* nb_bool */
2769 : : 0, /*nb_invert*/
2770 : : 0, /*nb_lshift*/
2771 : : 0, /*nb_rshift*/
2772 : : 0, /*nb_and*/
2773 : : 0, /*nb_xor*/
2774 : : 0, /*nb_or*/
2775 : : 0, /*nb_int*/
2776 : : 0, /*nb_reserved*/
2777 : : 0, /*nb_float*/
2778 : : 0, /*nb_inplace_add*/
2779 : : 0, /*nb_inplace_subtract*/
2780 : : 0, /*nb_inplace_multiply*/
2781 : : 0, /*nb_inplace_remainder*/
2782 : : 0, /*nb_inplace_power*/
2783 : : 0, /*nb_inplace_lshift*/
2784 : : 0, /*nb_inplace_rshift*/
2785 : : 0, /*nb_inplace_and*/
2786 : : 0, /*nb_inplace_xor*/
2787 : : 0, /*nb_inplace_or*/
2788 : : delta_divide, /* nb_floor_divide */
2789 : : delta_truedivide, /* nb_true_divide */
2790 : : 0, /* nb_inplace_floor_divide */
2791 : : 0, /* nb_inplace_true_divide */
2792 : : };
2793 : :
2794 : : static PyTypeObject PyDateTime_DeltaType = {
2795 : : PyVarObject_HEAD_INIT(NULL, 0)
2796 : : "datetime.timedelta", /* tp_name */
2797 : : sizeof(PyDateTime_Delta), /* tp_basicsize */
2798 : : 0, /* tp_itemsize */
2799 : : 0, /* tp_dealloc */
2800 : : 0, /* tp_vectorcall_offset */
2801 : : 0, /* tp_getattr */
2802 : : 0, /* tp_setattr */
2803 : : 0, /* tp_as_async */
2804 : : (reprfunc)delta_repr, /* tp_repr */
2805 : : &delta_as_number, /* tp_as_number */
2806 : : 0, /* tp_as_sequence */
2807 : : 0, /* tp_as_mapping */
2808 : : (hashfunc)delta_hash, /* tp_hash */
2809 : : 0, /* tp_call */
2810 : : (reprfunc)delta_str, /* tp_str */
2811 : : PyObject_GenericGetAttr, /* tp_getattro */
2812 : : 0, /* tp_setattro */
2813 : : 0, /* tp_as_buffer */
2814 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
2815 : : delta_doc, /* tp_doc */
2816 : : 0, /* tp_traverse */
2817 : : 0, /* tp_clear */
2818 : : delta_richcompare, /* tp_richcompare */
2819 : : 0, /* tp_weaklistoffset */
2820 : : 0, /* tp_iter */
2821 : : 0, /* tp_iternext */
2822 : : delta_methods, /* tp_methods */
2823 : : delta_members, /* tp_members */
2824 : : 0, /* tp_getset */
2825 : : 0, /* tp_base */
2826 : : 0, /* tp_dict */
2827 : : 0, /* tp_descr_get */
2828 : : 0, /* tp_descr_set */
2829 : : 0, /* tp_dictoffset */
2830 : : 0, /* tp_init */
2831 : : 0, /* tp_alloc */
2832 : : delta_new, /* tp_new */
2833 : : 0, /* tp_free */
2834 : : };
2835 : :
2836 : : /*
2837 : : * PyDateTime_Date implementation.
2838 : : */
2839 : :
2840 : : /* Accessor properties. */
2841 : :
2842 : : static PyObject *
2843 : 0 : date_year(PyDateTime_Date *self, void *unused)
2844 : : {
2845 : 0 : return PyLong_FromLong(GET_YEAR(self));
2846 : : }
2847 : :
2848 : : static PyObject *
2849 : 0 : date_month(PyDateTime_Date *self, void *unused)
2850 : : {
2851 : 0 : return PyLong_FromLong(GET_MONTH(self));
2852 : : }
2853 : :
2854 : : static PyObject *
2855 : 0 : date_day(PyDateTime_Date *self, void *unused)
2856 : : {
2857 : 0 : return PyLong_FromLong(GET_DAY(self));
2858 : : }
2859 : :
2860 : : static PyGetSetDef date_getset[] = {
2861 : : {"year", (getter)date_year},
2862 : : {"month", (getter)date_month},
2863 : : {"day", (getter)date_day},
2864 : : {NULL}
2865 : : };
2866 : :
2867 : : /* Constructors. */
2868 : :
2869 : : static char *date_kws[] = {"year", "month", "day", NULL};
2870 : :
2871 : : static PyObject *
2872 : 0 : date_from_pickle(PyTypeObject *type, PyObject *state)
2873 : : {
2874 : : PyDateTime_Date *me;
2875 : :
2876 : 0 : me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
2877 [ # # ]: 0 : if (me != NULL) {
2878 : 0 : const char *pdata = PyBytes_AS_STRING(state);
2879 : 0 : memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
2880 : 0 : me->hashcode = -1;
2881 : : }
2882 : 0 : return (PyObject *)me;
2883 : : }
2884 : :
2885 : : static PyObject *
2886 : 0 : date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
2887 : : {
2888 : 0 : PyObject *self = NULL;
2889 : : int year;
2890 : : int month;
2891 : : int day;
2892 : :
2893 : : /* Check for invocation from pickle with __getstate__ state */
2894 [ # # ]: 0 : if (PyTuple_GET_SIZE(args) == 1) {
2895 : 0 : PyObject *state = PyTuple_GET_ITEM(args, 0);
2896 [ # # ]: 0 : if (PyBytes_Check(state)) {
2897 [ # # ]: 0 : if (PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
2898 [ # # ]: 0 : MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
2899 : : {
2900 : 0 : return date_from_pickle(type, state);
2901 : : }
2902 : : }
2903 [ # # ]: 0 : else if (PyUnicode_Check(state)) {
2904 [ # # ]: 0 : if (PyUnicode_READY(state)) {
2905 : 0 : return NULL;
2906 : : }
2907 [ # # ]: 0 : if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATE_DATASIZE &&
2908 [ # # ]: 0 : MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2)))
2909 : : {
2910 : 0 : state = PyUnicode_AsLatin1String(state);
2911 [ # # ]: 0 : if (state == NULL) {
2912 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
2913 : : /* More informative error message. */
2914 : 0 : PyErr_SetString(PyExc_ValueError,
2915 : : "Failed to encode latin1 string when unpickling "
2916 : : "a date object. "
2917 : : "pickle.load(data, encoding='latin1') is assumed.");
2918 : : }
2919 : 0 : return NULL;
2920 : : }
2921 : 0 : self = date_from_pickle(type, state);
2922 : 0 : Py_DECREF(state);
2923 : 0 : return self;
2924 : : }
2925 : : }
2926 : : }
2927 : :
2928 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws,
2929 : : &year, &month, &day)) {
2930 : 0 : self = new_date_ex(year, month, day, type);
2931 : : }
2932 : 0 : return self;
2933 : : }
2934 : :
2935 : : static PyObject *
2936 : 0 : date_fromtimestamp(PyObject *cls, PyObject *obj)
2937 : : {
2938 : : struct tm tm;
2939 : : time_t t;
2940 : :
2941 [ # # ]: 0 : if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_FLOOR) == -1)
2942 : 0 : return NULL;
2943 : :
2944 [ # # ]: 0 : if (_PyTime_localtime(t, &tm) != 0)
2945 : 0 : return NULL;
2946 : :
2947 : 0 : return new_date_subclass_ex(tm.tm_year + 1900,
2948 : 0 : tm.tm_mon + 1,
2949 : : tm.tm_mday,
2950 : : cls);
2951 : : }
2952 : :
2953 : : /* Return new date from current time.
2954 : : * We say this is equivalent to fromtimestamp(time.time()), and the
2955 : : * only way to be sure of that is to *call* time.time(). That's not
2956 : : * generally the same as calling C's time.
2957 : : */
2958 : : static PyObject *
2959 : 0 : date_today(PyObject *cls, PyObject *dummy)
2960 : : {
2961 : : PyObject *time;
2962 : : PyObject *result;
2963 : 0 : time = time_time();
2964 [ # # ]: 0 : if (time == NULL)
2965 : 0 : return NULL;
2966 : :
2967 : : /* Note well: today() is a class method, so this may not call
2968 : : * date.fromtimestamp. For example, it may call
2969 : : * datetime.fromtimestamp. That's why we need all the accuracy
2970 : : * time.time() delivers; if someone were gonzo about optimization,
2971 : : * date.today() could get away with plain C time().
2972 : : */
2973 : 0 : result = PyObject_CallMethodOneArg(cls, &_Py_ID(fromtimestamp), time);
2974 : 0 : Py_DECREF(time);
2975 : 0 : return result;
2976 : : }
2977 : :
2978 : : /*[clinic input]
2979 : : @classmethod
2980 : : datetime.date.fromtimestamp
2981 : :
2982 : : timestamp: object
2983 : : /
2984 : :
2985 : : Create a date from a POSIX timestamp.
2986 : :
2987 : : The timestamp is a number, e.g. created via time.time(), that is interpreted
2988 : : as local time.
2989 : : [clinic start generated code]*/
2990 : :
2991 : : static PyObject *
2992 : 0 : datetime_date_fromtimestamp(PyTypeObject *type, PyObject *timestamp)
2993 : : /*[clinic end generated code: output=fd045fda58168869 input=eabb3fe7f40491fe]*/
2994 : : {
2995 : 0 : return date_fromtimestamp((PyObject *) type, timestamp);
2996 : : }
2997 : :
2998 : : /* bpo-36025: This is a wrapper for API compatibility with the public C API,
2999 : : * which expects a function that takes an *args tuple, whereas the argument
3000 : : * clinic generates code that takes METH_O.
3001 : : */
3002 : : static PyObject *
3003 : 0 : datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args)
3004 : : {
3005 : : PyObject *timestamp;
3006 : 0 : PyObject *result = NULL;
3007 : :
3008 [ # # ]: 0 : if (PyArg_UnpackTuple(args, "fromtimestamp", 1, 1, ×tamp)) {
3009 : 0 : result = date_fromtimestamp(cls, timestamp);
3010 : : }
3011 : :
3012 : 0 : return result;
3013 : : }
3014 : :
3015 : : /* Return new date from proleptic Gregorian ordinal. Raises ValueError if
3016 : : * the ordinal is out of range.
3017 : : */
3018 : : static PyObject *
3019 : 0 : date_fromordinal(PyObject *cls, PyObject *args)
3020 : : {
3021 : 0 : PyObject *result = NULL;
3022 : : int ordinal;
3023 : :
3024 [ # # ]: 0 : if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) {
3025 : : int year;
3026 : : int month;
3027 : : int day;
3028 : :
3029 [ # # ]: 0 : if (ordinal < 1)
3030 : 0 : PyErr_SetString(PyExc_ValueError, "ordinal must be "
3031 : : ">= 1");
3032 : : else {
3033 : 0 : ord_to_ymd(ordinal, &year, &month, &day);
3034 : 0 : result = new_date_subclass_ex(year, month, day, cls);
3035 : : }
3036 : : }
3037 : 0 : return result;
3038 : : }
3039 : :
3040 : : /* Return the new date from a string as generated by date.isoformat() */
3041 : : static PyObject *
3042 : 0 : date_fromisoformat(PyObject *cls, PyObject *dtstr)
3043 : : {
3044 : : assert(dtstr != NULL);
3045 : :
3046 [ # # ]: 0 : if (!PyUnicode_Check(dtstr)) {
3047 : 0 : PyErr_SetString(PyExc_TypeError,
3048 : : "fromisoformat: argument must be str");
3049 : 0 : return NULL;
3050 : : }
3051 : :
3052 : : Py_ssize_t len;
3053 : :
3054 : 0 : const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
3055 [ # # ]: 0 : if (dt_ptr == NULL) {
3056 : 0 : goto invalid_string_error;
3057 : : }
3058 : :
3059 : 0 : int year = 0, month = 0, day = 0;
3060 : :
3061 : : int rv;
3062 [ # # # # : 0 : if (len == 7 || len == 8 || len == 10) {
# # ]
3063 : 0 : rv = parse_isoformat_date(dt_ptr, len, &year, &month, &day);
3064 : : }
3065 : : else {
3066 : 0 : rv = -1;
3067 : : }
3068 : :
3069 [ # # ]: 0 : if (rv < 0) {
3070 : 0 : goto invalid_string_error;
3071 : : }
3072 : :
3073 : 0 : return new_date_subclass_ex(year, month, day, cls);
3074 : :
3075 : 0 : invalid_string_error:
3076 : 0 : PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
3077 : 0 : return NULL;
3078 : : }
3079 : :
3080 : :
3081 : : static PyObject *
3082 : 0 : date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw)
3083 : : {
3084 : : static char *keywords[] = {
3085 : : "year", "week", "day", NULL
3086 : : };
3087 : :
3088 : : int year, week, day;
3089 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "iii:fromisocalendar",
3090 : : keywords,
3091 : : &year, &week, &day) == 0) {
3092 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
3093 : 0 : PyErr_Format(PyExc_ValueError,
3094 : : "ISO calendar component out of range");
3095 : :
3096 : : }
3097 : 0 : return NULL;
3098 : : }
3099 : :
3100 : : // Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5)
3101 [ # # # # ]: 0 : if (year < MINYEAR || year > MAXYEAR) {
3102 : 0 : PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year);
3103 : 0 : return NULL;
3104 : : }
3105 : :
3106 : : int month;
3107 : 0 : int rv = iso_to_ymd(year, week, day, &year, &month, &day);
3108 : :
3109 : :
3110 [ # # ]: 0 : if (rv == -2) {
3111 : 0 : PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);
3112 : 0 : return NULL;
3113 : : }
3114 : :
3115 [ # # ]: 0 : if (rv == -3) {
3116 : 0 : PyErr_Format(PyExc_ValueError, "Invalid day: %d (range is [1, 7])",
3117 : : day);
3118 : 0 : return NULL;
3119 : : }
3120 : :
3121 : 0 : return new_date_subclass_ex(year, month, day, cls);
3122 : : }
3123 : :
3124 : :
3125 : : /*
3126 : : * Date arithmetic.
3127 : : */
3128 : :
3129 : : /* date + timedelta -> date. If arg negate is true, subtract the timedelta
3130 : : * instead.
3131 : : */
3132 : : static PyObject *
3133 : 0 : add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate)
3134 : : {
3135 : 0 : PyObject *result = NULL;
3136 : 0 : int year = GET_YEAR(date);
3137 : 0 : int month = GET_MONTH(date);
3138 : 0 : int deltadays = GET_TD_DAYS(delta);
3139 : : /* C-level overflow is impossible because |deltadays| < 1e9. */
3140 [ # # ]: 0 : int day = GET_DAY(date) + (negate ? -deltadays : deltadays);
3141 : :
3142 [ # # ]: 0 : if (normalize_date(&year, &month, &day) >= 0)
3143 : 0 : result = new_date_subclass_ex(year, month, day,
3144 : 0 : (PyObject* )Py_TYPE(date));
3145 : 0 : return result;
3146 : : }
3147 : :
3148 : : static PyObject *
3149 : 0 : date_add(PyObject *left, PyObject *right)
3150 : : {
3151 [ # # # # ]: 0 : if (PyDateTime_Check(left) || PyDateTime_Check(right))
3152 : 0 : Py_RETURN_NOTIMPLEMENTED;
3153 : :
3154 [ # # ]: 0 : if (PyDate_Check(left)) {
3155 : : /* date + ??? */
3156 [ # # ]: 0 : if (PyDelta_Check(right))
3157 : : /* date + delta */
3158 : 0 : return add_date_timedelta((PyDateTime_Date *) left,
3159 : : (PyDateTime_Delta *) right,
3160 : : 0);
3161 : : }
3162 : : else {
3163 : : /* ??? + date
3164 : : * 'right' must be one of us, or we wouldn't have been called
3165 : : */
3166 [ # # ]: 0 : if (PyDelta_Check(left))
3167 : : /* delta + date */
3168 : 0 : return add_date_timedelta((PyDateTime_Date *) right,
3169 : : (PyDateTime_Delta *) left,
3170 : : 0);
3171 : : }
3172 : 0 : Py_RETURN_NOTIMPLEMENTED;
3173 : : }
3174 : :
3175 : : static PyObject *
3176 : 0 : date_subtract(PyObject *left, PyObject *right)
3177 : : {
3178 [ # # # # ]: 0 : if (PyDateTime_Check(left) || PyDateTime_Check(right))
3179 : 0 : Py_RETURN_NOTIMPLEMENTED;
3180 : :
3181 [ # # ]: 0 : if (PyDate_Check(left)) {
3182 [ # # ]: 0 : if (PyDate_Check(right)) {
3183 : : /* date - date */
3184 : 0 : int left_ord = ymd_to_ord(GET_YEAR(left),
3185 : 0 : GET_MONTH(left),
3186 : 0 : GET_DAY(left));
3187 : 0 : int right_ord = ymd_to_ord(GET_YEAR(right),
3188 : 0 : GET_MONTH(right),
3189 : 0 : GET_DAY(right));
3190 : 0 : return new_delta(left_ord - right_ord, 0, 0, 0);
3191 : : }
3192 [ # # ]: 0 : if (PyDelta_Check(right)) {
3193 : : /* date - delta */
3194 : 0 : return add_date_timedelta((PyDateTime_Date *) left,
3195 : : (PyDateTime_Delta *) right,
3196 : : 1);
3197 : : }
3198 : : }
3199 : 0 : Py_RETURN_NOTIMPLEMENTED;
3200 : : }
3201 : :
3202 : :
3203 : : /* Various ways to turn a date into a string. */
3204 : :
3205 : : static PyObject *
3206 : 0 : date_repr(PyDateTime_Date *self)
3207 : : {
3208 : 0 : return PyUnicode_FromFormat("%s(%d, %d, %d)",
3209 : 0 : Py_TYPE(self)->tp_name,
3210 : 0 : GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
3211 : : }
3212 : :
3213 : : static PyObject *
3214 : 0 : date_isoformat(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3215 : : {
3216 : 0 : return PyUnicode_FromFormat("%04d-%02d-%02d",
3217 : 0 : GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
3218 : : }
3219 : :
3220 : : /* str() calls the appropriate isoformat() method. */
3221 : : static PyObject *
3222 : 0 : date_str(PyDateTime_Date *self)
3223 : : {
3224 : 0 : return PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(isoformat));
3225 : : }
3226 : :
3227 : :
3228 : : static PyObject *
3229 : 0 : date_ctime(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3230 : : {
3231 : 0 : return format_ctime(self, 0, 0, 0);
3232 : : }
3233 : :
3234 : : static PyObject *
3235 : 0 : date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw)
3236 : : {
3237 : : /* This method can be inherited, and needs to call the
3238 : : * timetuple() method appropriate to self's class.
3239 : : */
3240 : : PyObject *result;
3241 : : PyObject *tuple;
3242 : : PyObject *format;
3243 : : static char *keywords[] = {"format", NULL};
3244 : :
3245 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords,
3246 : : &format))
3247 : 0 : return NULL;
3248 : :
3249 : 0 : tuple = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(timetuple));
3250 [ # # ]: 0 : if (tuple == NULL)
3251 : 0 : return NULL;
3252 : 0 : result = wrap_strftime((PyObject *)self, format, tuple,
3253 : : (PyObject *)self);
3254 : 0 : Py_DECREF(tuple);
3255 : 0 : return result;
3256 : : }
3257 : :
3258 : : static PyObject *
3259 : 0 : date_format(PyDateTime_Date *self, PyObject *args)
3260 : : {
3261 : : PyObject *format;
3262 : :
3263 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U:__format__", &format))
3264 : 0 : return NULL;
3265 : :
3266 : : /* if the format is zero length, return str(self) */
3267 [ # # ]: 0 : if (PyUnicode_GetLength(format) == 0)
3268 : 0 : return PyObject_Str((PyObject *)self);
3269 : :
3270 : 0 : return PyObject_CallMethodOneArg((PyObject *)self, &_Py_ID(strftime),
3271 : : format);
3272 : : }
3273 : :
3274 : : /* ISO methods. */
3275 : :
3276 : : static PyObject *
3277 : 0 : date_isoweekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3278 : : {
3279 : 0 : int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
3280 : :
3281 : 0 : return PyLong_FromLong(dow + 1);
3282 : : }
3283 : :
3284 : : PyDoc_STRVAR(iso_calendar_date__doc__,
3285 : : "The result of date.isocalendar() or datetime.isocalendar()\n\n\
3286 : : This object may be accessed either as a tuple of\n\
3287 : : ((year, week, weekday)\n\
3288 : : or via the object attributes as named in the above tuple.");
3289 : :
3290 : : typedef struct {
3291 : : PyTupleObject tuple;
3292 : : } PyDateTime_IsoCalendarDate;
3293 : :
3294 : : static PyObject *
3295 : 0 : iso_calendar_date_repr(PyDateTime_IsoCalendarDate *self)
3296 : : {
3297 : 0 : PyObject* year = PyTuple_GetItem((PyObject *)self, 0);
3298 [ # # ]: 0 : if (year == NULL) {
3299 : 0 : return NULL;
3300 : : }
3301 : 0 : PyObject* week = PyTuple_GetItem((PyObject *)self, 1);
3302 [ # # ]: 0 : if (week == NULL) {
3303 : 0 : return NULL;
3304 : : }
3305 : 0 : PyObject* weekday = PyTuple_GetItem((PyObject *)self, 2);
3306 [ # # ]: 0 : if (weekday == NULL) {
3307 : 0 : return NULL;
3308 : : }
3309 : :
3310 : 0 : return PyUnicode_FromFormat("%.200s(year=%S, week=%S, weekday=%S)",
3311 : 0 : Py_TYPE(self)->tp_name, year, week, weekday);
3312 : : }
3313 : :
3314 : : static PyObject *
3315 : 0 : iso_calendar_date_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
3316 : : {
3317 : : // Construct the tuple that this reduces to
3318 : 0 : PyObject * reduce_tuple = Py_BuildValue(
3319 : : "O((OOO))", &PyTuple_Type,
3320 : : PyTuple_GET_ITEM(self, 0),
3321 : : PyTuple_GET_ITEM(self, 1),
3322 : : PyTuple_GET_ITEM(self, 2)
3323 : : );
3324 : :
3325 : 0 : return reduce_tuple;
3326 : : }
3327 : :
3328 : : static PyObject *
3329 : 0 : iso_calendar_date_year(PyDateTime_IsoCalendarDate *self, void *unused)
3330 : : {
3331 : 0 : PyObject *year = PyTuple_GetItem((PyObject *)self, 0);
3332 [ # # ]: 0 : if (year == NULL) {
3333 : 0 : return NULL;
3334 : : }
3335 : 0 : return Py_NewRef(year);
3336 : : }
3337 : :
3338 : : static PyObject *
3339 : 0 : iso_calendar_date_week(PyDateTime_IsoCalendarDate *self, void *unused)
3340 : : {
3341 : 0 : PyObject *week = PyTuple_GetItem((PyObject *)self, 1);
3342 [ # # ]: 0 : if (week == NULL) {
3343 : 0 : return NULL;
3344 : : }
3345 : 0 : return Py_NewRef(week);
3346 : : }
3347 : :
3348 : : static PyObject *
3349 : 0 : iso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused)
3350 : : {
3351 : 0 : PyObject *weekday = PyTuple_GetItem((PyObject *)self, 2);
3352 [ # # ]: 0 : if (weekday == NULL) {
3353 : 0 : return NULL;
3354 : : }
3355 : 0 : return Py_NewRef(weekday);
3356 : : }
3357 : :
3358 : : static PyGetSetDef iso_calendar_date_getset[] = {
3359 : : {"year", (getter)iso_calendar_date_year},
3360 : : {"week", (getter)iso_calendar_date_week},
3361 : : {"weekday", (getter)iso_calendar_date_weekday},
3362 : : {NULL}
3363 : : };
3364 : :
3365 : : static PyMethodDef iso_calendar_date_methods[] = {
3366 : : {"__reduce__", (PyCFunction)iso_calendar_date_reduce, METH_NOARGS,
3367 : : PyDoc_STR("__reduce__() -> (cls, state)")},
3368 : : {NULL, NULL},
3369 : : };
3370 : :
3371 : : static PyTypeObject PyDateTime_IsoCalendarDateType = {
3372 : : PyVarObject_HEAD_INIT(NULL, 0)
3373 : : .tp_name = "datetime.IsoCalendarDate",
3374 : : .tp_basicsize = sizeof(PyDateTime_IsoCalendarDate),
3375 : : .tp_repr = (reprfunc) iso_calendar_date_repr,
3376 : : .tp_flags = Py_TPFLAGS_DEFAULT,
3377 : : .tp_doc = iso_calendar_date__doc__,
3378 : : .tp_methods = iso_calendar_date_methods,
3379 : : .tp_getset = iso_calendar_date_getset,
3380 : : // .tp_base = &PyTuple_Type, // filled in PyInit__datetime
3381 : : .tp_new = iso_calendar_date_new,
3382 : : };
3383 : :
3384 : : /*[clinic input]
3385 : : @classmethod
3386 : : datetime.IsoCalendarDate.__new__ as iso_calendar_date_new
3387 : : year: int
3388 : : week: int
3389 : : weekday: int
3390 : : [clinic start generated code]*/
3391 : :
3392 : : static PyObject *
3393 : 0 : iso_calendar_date_new_impl(PyTypeObject *type, int year, int week,
3394 : : int weekday)
3395 : : /*[clinic end generated code: output=383d33d8dc7183a2 input=4f2c663c9d19c4ee]*/
3396 : :
3397 : : {
3398 : : PyDateTime_IsoCalendarDate *self;
3399 : 0 : self = (PyDateTime_IsoCalendarDate *) type->tp_alloc(type, 3);
3400 [ # # ]: 0 : if (self == NULL) {
3401 : 0 : return NULL;
3402 : : }
3403 : :
3404 : 0 : PyTuple_SET_ITEM(self, 0, PyLong_FromLong(year));
3405 : 0 : PyTuple_SET_ITEM(self, 1, PyLong_FromLong(week));
3406 : 0 : PyTuple_SET_ITEM(self, 2, PyLong_FromLong(weekday));
3407 : :
3408 : 0 : return (PyObject *)self;
3409 : : }
3410 : :
3411 : : static PyObject *
3412 : 0 : date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3413 : : {
3414 : 0 : int year = GET_YEAR(self);
3415 : 0 : int week1_monday = iso_week1_monday(year);
3416 : 0 : int today = ymd_to_ord(year, GET_MONTH(self), GET_DAY(self));
3417 : : int week;
3418 : : int day;
3419 : :
3420 : 0 : week = divmod(today - week1_monday, 7, &day);
3421 [ # # ]: 0 : if (week < 0) {
3422 : 0 : --year;
3423 : 0 : week1_monday = iso_week1_monday(year);
3424 : 0 : week = divmod(today - week1_monday, 7, &day);
3425 : : }
3426 [ # # # # ]: 0 : else if (week >= 52 && today >= iso_week1_monday(year + 1)) {
3427 : 0 : ++year;
3428 : 0 : week = 0;
3429 : : }
3430 : :
3431 : 0 : PyObject* v = iso_calendar_date_new_impl(&PyDateTime_IsoCalendarDateType,
3432 : : year, week + 1, day + 1);
3433 [ # # ]: 0 : if (v == NULL) {
3434 : 0 : return NULL;
3435 : : }
3436 : 0 : return v;
3437 : : }
3438 : :
3439 : : /* Miscellaneous methods. */
3440 : :
3441 : : static PyObject *
3442 : 0 : date_richcompare(PyObject *self, PyObject *other, int op)
3443 : : {
3444 [ # # ]: 0 : if (PyDate_Check(other)) {
3445 : 0 : int diff = memcmp(((PyDateTime_Date *)self)->data,
3446 : 0 : ((PyDateTime_Date *)other)->data,
3447 : : _PyDateTime_DATE_DATASIZE);
3448 : 0 : return diff_to_bool(diff, op);
3449 : : }
3450 : : else
3451 : 0 : Py_RETURN_NOTIMPLEMENTED;
3452 : : }
3453 : :
3454 : : static PyObject *
3455 : 0 : date_timetuple(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3456 : : {
3457 : 0 : return build_struct_time(GET_YEAR(self),
3458 : 0 : GET_MONTH(self),
3459 : 0 : GET_DAY(self),
3460 : : 0, 0, 0, -1);
3461 : : }
3462 : :
3463 : : static PyObject *
3464 : 0 : date_replace(PyDateTime_Date *self, PyObject *args, PyObject *kw)
3465 : : {
3466 : : PyObject *clone;
3467 : : PyObject *tuple;
3468 : 0 : int year = GET_YEAR(self);
3469 : 0 : int month = GET_MONTH(self);
3470 : 0 : int day = GET_DAY(self);
3471 : :
3472 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "|iii:replace", date_kws,
3473 : : &year, &month, &day))
3474 : 0 : return NULL;
3475 : 0 : tuple = Py_BuildValue("iii", year, month, day);
3476 [ # # ]: 0 : if (tuple == NULL)
3477 : 0 : return NULL;
3478 : 0 : clone = date_new(Py_TYPE(self), tuple, NULL);
3479 : 0 : Py_DECREF(tuple);
3480 : 0 : return clone;
3481 : : }
3482 : :
3483 : : static Py_hash_t
3484 : 0 : generic_hash(unsigned char *data, int len)
3485 : : {
3486 : 0 : return _Py_HashBytes(data, len);
3487 : : }
3488 : :
3489 : :
3490 : : static PyObject *date_getstate(PyDateTime_Date *self);
3491 : :
3492 : : static Py_hash_t
3493 : 0 : date_hash(PyDateTime_Date *self)
3494 : : {
3495 [ # # ]: 0 : if (self->hashcode == -1) {
3496 : 0 : self->hashcode = generic_hash(
3497 : 0 : (unsigned char *)self->data, _PyDateTime_DATE_DATASIZE);
3498 : : }
3499 : :
3500 : 0 : return self->hashcode;
3501 : : }
3502 : :
3503 : : static PyObject *
3504 : 0 : date_toordinal(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3505 : : {
3506 : 0 : return PyLong_FromLong(ymd_to_ord(GET_YEAR(self), GET_MONTH(self),
3507 : 0 : GET_DAY(self)));
3508 : : }
3509 : :
3510 : : static PyObject *
3511 : 0 : date_weekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3512 : : {
3513 : 0 : int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
3514 : :
3515 : 0 : return PyLong_FromLong(dow);
3516 : : }
3517 : :
3518 : : /* Pickle support, a simple use of __reduce__. */
3519 : :
3520 : : /* __getstate__ isn't exposed */
3521 : : static PyObject *
3522 : 0 : date_getstate(PyDateTime_Date *self)
3523 : : {
3524 : : PyObject* field;
3525 : 0 : field = PyBytes_FromStringAndSize((char*)self->data,
3526 : : _PyDateTime_DATE_DATASIZE);
3527 : 0 : return Py_BuildValue("(N)", field);
3528 : : }
3529 : :
3530 : : static PyObject *
3531 : 0 : date_reduce(PyDateTime_Date *self, PyObject *arg)
3532 : : {
3533 : 0 : return Py_BuildValue("(ON)", Py_TYPE(self), date_getstate(self));
3534 : : }
3535 : :
3536 : : static PyMethodDef date_methods[] = {
3537 : :
3538 : : /* Class methods: */
3539 : : DATETIME_DATE_FROMTIMESTAMP_METHODDEF
3540 : :
3541 : : {"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS |
3542 : : METH_CLASS,
3543 : : PyDoc_STR("int -> date corresponding to a proleptic Gregorian "
3544 : : "ordinal.")},
3545 : :
3546 : : {"fromisoformat", (PyCFunction)date_fromisoformat, METH_O |
3547 : : METH_CLASS,
3548 : : PyDoc_STR("str -> Construct a date from a string in ISO 8601 format.")},
3549 : :
3550 : : {"fromisocalendar", _PyCFunction_CAST(date_fromisocalendar),
3551 : : METH_VARARGS | METH_KEYWORDS | METH_CLASS,
3552 : : PyDoc_STR("int, int, int -> Construct a date from the ISO year, week "
3553 : : "number and weekday.\n\n"
3554 : : "This is the inverse of the date.isocalendar() function")},
3555 : :
3556 : : {"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS,
3557 : : PyDoc_STR("Current date or datetime: same as "
3558 : : "self.__class__.fromtimestamp(time.time()).")},
3559 : :
3560 : : /* Instance methods: */
3561 : :
3562 : : {"ctime", (PyCFunction)date_ctime, METH_NOARGS,
3563 : : PyDoc_STR("Return ctime() style string.")},
3564 : :
3565 : : {"strftime", _PyCFunction_CAST(date_strftime), METH_VARARGS | METH_KEYWORDS,
3566 : : PyDoc_STR("format -> strftime() style string.")},
3567 : :
3568 : : {"__format__", (PyCFunction)date_format, METH_VARARGS,
3569 : : PyDoc_STR("Formats self with strftime.")},
3570 : :
3571 : : {"timetuple", (PyCFunction)date_timetuple, METH_NOARGS,
3572 : : PyDoc_STR("Return time tuple, compatible with time.localtime().")},
3573 : :
3574 : : {"isocalendar", (PyCFunction)date_isocalendar, METH_NOARGS,
3575 : : PyDoc_STR("Return a named tuple containing ISO year, week number, and "
3576 : : "weekday.")},
3577 : :
3578 : : {"isoformat", (PyCFunction)date_isoformat, METH_NOARGS,
3579 : : PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")},
3580 : :
3581 : : {"isoweekday", (PyCFunction)date_isoweekday, METH_NOARGS,
3582 : : PyDoc_STR("Return the day of the week represented by the date.\n"
3583 : : "Monday == 1 ... Sunday == 7")},
3584 : :
3585 : : {"toordinal", (PyCFunction)date_toordinal, METH_NOARGS,
3586 : : PyDoc_STR("Return proleptic Gregorian ordinal. January 1 of year "
3587 : : "1 is day 1.")},
3588 : :
3589 : : {"weekday", (PyCFunction)date_weekday, METH_NOARGS,
3590 : : PyDoc_STR("Return the day of the week represented by the date.\n"
3591 : : "Monday == 0 ... Sunday == 6")},
3592 : :
3593 : : {"replace", _PyCFunction_CAST(date_replace), METH_VARARGS | METH_KEYWORDS,
3594 : : PyDoc_STR("Return date with new specified fields.")},
3595 : :
3596 : : {"__reduce__", (PyCFunction)date_reduce, METH_NOARGS,
3597 : : PyDoc_STR("__reduce__() -> (cls, state)")},
3598 : :
3599 : : {NULL, NULL}
3600 : : };
3601 : :
3602 : : static const char date_doc[] =
3603 : : PyDoc_STR("date(year, month, day) --> date object");
3604 : :
3605 : : static PyNumberMethods date_as_number = {
3606 : : date_add, /* nb_add */
3607 : : date_subtract, /* nb_subtract */
3608 : : 0, /* nb_multiply */
3609 : : 0, /* nb_remainder */
3610 : : 0, /* nb_divmod */
3611 : : 0, /* nb_power */
3612 : : 0, /* nb_negative */
3613 : : 0, /* nb_positive */
3614 : : 0, /* nb_absolute */
3615 : : 0, /* nb_bool */
3616 : : };
3617 : :
3618 : : static PyTypeObject PyDateTime_DateType = {
3619 : : PyVarObject_HEAD_INIT(NULL, 0)
3620 : : "datetime.date", /* tp_name */
3621 : : sizeof(PyDateTime_Date), /* tp_basicsize */
3622 : : 0, /* tp_itemsize */
3623 : : 0, /* tp_dealloc */
3624 : : 0, /* tp_vectorcall_offset */
3625 : : 0, /* tp_getattr */
3626 : : 0, /* tp_setattr */
3627 : : 0, /* tp_as_async */
3628 : : (reprfunc)date_repr, /* tp_repr */
3629 : : &date_as_number, /* tp_as_number */
3630 : : 0, /* tp_as_sequence */
3631 : : 0, /* tp_as_mapping */
3632 : : (hashfunc)date_hash, /* tp_hash */
3633 : : 0, /* tp_call */
3634 : : (reprfunc)date_str, /* tp_str */
3635 : : PyObject_GenericGetAttr, /* tp_getattro */
3636 : : 0, /* tp_setattro */
3637 : : 0, /* tp_as_buffer */
3638 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
3639 : : date_doc, /* tp_doc */
3640 : : 0, /* tp_traverse */
3641 : : 0, /* tp_clear */
3642 : : date_richcompare, /* tp_richcompare */
3643 : : 0, /* tp_weaklistoffset */
3644 : : 0, /* tp_iter */
3645 : : 0, /* tp_iternext */
3646 : : date_methods, /* tp_methods */
3647 : : 0, /* tp_members */
3648 : : date_getset, /* tp_getset */
3649 : : 0, /* tp_base */
3650 : : 0, /* tp_dict */
3651 : : 0, /* tp_descr_get */
3652 : : 0, /* tp_descr_set */
3653 : : 0, /* tp_dictoffset */
3654 : : 0, /* tp_init */
3655 : : 0, /* tp_alloc */
3656 : : date_new, /* tp_new */
3657 : : 0, /* tp_free */
3658 : : };
3659 : :
3660 : : /*
3661 : : * PyDateTime_TZInfo implementation.
3662 : : */
3663 : :
3664 : : /* This is a pure abstract base class, so doesn't do anything beyond
3665 : : * raising NotImplemented exceptions. Real tzinfo classes need
3666 : : * to derive from this. This is mostly for clarity, and for efficiency in
3667 : : * datetime and time constructors (their tzinfo arguments need to
3668 : : * be subclasses of this tzinfo class, which is easy and quick to check).
3669 : : *
3670 : : * Note: For reasons having to do with pickling of subclasses, we have
3671 : : * to allow tzinfo objects to be instantiated. This wasn't an issue
3672 : : * in the Python implementation (__init__() could raise NotImplementedError
3673 : : * there without ill effect), but doing so in the C implementation hit a
3674 : : * brick wall.
3675 : : */
3676 : :
3677 : : static PyObject *
3678 : 0 : tzinfo_nogo(const char* methodname)
3679 : : {
3680 : 0 : PyErr_Format(PyExc_NotImplementedError,
3681 : : "a tzinfo subclass must implement %s()",
3682 : : methodname);
3683 : 0 : return NULL;
3684 : : }
3685 : :
3686 : : /* Methods. A subclass must implement these. */
3687 : :
3688 : : static PyObject *
3689 : 0 : tzinfo_tzname(PyDateTime_TZInfo *self, PyObject *dt)
3690 : : {
3691 : 0 : return tzinfo_nogo("tzname");
3692 : : }
3693 : :
3694 : : static PyObject *
3695 : 0 : tzinfo_utcoffset(PyDateTime_TZInfo *self, PyObject *dt)
3696 : : {
3697 : 0 : return tzinfo_nogo("utcoffset");
3698 : : }
3699 : :
3700 : : static PyObject *
3701 : 0 : tzinfo_dst(PyDateTime_TZInfo *self, PyObject *dt)
3702 : : {
3703 : 0 : return tzinfo_nogo("dst");
3704 : : }
3705 : :
3706 : :
3707 : : static PyObject *add_datetime_timedelta(PyDateTime_DateTime *date,
3708 : : PyDateTime_Delta *delta,
3709 : : int factor);
3710 : : static PyObject *datetime_utcoffset(PyObject *self, PyObject *);
3711 : : static PyObject *datetime_dst(PyObject *self, PyObject *);
3712 : :
3713 : : static PyObject *
3714 : 0 : tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt)
3715 : : {
3716 : 0 : PyObject *result = NULL;
3717 : 0 : PyObject *off = NULL, *dst = NULL;
3718 : 0 : PyDateTime_Delta *delta = NULL;
3719 : :
3720 [ # # ]: 0 : if (!PyDateTime_Check(dt)) {
3721 : 0 : PyErr_SetString(PyExc_TypeError,
3722 : : "fromutc: argument must be a datetime");
3723 : 0 : return NULL;
3724 : : }
3725 [ # # # # ]: 0 : if (GET_DT_TZINFO(dt) != (PyObject *)self) {
3726 : 0 : PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo "
3727 : : "is not self");
3728 : 0 : return NULL;
3729 : : }
3730 : :
3731 : 0 : off = datetime_utcoffset(dt, NULL);
3732 [ # # ]: 0 : if (off == NULL)
3733 : 0 : return NULL;
3734 [ # # ]: 0 : if (off == Py_None) {
3735 : 0 : PyErr_SetString(PyExc_ValueError, "fromutc: non-None "
3736 : : "utcoffset() result required");
3737 : 0 : goto Fail;
3738 : : }
3739 : :
3740 : 0 : dst = datetime_dst(dt, NULL);
3741 [ # # ]: 0 : if (dst == NULL)
3742 : 0 : goto Fail;
3743 [ # # ]: 0 : if (dst == Py_None) {
3744 : 0 : PyErr_SetString(PyExc_ValueError, "fromutc: non-None "
3745 : : "dst() result required");
3746 : 0 : goto Fail;
3747 : : }
3748 : :
3749 : 0 : delta = (PyDateTime_Delta *)delta_subtract(off, dst);
3750 [ # # ]: 0 : if (delta == NULL)
3751 : 0 : goto Fail;
3752 : 0 : result = add_datetime_timedelta((PyDateTime_DateTime *)dt, delta, 1);
3753 [ # # ]: 0 : if (result == NULL)
3754 : 0 : goto Fail;
3755 : :
3756 : 0 : Py_DECREF(dst);
3757 [ # # ]: 0 : dst = call_dst(GET_DT_TZINFO(dt), result);
3758 [ # # ]: 0 : if (dst == NULL)
3759 : 0 : goto Fail;
3760 [ # # ]: 0 : if (dst == Py_None)
3761 : 0 : goto Inconsistent;
3762 [ # # ]: 0 : if (delta_bool((PyDateTime_Delta *)dst) != 0) {
3763 : 0 : Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result,
3764 : : (PyDateTime_Delta *)dst, 1));
3765 [ # # ]: 0 : if (result == NULL)
3766 : 0 : goto Fail;
3767 : : }
3768 : 0 : Py_DECREF(delta);
3769 : 0 : Py_DECREF(dst);
3770 : 0 : Py_DECREF(off);
3771 : 0 : return result;
3772 : :
3773 : 0 : Inconsistent:
3774 : 0 : PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave "
3775 : : "inconsistent results; cannot convert");
3776 : :
3777 : : /* fall through to failure */
3778 : 0 : Fail:
3779 : 0 : Py_XDECREF(off);
3780 : 0 : Py_XDECREF(dst);
3781 : 0 : Py_XDECREF(delta);
3782 : 0 : Py_XDECREF(result);
3783 : 0 : return NULL;
3784 : : }
3785 : :
3786 : : /*
3787 : : * Pickle support. This is solely so that tzinfo subclasses can use
3788 : : * pickling -- tzinfo itself is supposed to be uninstantiable.
3789 : : */
3790 : :
3791 : : static PyObject *
3792 : 0 : tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
3793 : : {
3794 : : PyObject *args, *state;
3795 : : PyObject *getinitargs;
3796 : :
3797 [ # # ]: 0 : if (_PyObject_LookupAttr(self, &_Py_ID(__getinitargs__), &getinitargs) < 0) {
3798 : 0 : return NULL;
3799 : : }
3800 [ # # ]: 0 : if (getinitargs != NULL) {
3801 : 0 : args = PyObject_CallNoArgs(getinitargs);
3802 : 0 : Py_DECREF(getinitargs);
3803 : : }
3804 : : else {
3805 : 0 : args = PyTuple_New(0);
3806 : : }
3807 [ # # ]: 0 : if (args == NULL) {
3808 : 0 : return NULL;
3809 : : }
3810 : :
3811 : 0 : state = _PyObject_GetState(self);
3812 [ # # ]: 0 : if (state == NULL) {
3813 : 0 : Py_DECREF(args);
3814 : 0 : return NULL;
3815 : : }
3816 : :
3817 : 0 : return Py_BuildValue("(ONN)", Py_TYPE(self), args, state);
3818 : : }
3819 : :
3820 : : static PyMethodDef tzinfo_methods[] = {
3821 : :
3822 : : {"tzname", (PyCFunction)tzinfo_tzname, METH_O,
3823 : : PyDoc_STR("datetime -> string name of time zone.")},
3824 : :
3825 : : {"utcoffset", (PyCFunction)tzinfo_utcoffset, METH_O,
3826 : : PyDoc_STR("datetime -> timedelta showing offset from UTC, negative "
3827 : : "values indicating West of UTC")},
3828 : :
3829 : : {"dst", (PyCFunction)tzinfo_dst, METH_O,
3830 : : PyDoc_STR("datetime -> DST offset as timedelta positive east of UTC.")},
3831 : :
3832 : : {"fromutc", (PyCFunction)tzinfo_fromutc, METH_O,
3833 : : PyDoc_STR("datetime in UTC -> datetime in local time.")},
3834 : :
3835 : : {"__reduce__", tzinfo_reduce, METH_NOARGS,
3836 : : PyDoc_STR("-> (cls, state)")},
3837 : :
3838 : : {NULL, NULL}
3839 : : };
3840 : :
3841 : : static const char tzinfo_doc[] =
3842 : : PyDoc_STR("Abstract base class for time zone info objects.");
3843 : :
3844 : : static PyTypeObject PyDateTime_TZInfoType = {
3845 : : PyVarObject_HEAD_INIT(NULL, 0)
3846 : : "datetime.tzinfo", /* tp_name */
3847 : : sizeof(PyDateTime_TZInfo), /* tp_basicsize */
3848 : : 0, /* tp_itemsize */
3849 : : 0, /* tp_dealloc */
3850 : : 0, /* tp_vectorcall_offset */
3851 : : 0, /* tp_getattr */
3852 : : 0, /* tp_setattr */
3853 : : 0, /* tp_as_async */
3854 : : 0, /* tp_repr */
3855 : : 0, /* tp_as_number */
3856 : : 0, /* tp_as_sequence */
3857 : : 0, /* tp_as_mapping */
3858 : : 0, /* tp_hash */
3859 : : 0, /* tp_call */
3860 : : 0, /* tp_str */
3861 : : PyObject_GenericGetAttr, /* tp_getattro */
3862 : : 0, /* tp_setattro */
3863 : : 0, /* tp_as_buffer */
3864 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
3865 : : tzinfo_doc, /* tp_doc */
3866 : : 0, /* tp_traverse */
3867 : : 0, /* tp_clear */
3868 : : 0, /* tp_richcompare */
3869 : : 0, /* tp_weaklistoffset */
3870 : : 0, /* tp_iter */
3871 : : 0, /* tp_iternext */
3872 : : tzinfo_methods, /* tp_methods */
3873 : : 0, /* tp_members */
3874 : : 0, /* tp_getset */
3875 : : 0, /* tp_base */
3876 : : 0, /* tp_dict */
3877 : : 0, /* tp_descr_get */
3878 : : 0, /* tp_descr_set */
3879 : : 0, /* tp_dictoffset */
3880 : : 0, /* tp_init */
3881 : : 0, /* tp_alloc */
3882 : : PyType_GenericNew, /* tp_new */
3883 : : 0, /* tp_free */
3884 : : };
3885 : :
3886 : : static char *timezone_kws[] = {"offset", "name", NULL};
3887 : :
3888 : : static PyObject *
3889 : 0 : timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw)
3890 : : {
3891 : : PyObject *offset;
3892 : 0 : PyObject *name = NULL;
3893 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws,
3894 : : &PyDateTime_DeltaType, &offset, &name))
3895 : 0 : return new_timezone(offset, name);
3896 : :
3897 : 0 : return NULL;
3898 : : }
3899 : :
3900 : : static void
3901 : 0 : timezone_dealloc(PyDateTime_TimeZone *self)
3902 : : {
3903 [ # # ]: 0 : Py_CLEAR(self->offset);
3904 [ # # ]: 0 : Py_CLEAR(self->name);
3905 : 0 : Py_TYPE(self)->tp_free((PyObject *)self);
3906 : 0 : }
3907 : :
3908 : : static PyObject *
3909 : 0 : timezone_richcompare(PyDateTime_TimeZone *self,
3910 : : PyDateTime_TimeZone *other, int op)
3911 : : {
3912 [ # # # # ]: 0 : if (op != Py_EQ && op != Py_NE)
3913 : 0 : Py_RETURN_NOTIMPLEMENTED;
3914 [ # # ]: 0 : if (!PyTimezone_Check(other)) {
3915 : 0 : Py_RETURN_NOTIMPLEMENTED;
3916 : : }
3917 : 0 : return delta_richcompare(self->offset, other->offset, op);
3918 : : }
3919 : :
3920 : : static Py_hash_t
3921 : 0 : timezone_hash(PyDateTime_TimeZone *self)
3922 : : {
3923 : 0 : return delta_hash((PyDateTime_Delta *)self->offset);
3924 : : }
3925 : :
3926 : : /* Check argument type passed to tzname, utcoffset, or dst methods.
3927 : : Returns 0 for good argument. Returns -1 and sets exception info
3928 : : otherwise.
3929 : : */
3930 : : static int
3931 : 0 : _timezone_check_argument(PyObject *dt, const char *meth)
3932 : : {
3933 [ # # # # ]: 0 : if (dt == Py_None || PyDateTime_Check(dt))
3934 : 0 : return 0;
3935 : 0 : PyErr_Format(PyExc_TypeError, "%s(dt) argument must be a datetime instance"
3936 : 0 : " or None, not %.200s", meth, Py_TYPE(dt)->tp_name);
3937 : 0 : return -1;
3938 : : }
3939 : :
3940 : : static PyObject *
3941 : 0 : timezone_repr(PyDateTime_TimeZone *self)
3942 : : {
3943 : : /* Note that although timezone is not subclassable, it is convenient
3944 : : to use Py_TYPE(self)->tp_name here. */
3945 : 0 : const char *type_name = Py_TYPE(self)->tp_name;
3946 : :
3947 [ # # ]: 0 : if (((PyObject *)self) == PyDateTime_TimeZone_UTC)
3948 : 0 : return PyUnicode_FromFormat("%s.utc", type_name);
3949 : :
3950 [ # # ]: 0 : if (self->name == NULL)
3951 : 0 : return PyUnicode_FromFormat("%s(%R)", type_name, self->offset);
3952 : :
3953 : 0 : return PyUnicode_FromFormat("%s(%R, %R)", type_name, self->offset,
3954 : : self->name);
3955 : : }
3956 : :
3957 : :
3958 : : static PyObject *
3959 : 0 : timezone_str(PyDateTime_TimeZone *self)
3960 : : {
3961 : : int hours, minutes, seconds, microseconds;
3962 : : PyObject *offset;
3963 : : char sign;
3964 : :
3965 [ # # ]: 0 : if (self->name != NULL) {
3966 : 0 : return Py_NewRef(self->name);
3967 : : }
3968 [ # # ]: 0 : if ((PyObject *)self == PyDateTime_TimeZone_UTC ||
3969 [ # # ]: 0 : (GET_TD_DAYS(self->offset) == 0 &&
3970 [ # # ]: 0 : GET_TD_SECONDS(self->offset) == 0 &&
3971 [ # # ]: 0 : GET_TD_MICROSECONDS(self->offset) == 0))
3972 : 0 : return PyUnicode_FromString("UTC");
3973 : : /* Offset is normalized, so it is negative if days < 0 */
3974 [ # # ]: 0 : if (GET_TD_DAYS(self->offset) < 0) {
3975 : 0 : sign = '-';
3976 : 0 : offset = delta_negative((PyDateTime_Delta *)self->offset);
3977 [ # # ]: 0 : if (offset == NULL)
3978 : 0 : return NULL;
3979 : : }
3980 : : else {
3981 : 0 : sign = '+';
3982 : 0 : offset = Py_NewRef(self->offset);
3983 : : }
3984 : : /* Offset is not negative here. */
3985 : 0 : microseconds = GET_TD_MICROSECONDS(offset);
3986 : 0 : seconds = GET_TD_SECONDS(offset);
3987 : 0 : Py_DECREF(offset);
3988 : 0 : minutes = divmod(seconds, 60, &seconds);
3989 : 0 : hours = divmod(minutes, 60, &minutes);
3990 [ # # ]: 0 : if (microseconds != 0) {
3991 : 0 : return PyUnicode_FromFormat("UTC%c%02d:%02d:%02d.%06d",
3992 : : sign, hours, minutes,
3993 : : seconds, microseconds);
3994 : : }
3995 [ # # ]: 0 : if (seconds != 0) {
3996 : 0 : return PyUnicode_FromFormat("UTC%c%02d:%02d:%02d",
3997 : : sign, hours, minutes, seconds);
3998 : : }
3999 : 0 : return PyUnicode_FromFormat("UTC%c%02d:%02d", sign, hours, minutes);
4000 : : }
4001 : :
4002 : : static PyObject *
4003 : 0 : timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt)
4004 : : {
4005 [ # # ]: 0 : if (_timezone_check_argument(dt, "tzname") == -1)
4006 : 0 : return NULL;
4007 : :
4008 : 0 : return timezone_str(self);
4009 : : }
4010 : :
4011 : : static PyObject *
4012 : 0 : timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt)
4013 : : {
4014 [ # # ]: 0 : if (_timezone_check_argument(dt, "utcoffset") == -1)
4015 : 0 : return NULL;
4016 : :
4017 : 0 : return Py_NewRef(self->offset);
4018 : : }
4019 : :
4020 : : static PyObject *
4021 : 0 : timezone_dst(PyObject *self, PyObject *dt)
4022 : : {
4023 [ # # ]: 0 : if (_timezone_check_argument(dt, "dst") == -1)
4024 : 0 : return NULL;
4025 : :
4026 : 0 : Py_RETURN_NONE;
4027 : : }
4028 : :
4029 : : static PyObject *
4030 : 0 : timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt)
4031 : : {
4032 [ # # ]: 0 : if (!PyDateTime_Check(dt)) {
4033 : 0 : PyErr_SetString(PyExc_TypeError,
4034 : : "fromutc: argument must be a datetime");
4035 : 0 : return NULL;
4036 : : }
4037 [ # # # # ]: 0 : if (!HASTZINFO(dt) || dt->tzinfo != (PyObject *)self) {
4038 : 0 : PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo "
4039 : : "is not self");
4040 : 0 : return NULL;
4041 : : }
4042 : :
4043 : 0 : return add_datetime_timedelta(dt, (PyDateTime_Delta *)self->offset, 1);
4044 : : }
4045 : :
4046 : : static PyObject *
4047 : 0 : timezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored))
4048 : : {
4049 [ # # ]: 0 : if (self->name == NULL)
4050 : 0 : return Py_BuildValue("(O)", self->offset);
4051 : 0 : return Py_BuildValue("(OO)", self->offset, self->name);
4052 : : }
4053 : :
4054 : : static PyMethodDef timezone_methods[] = {
4055 : : {"tzname", (PyCFunction)timezone_tzname, METH_O,
4056 : : PyDoc_STR("If name is specified when timezone is created, returns the name."
4057 : : " Otherwise returns offset as 'UTC(+|-)HH:MM'.")},
4058 : :
4059 : : {"utcoffset", (PyCFunction)timezone_utcoffset, METH_O,
4060 : : PyDoc_STR("Return fixed offset.")},
4061 : :
4062 : : {"dst", (PyCFunction)timezone_dst, METH_O,
4063 : : PyDoc_STR("Return None.")},
4064 : :
4065 : : {"fromutc", (PyCFunction)timezone_fromutc, METH_O,
4066 : : PyDoc_STR("datetime in UTC -> datetime in local time.")},
4067 : :
4068 : : {"__getinitargs__", (PyCFunction)timezone_getinitargs, METH_NOARGS,
4069 : : PyDoc_STR("pickle support")},
4070 : :
4071 : : {NULL, NULL}
4072 : : };
4073 : :
4074 : : static const char timezone_doc[] =
4075 : : PyDoc_STR("Fixed offset from UTC implementation of tzinfo.");
4076 : :
4077 : : static PyTypeObject PyDateTime_TimeZoneType = {
4078 : : PyVarObject_HEAD_INIT(NULL, 0)
4079 : : "datetime.timezone", /* tp_name */
4080 : : sizeof(PyDateTime_TimeZone), /* tp_basicsize */
4081 : : 0, /* tp_itemsize */
4082 : : (destructor)timezone_dealloc, /* tp_dealloc */
4083 : : 0, /* tp_vectorcall_offset */
4084 : : 0, /* tp_getattr */
4085 : : 0, /* tp_setattr */
4086 : : 0, /* tp_as_async */
4087 : : (reprfunc)timezone_repr, /* tp_repr */
4088 : : 0, /* tp_as_number */
4089 : : 0, /* tp_as_sequence */
4090 : : 0, /* tp_as_mapping */
4091 : : (hashfunc)timezone_hash, /* tp_hash */
4092 : : 0, /* tp_call */
4093 : : (reprfunc)timezone_str, /* tp_str */
4094 : : 0, /* tp_getattro */
4095 : : 0, /* tp_setattro */
4096 : : 0, /* tp_as_buffer */
4097 : : Py_TPFLAGS_DEFAULT, /* tp_flags */
4098 : : timezone_doc, /* tp_doc */
4099 : : 0, /* tp_traverse */
4100 : : 0, /* tp_clear */
4101 : : (richcmpfunc)timezone_richcompare,/* tp_richcompare */
4102 : : 0, /* tp_weaklistoffset */
4103 : : 0, /* tp_iter */
4104 : : 0, /* tp_iternext */
4105 : : timezone_methods, /* tp_methods */
4106 : : 0, /* tp_members */
4107 : : 0, /* tp_getset */
4108 : : 0, /* tp_base; filled in PyInit__datetime */
4109 : : 0, /* tp_dict */
4110 : : 0, /* tp_descr_get */
4111 : : 0, /* tp_descr_set */
4112 : : 0, /* tp_dictoffset */
4113 : : 0, /* tp_init */
4114 : : 0, /* tp_alloc */
4115 : : timezone_new, /* tp_new */
4116 : : };
4117 : :
4118 : : /*
4119 : : * PyDateTime_Time implementation.
4120 : : */
4121 : :
4122 : : /* Accessor properties.
4123 : : */
4124 : :
4125 : : static PyObject *
4126 : 0 : time_hour(PyDateTime_Time *self, void *unused)
4127 : : {
4128 : 0 : return PyLong_FromLong(TIME_GET_HOUR(self));
4129 : : }
4130 : :
4131 : : static PyObject *
4132 : 0 : time_minute(PyDateTime_Time *self, void *unused)
4133 : : {
4134 : 0 : return PyLong_FromLong(TIME_GET_MINUTE(self));
4135 : : }
4136 : :
4137 : : /* The name time_second conflicted with some platform header file. */
4138 : : static PyObject *
4139 : 0 : py_time_second(PyDateTime_Time *self, void *unused)
4140 : : {
4141 : 0 : return PyLong_FromLong(TIME_GET_SECOND(self));
4142 : : }
4143 : :
4144 : : static PyObject *
4145 : 0 : time_microsecond(PyDateTime_Time *self, void *unused)
4146 : : {
4147 : 0 : return PyLong_FromLong(TIME_GET_MICROSECOND(self));
4148 : : }
4149 : :
4150 : : static PyObject *
4151 : 0 : time_tzinfo(PyDateTime_Time *self, void *unused)
4152 : : {
4153 [ # # ]: 0 : PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
4154 : 0 : return Py_NewRef(result);
4155 : : }
4156 : :
4157 : : static PyObject *
4158 : 0 : time_fold(PyDateTime_Time *self, void *unused)
4159 : : {
4160 : 0 : return PyLong_FromLong(TIME_GET_FOLD(self));
4161 : : }
4162 : :
4163 : : static PyGetSetDef time_getset[] = {
4164 : : {"hour", (getter)time_hour},
4165 : : {"minute", (getter)time_minute},
4166 : : {"second", (getter)py_time_second},
4167 : : {"microsecond", (getter)time_microsecond},
4168 : : {"tzinfo", (getter)time_tzinfo},
4169 : : {"fold", (getter)time_fold},
4170 : : {NULL}
4171 : : };
4172 : :
4173 : : /*
4174 : : * Constructors.
4175 : : */
4176 : :
4177 : : static char *time_kws[] = {"hour", "minute", "second", "microsecond",
4178 : : "tzinfo", "fold", NULL};
4179 : :
4180 : : static PyObject *
4181 : 0 : time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
4182 : : {
4183 : : PyDateTime_Time *me;
4184 : 0 : char aware = (char)(tzinfo != Py_None);
4185 : :
4186 [ # # # # ]: 0 : if (aware && check_tzinfo_subclass(tzinfo) < 0) {
4187 : 0 : PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
4188 : 0 : return NULL;
4189 : : }
4190 : :
4191 : 0 : me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
4192 [ # # ]: 0 : if (me != NULL) {
4193 : 0 : const char *pdata = PyBytes_AS_STRING(state);
4194 : :
4195 : 0 : memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
4196 : 0 : me->hashcode = -1;
4197 : 0 : me->hastzinfo = aware;
4198 [ # # ]: 0 : if (aware) {
4199 : 0 : me->tzinfo = Py_NewRef(tzinfo);
4200 : : }
4201 [ # # ]: 0 : if (pdata[0] & (1 << 7)) {
4202 : 0 : me->data[0] -= 128;
4203 : 0 : me->fold = 1;
4204 : : }
4205 : : else {
4206 : 0 : me->fold = 0;
4207 : : }
4208 : : }
4209 : 0 : return (PyObject *)me;
4210 : : }
4211 : :
4212 : : static PyObject *
4213 : 0 : time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
4214 : : {
4215 : 0 : PyObject *self = NULL;
4216 : 0 : int hour = 0;
4217 : 0 : int minute = 0;
4218 : 0 : int second = 0;
4219 : 0 : int usecond = 0;
4220 : 0 : PyObject *tzinfo = Py_None;
4221 : 0 : int fold = 0;
4222 : :
4223 : : /* Check for invocation from pickle with __getstate__ state */
4224 [ # # # # ]: 0 : if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
4225 : 0 : PyObject *state = PyTuple_GET_ITEM(args, 0);
4226 [ # # ]: 0 : if (PyTuple_GET_SIZE(args) == 2) {
4227 : 0 : tzinfo = PyTuple_GET_ITEM(args, 1);
4228 : : }
4229 [ # # ]: 0 : if (PyBytes_Check(state)) {
4230 [ # # ]: 0 : if (PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
4231 [ # # ]: 0 : (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
4232 : : {
4233 : 0 : return time_from_pickle(type, state, tzinfo);
4234 : : }
4235 : : }
4236 [ # # ]: 0 : else if (PyUnicode_Check(state)) {
4237 [ # # ]: 0 : if (PyUnicode_READY(state)) {
4238 : 0 : return NULL;
4239 : : }
4240 [ # # ]: 0 : if (PyUnicode_GET_LENGTH(state) == _PyDateTime_TIME_DATASIZE &&
4241 [ # # ]: 0 : (0x7F & PyUnicode_READ_CHAR(state, 0)) < 24)
4242 : : {
4243 : 0 : state = PyUnicode_AsLatin1String(state);
4244 [ # # ]: 0 : if (state == NULL) {
4245 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
4246 : : /* More informative error message. */
4247 : 0 : PyErr_SetString(PyExc_ValueError,
4248 : : "Failed to encode latin1 string when unpickling "
4249 : : "a time object. "
4250 : : "pickle.load(data, encoding='latin1') is assumed.");
4251 : : }
4252 : 0 : return NULL;
4253 : : }
4254 : 0 : self = time_from_pickle(type, state, tzinfo);
4255 : 0 : Py_DECREF(state);
4256 : 0 : return self;
4257 : : }
4258 : : }
4259 : 0 : tzinfo = Py_None;
4260 : : }
4261 : :
4262 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
4263 : : &hour, &minute, &second, &usecond,
4264 : : &tzinfo, &fold)) {
4265 : 0 : self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold,
4266 : : type);
4267 : : }
4268 : 0 : return self;
4269 : : }
4270 : :
4271 : : /*
4272 : : * Destructor.
4273 : : */
4274 : :
4275 : : static void
4276 : 0 : time_dealloc(PyDateTime_Time *self)
4277 : : {
4278 [ # # ]: 0 : if (HASTZINFO(self)) {
4279 : 0 : Py_XDECREF(self->tzinfo);
4280 : : }
4281 : 0 : Py_TYPE(self)->tp_free((PyObject *)self);
4282 : 0 : }
4283 : :
4284 : : /*
4285 : : * Indirect access to tzinfo methods.
4286 : : */
4287 : :
4288 : : /* These are all METH_NOARGS, so don't need to check the arglist. */
4289 : : static PyObject *
4290 : 0 : time_utcoffset(PyObject *self, PyObject *unused) {
4291 [ # # ]: 0 : return call_utcoffset(GET_TIME_TZINFO(self), Py_None);
4292 : : }
4293 : :
4294 : : static PyObject *
4295 : 0 : time_dst(PyObject *self, PyObject *unused) {
4296 [ # # ]: 0 : return call_dst(GET_TIME_TZINFO(self), Py_None);
4297 : : }
4298 : :
4299 : : static PyObject *
4300 : 0 : time_tzname(PyDateTime_Time *self, PyObject *unused) {
4301 [ # # ]: 0 : return call_tzname(GET_TIME_TZINFO(self), Py_None);
4302 : : }
4303 : :
4304 : : /*
4305 : : * Various ways to turn a time into a string.
4306 : : */
4307 : :
4308 : : static PyObject *
4309 : 0 : time_repr(PyDateTime_Time *self)
4310 : : {
4311 : 0 : const char *type_name = Py_TYPE(self)->tp_name;
4312 : 0 : int h = TIME_GET_HOUR(self);
4313 : 0 : int m = TIME_GET_MINUTE(self);
4314 : 0 : int s = TIME_GET_SECOND(self);
4315 : 0 : int us = TIME_GET_MICROSECOND(self);
4316 : 0 : int fold = TIME_GET_FOLD(self);
4317 : 0 : PyObject *result = NULL;
4318 : :
4319 [ # # ]: 0 : if (us)
4320 : 0 : result = PyUnicode_FromFormat("%s(%d, %d, %d, %d)",
4321 : : type_name, h, m, s, us);
4322 [ # # ]: 0 : else if (s)
4323 : 0 : result = PyUnicode_FromFormat("%s(%d, %d, %d)",
4324 : : type_name, h, m, s);
4325 : : else
4326 : 0 : result = PyUnicode_FromFormat("%s(%d, %d)", type_name, h, m);
4327 [ # # # # ]: 0 : if (result != NULL && HASTZINFO(self))
4328 : 0 : result = append_keyword_tzinfo(result, self->tzinfo);
4329 [ # # # # ]: 0 : if (result != NULL && fold)
4330 : 0 : result = append_keyword_fold(result, fold);
4331 : 0 : return result;
4332 : : }
4333 : :
4334 : : static PyObject *
4335 : 0 : time_str(PyDateTime_Time *self)
4336 : : {
4337 : 0 : return PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(isoformat));
4338 : : }
4339 : :
4340 : : static PyObject *
4341 : 0 : time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
4342 : : {
4343 : : char buf[100];
4344 : 0 : const char *timespec = NULL;
4345 : : static char *keywords[] = {"timespec", NULL};
4346 : : PyObject *result;
4347 : 0 : int us = TIME_GET_MICROSECOND(self);
4348 : : static const char *specs[][2] = {
4349 : : {"hours", "%02d"},
4350 : : {"minutes", "%02d:%02d"},
4351 : : {"seconds", "%02d:%02d:%02d"},
4352 : : {"milliseconds", "%02d:%02d:%02d.%03d"},
4353 : : {"microseconds", "%02d:%02d:%02d.%06d"},
4354 : : };
4355 : : size_t given_spec;
4356 : :
4357 [ # # ]: 0 : if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, ×pec))
4358 : 0 : return NULL;
4359 : :
4360 [ # # # # ]: 0 : if (timespec == NULL || strcmp(timespec, "auto") == 0) {
4361 [ # # ]: 0 : if (us == 0) {
4362 : : /* seconds */
4363 : 0 : given_spec = 2;
4364 : : }
4365 : : else {
4366 : : /* microseconds */
4367 : 0 : given_spec = 4;
4368 : : }
4369 : : }
4370 : : else {
4371 [ # # ]: 0 : for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
4372 [ # # ]: 0 : if (strcmp(timespec, specs[given_spec][0]) == 0) {
4373 [ # # ]: 0 : if (given_spec == 3) {
4374 : : /* milliseconds */
4375 : 0 : us = us / 1000;
4376 : : }
4377 : 0 : break;
4378 : : }
4379 : : }
4380 : : }
4381 : :
4382 [ # # ]: 0 : if (given_spec == Py_ARRAY_LENGTH(specs)) {
4383 : 0 : PyErr_Format(PyExc_ValueError, "Unknown timespec value");
4384 : 0 : return NULL;
4385 : : }
4386 : : else {
4387 : 0 : result = PyUnicode_FromFormat(specs[given_spec][1],
4388 : 0 : TIME_GET_HOUR(self), TIME_GET_MINUTE(self),
4389 : 0 : TIME_GET_SECOND(self), us);
4390 : : }
4391 : :
4392 [ # # # # : 0 : if (result == NULL || !HASTZINFO(self) || self->tzinfo == Py_None)
# # ]
4393 : 0 : return result;
4394 : :
4395 : : /* We need to append the UTC offset. */
4396 [ # # ]: 0 : if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo,
4397 : : Py_None) < 0) {
4398 : 0 : Py_DECREF(result);
4399 : 0 : return NULL;
4400 : : }
4401 : 0 : PyUnicode_AppendAndDel(&result, PyUnicode_FromString(buf));
4402 : 0 : return result;
4403 : : }
4404 : :
4405 : : static PyObject *
4406 : 0 : time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw)
4407 : : {
4408 : : PyObject *result;
4409 : : PyObject *tuple;
4410 : : PyObject *format;
4411 : : static char *keywords[] = {"format", NULL};
4412 : :
4413 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords,
4414 : : &format))
4415 : 0 : return NULL;
4416 : :
4417 : : /* Python's strftime does insane things with the year part of the
4418 : : * timetuple. The year is forced to (the otherwise nonsensical)
4419 : : * 1900 to work around that.
4420 : : */
4421 : 0 : tuple = Py_BuildValue("iiiiiiiii",
4422 : : 1900, 1, 1, /* year, month, day */
4423 : 0 : TIME_GET_HOUR(self),
4424 : 0 : TIME_GET_MINUTE(self),
4425 : 0 : TIME_GET_SECOND(self),
4426 : : 0, 1, -1); /* weekday, daynum, dst */
4427 [ # # ]: 0 : if (tuple == NULL)
4428 : 0 : return NULL;
4429 : : assert(PyTuple_Size(tuple) == 9);
4430 : 0 : result = wrap_strftime((PyObject *)self, format, tuple,
4431 : : Py_None);
4432 : 0 : Py_DECREF(tuple);
4433 : 0 : return result;
4434 : : }
4435 : :
4436 : : /*
4437 : : * Miscellaneous methods.
4438 : : */
4439 : :
4440 : : static PyObject *
4441 : 0 : time_richcompare(PyObject *self, PyObject *other, int op)
4442 : : {
4443 : 0 : PyObject *result = NULL;
4444 : : PyObject *offset1, *offset2;
4445 : : int diff;
4446 : :
4447 [ # # ]: 0 : if (! PyTime_Check(other))
4448 : 0 : Py_RETURN_NOTIMPLEMENTED;
4449 : :
4450 [ # # # # : 0 : if (GET_TIME_TZINFO(self) == GET_TIME_TZINFO(other)) {
# # ]
4451 : 0 : diff = memcmp(((PyDateTime_Time *)self)->data,
4452 : 0 : ((PyDateTime_Time *)other)->data,
4453 : : _PyDateTime_TIME_DATASIZE);
4454 : 0 : return diff_to_bool(diff, op);
4455 : : }
4456 : 0 : offset1 = time_utcoffset(self, NULL);
4457 [ # # ]: 0 : if (offset1 == NULL)
4458 : 0 : return NULL;
4459 : 0 : offset2 = time_utcoffset(other, NULL);
4460 [ # # ]: 0 : if (offset2 == NULL)
4461 : 0 : goto done;
4462 : : /* If they're both naive, or both aware and have the same offsets,
4463 : : * we get off cheap. Note that if they're both naive, offset1 ==
4464 : : * offset2 == Py_None at this point.
4465 : : */
4466 [ # # # # ]: 0 : if ((offset1 == offset2) ||
4467 [ # # # # ]: 0 : (PyDelta_Check(offset1) && PyDelta_Check(offset2) &&
4468 : 0 : delta_cmp(offset1, offset2) == 0)) {
4469 : 0 : diff = memcmp(((PyDateTime_Time *)self)->data,
4470 : 0 : ((PyDateTime_Time *)other)->data,
4471 : : _PyDateTime_TIME_DATASIZE);
4472 : 0 : result = diff_to_bool(diff, op);
4473 : : }
4474 : : /* The hard case: both aware with different UTC offsets */
4475 [ # # # # ]: 0 : else if (offset1 != Py_None && offset2 != Py_None) {
4476 : : int offsecs1, offsecs2;
4477 : : assert(offset1 != offset2); /* else last "if" handled it */
4478 : 0 : offsecs1 = TIME_GET_HOUR(self) * 3600 +
4479 : 0 : TIME_GET_MINUTE(self) * 60 +
4480 : 0 : TIME_GET_SECOND(self) -
4481 : 0 : GET_TD_DAYS(offset1) * 86400 -
4482 : 0 : GET_TD_SECONDS(offset1);
4483 : 0 : offsecs2 = TIME_GET_HOUR(other) * 3600 +
4484 : 0 : TIME_GET_MINUTE(other) * 60 +
4485 : 0 : TIME_GET_SECOND(other) -
4486 : 0 : GET_TD_DAYS(offset2) * 86400 -
4487 : 0 : GET_TD_SECONDS(offset2);
4488 : 0 : diff = offsecs1 - offsecs2;
4489 [ # # ]: 0 : if (diff == 0)
4490 : 0 : diff = TIME_GET_MICROSECOND(self) -
4491 : 0 : TIME_GET_MICROSECOND(other);
4492 : 0 : result = diff_to_bool(diff, op);
4493 : : }
4494 [ # # ]: 0 : else if (op == Py_EQ) {
4495 : 0 : result = Py_NewRef(Py_False);
4496 : : }
4497 [ # # ]: 0 : else if (op == Py_NE) {
4498 : 0 : result = Py_NewRef(Py_True);
4499 : : }
4500 : : else {
4501 : 0 : PyErr_SetString(PyExc_TypeError,
4502 : : "can't compare offset-naive and "
4503 : : "offset-aware times");
4504 : : }
4505 : 0 : done:
4506 : 0 : Py_DECREF(offset1);
4507 : 0 : Py_XDECREF(offset2);
4508 : 0 : return result;
4509 : : }
4510 : :
4511 : : static Py_hash_t
4512 : 0 : time_hash(PyDateTime_Time *self)
4513 : : {
4514 [ # # ]: 0 : if (self->hashcode == -1) {
4515 : : PyObject *offset, *self0;
4516 [ # # ]: 0 : if (TIME_GET_FOLD(self)) {
4517 : 0 : self0 = new_time_ex2(TIME_GET_HOUR(self),
4518 : 0 : TIME_GET_MINUTE(self),
4519 : 0 : TIME_GET_SECOND(self),
4520 : 0 : TIME_GET_MICROSECOND(self),
4521 [ # # ]: 0 : HASTZINFO(self) ? self->tzinfo : Py_None,
4522 : : 0, Py_TYPE(self));
4523 [ # # ]: 0 : if (self0 == NULL)
4524 : 0 : return -1;
4525 : : }
4526 : : else {
4527 : 0 : self0 = Py_NewRef(self);
4528 : : }
4529 : 0 : offset = time_utcoffset(self0, NULL);
4530 : 0 : Py_DECREF(self0);
4531 : :
4532 [ # # ]: 0 : if (offset == NULL)
4533 : 0 : return -1;
4534 : :
4535 : : /* Reduce this to a hash of another object. */
4536 [ # # ]: 0 : if (offset == Py_None)
4537 : 0 : self->hashcode = generic_hash(
4538 : 0 : (unsigned char *)self->data, _PyDateTime_TIME_DATASIZE);
4539 : : else {
4540 : : PyObject *temp1, *temp2;
4541 : : int seconds, microseconds;
4542 : : assert(HASTZINFO(self));
4543 : 0 : seconds = TIME_GET_HOUR(self) * 3600 +
4544 : 0 : TIME_GET_MINUTE(self) * 60 +
4545 : 0 : TIME_GET_SECOND(self);
4546 : 0 : microseconds = TIME_GET_MICROSECOND(self);
4547 : 0 : temp1 = new_delta(0, seconds, microseconds, 1);
4548 [ # # ]: 0 : if (temp1 == NULL) {
4549 : 0 : Py_DECREF(offset);
4550 : 0 : return -1;
4551 : : }
4552 : 0 : temp2 = delta_subtract(temp1, offset);
4553 : 0 : Py_DECREF(temp1);
4554 [ # # ]: 0 : if (temp2 == NULL) {
4555 : 0 : Py_DECREF(offset);
4556 : 0 : return -1;
4557 : : }
4558 : 0 : self->hashcode = PyObject_Hash(temp2);
4559 : 0 : Py_DECREF(temp2);
4560 : : }
4561 : 0 : Py_DECREF(offset);
4562 : : }
4563 : 0 : return self->hashcode;
4564 : : }
4565 : :
4566 : : static PyObject *
4567 : 0 : time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
4568 : : {
4569 : : PyObject *clone;
4570 : : PyObject *tuple;
4571 : 0 : int hh = TIME_GET_HOUR(self);
4572 : 0 : int mm = TIME_GET_MINUTE(self);
4573 : 0 : int ss = TIME_GET_SECOND(self);
4574 : 0 : int us = TIME_GET_MICROSECOND(self);
4575 [ # # ]: 0 : PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
4576 : 0 : int fold = TIME_GET_FOLD(self);
4577 : :
4578 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i:replace",
4579 : : time_kws,
4580 : : &hh, &mm, &ss, &us, &tzinfo, &fold))
4581 : 0 : return NULL;
4582 [ # # # # ]: 0 : if (fold != 0 && fold != 1) {
4583 : 0 : PyErr_SetString(PyExc_ValueError,
4584 : : "fold must be either 0 or 1");
4585 : 0 : return NULL;
4586 : : }
4587 : 0 : tuple = Py_BuildValue("iiiiO", hh, mm, ss, us, tzinfo);
4588 [ # # ]: 0 : if (tuple == NULL)
4589 : 0 : return NULL;
4590 : 0 : clone = time_new(Py_TYPE(self), tuple, NULL);
4591 [ # # ]: 0 : if (clone != NULL) {
4592 : 0 : TIME_SET_FOLD(clone, fold);
4593 : : }
4594 : 0 : Py_DECREF(tuple);
4595 : 0 : return clone;
4596 : : }
4597 : :
4598 : : static PyObject *
4599 : 0 : time_fromisoformat(PyObject *cls, PyObject *tstr) {
4600 : : assert(tstr != NULL);
4601 : :
4602 [ # # ]: 0 : if (!PyUnicode_Check(tstr)) {
4603 : 0 : PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
4604 : 0 : return NULL;
4605 : : }
4606 : :
4607 : : Py_ssize_t len;
4608 : 0 : const char *p = PyUnicode_AsUTF8AndSize(tstr, &len);
4609 : :
4610 [ # # ]: 0 : if (p == NULL) {
4611 : 0 : goto invalid_string_error;
4612 : : }
4613 : :
4614 : : // The spec actually requires that time-only ISO 8601 strings start with
4615 : : // T, but the extended format allows this to be omitted as long as there
4616 : : // is no ambiguity with date strings.
4617 [ # # ]: 0 : if (*p == 'T') {
4618 : 0 : ++p;
4619 : 0 : len -= 1;
4620 : : }
4621 : :
4622 : 0 : int hour = 0, minute = 0, second = 0, microsecond = 0;
4623 : 0 : int tzoffset, tzimicrosecond = 0;
4624 : 0 : int rv = parse_isoformat_time(p, len,
4625 : : &hour, &minute, &second, µsecond,
4626 : : &tzoffset, &tzimicrosecond);
4627 : :
4628 [ # # ]: 0 : if (rv < 0) {
4629 : 0 : goto invalid_string_error;
4630 : : }
4631 : :
4632 : 0 : PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset,
4633 : : tzimicrosecond);
4634 : :
4635 [ # # ]: 0 : if (tzinfo == NULL) {
4636 : 0 : return NULL;
4637 : : }
4638 : :
4639 : : PyObject *t;
4640 [ # # ]: 0 : if ( (PyTypeObject *)cls == &PyDateTime_TimeType ) {
4641 : 0 : t = new_time(hour, minute, second, microsecond, tzinfo, 0);
4642 : : } else {
4643 : 0 : t = PyObject_CallFunction(cls, "iiiiO",
4644 : : hour, minute, second, microsecond, tzinfo);
4645 : : }
4646 : :
4647 : 0 : Py_DECREF(tzinfo);
4648 : 0 : return t;
4649 : :
4650 : 0 : invalid_string_error:
4651 : 0 : PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", tstr);
4652 : 0 : return NULL;
4653 : : }
4654 : :
4655 : :
4656 : : /* Pickle support, a simple use of __reduce__. */
4657 : :
4658 : : /* Let basestate be the non-tzinfo data string.
4659 : : * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo).
4660 : : * So it's a tuple in any (non-error) case.
4661 : : * __getstate__ isn't exposed.
4662 : : */
4663 : : static PyObject *
4664 : 0 : time_getstate(PyDateTime_Time *self, int proto)
4665 : : {
4666 : : PyObject *basestate;
4667 : 0 : PyObject *result = NULL;
4668 : :
4669 : 0 : basestate = PyBytes_FromStringAndSize((char *)self->data,
4670 : : _PyDateTime_TIME_DATASIZE);
4671 [ # # ]: 0 : if (basestate != NULL) {
4672 [ # # # # ]: 0 : if (proto > 3 && TIME_GET_FOLD(self))
4673 : : /* Set the first bit of the first byte */
4674 : 0 : PyBytes_AS_STRING(basestate)[0] |= (1 << 7);
4675 [ # # # # ]: 0 : if (! HASTZINFO(self) || self->tzinfo == Py_None)
4676 : 0 : result = PyTuple_Pack(1, basestate);
4677 : : else
4678 : 0 : result = PyTuple_Pack(2, basestate, self->tzinfo);
4679 : 0 : Py_DECREF(basestate);
4680 : : }
4681 : 0 : return result;
4682 : : }
4683 : :
4684 : : static PyObject *
4685 : 0 : time_reduce_ex(PyDateTime_Time *self, PyObject *args)
4686 : : {
4687 : : int proto;
4688 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
4689 : 0 : return NULL;
4690 : :
4691 : 0 : return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto));
4692 : : }
4693 : :
4694 : : static PyObject *
4695 : 0 : time_reduce(PyDateTime_Time *self, PyObject *arg)
4696 : : {
4697 : 0 : return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2));
4698 : : }
4699 : :
4700 : : static PyMethodDef time_methods[] = {
4701 : :
4702 : : {"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS,
4703 : : PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]"
4704 : : "[+HH:MM].\n\n"
4705 : : "The optional argument timespec specifies the number "
4706 : : "of additional terms\nof the time to include. Valid "
4707 : : "options are 'auto', 'hours', 'minutes',\n'seconds', "
4708 : : "'milliseconds' and 'microseconds'.\n")},
4709 : :
4710 : : {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS,
4711 : : PyDoc_STR("format -> strftime() style string.")},
4712 : :
4713 : : {"__format__", (PyCFunction)date_format, METH_VARARGS,
4714 : : PyDoc_STR("Formats self with strftime.")},
4715 : :
4716 : : {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS,
4717 : : PyDoc_STR("Return self.tzinfo.utcoffset(self).")},
4718 : :
4719 : : {"tzname", (PyCFunction)time_tzname, METH_NOARGS,
4720 : : PyDoc_STR("Return self.tzinfo.tzname(self).")},
4721 : :
4722 : : {"dst", (PyCFunction)time_dst, METH_NOARGS,
4723 : : PyDoc_STR("Return self.tzinfo.dst(self).")},
4724 : :
4725 : : {"replace", _PyCFunction_CAST(time_replace), METH_VARARGS | METH_KEYWORDS,
4726 : : PyDoc_STR("Return time with new specified fields.")},
4727 : :
4728 : : {"fromisoformat", (PyCFunction)time_fromisoformat, METH_O | METH_CLASS,
4729 : : PyDoc_STR("string -> time from a string in ISO 8601 format")},
4730 : :
4731 : : {"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS,
4732 : : PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
4733 : :
4734 : : {"__reduce__", (PyCFunction)time_reduce, METH_NOARGS,
4735 : : PyDoc_STR("__reduce__() -> (cls, state)")},
4736 : :
4737 : : {NULL, NULL}
4738 : : };
4739 : :
4740 : : static const char time_doc[] =
4741 : : PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n\
4742 : : \n\
4743 : : All arguments are optional. tzinfo may be None, or an instance of\n\
4744 : : a tzinfo subclass. The remaining arguments may be ints.\n");
4745 : :
4746 : : static PyTypeObject PyDateTime_TimeType = {
4747 : : PyVarObject_HEAD_INIT(NULL, 0)
4748 : : "datetime.time", /* tp_name */
4749 : : sizeof(PyDateTime_Time), /* tp_basicsize */
4750 : : 0, /* tp_itemsize */
4751 : : (destructor)time_dealloc, /* tp_dealloc */
4752 : : 0, /* tp_vectorcall_offset */
4753 : : 0, /* tp_getattr */
4754 : : 0, /* tp_setattr */
4755 : : 0, /* tp_as_async */
4756 : : (reprfunc)time_repr, /* tp_repr */
4757 : : 0, /* tp_as_number */
4758 : : 0, /* tp_as_sequence */
4759 : : 0, /* tp_as_mapping */
4760 : : (hashfunc)time_hash, /* tp_hash */
4761 : : 0, /* tp_call */
4762 : : (reprfunc)time_str, /* tp_str */
4763 : : PyObject_GenericGetAttr, /* tp_getattro */
4764 : : 0, /* tp_setattro */
4765 : : 0, /* tp_as_buffer */
4766 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
4767 : : time_doc, /* tp_doc */
4768 : : 0, /* tp_traverse */
4769 : : 0, /* tp_clear */
4770 : : time_richcompare, /* tp_richcompare */
4771 : : 0, /* tp_weaklistoffset */
4772 : : 0, /* tp_iter */
4773 : : 0, /* tp_iternext */
4774 : : time_methods, /* tp_methods */
4775 : : 0, /* tp_members */
4776 : : time_getset, /* tp_getset */
4777 : : 0, /* tp_base */
4778 : : 0, /* tp_dict */
4779 : : 0, /* tp_descr_get */
4780 : : 0, /* tp_descr_set */
4781 : : 0, /* tp_dictoffset */
4782 : : 0, /* tp_init */
4783 : : time_alloc, /* tp_alloc */
4784 : : time_new, /* tp_new */
4785 : : 0, /* tp_free */
4786 : : };
4787 : :
4788 : : /*
4789 : : * PyDateTime_DateTime implementation.
4790 : : */
4791 : :
4792 : : /* Accessor properties. Properties for day, month, and year are inherited
4793 : : * from date.
4794 : : */
4795 : :
4796 : : static PyObject *
4797 : 0 : datetime_hour(PyDateTime_DateTime *self, void *unused)
4798 : : {
4799 : 0 : return PyLong_FromLong(DATE_GET_HOUR(self));
4800 : : }
4801 : :
4802 : : static PyObject *
4803 : 0 : datetime_minute(PyDateTime_DateTime *self, void *unused)
4804 : : {
4805 : 0 : return PyLong_FromLong(DATE_GET_MINUTE(self));
4806 : : }
4807 : :
4808 : : static PyObject *
4809 : 0 : datetime_second(PyDateTime_DateTime *self, void *unused)
4810 : : {
4811 : 0 : return PyLong_FromLong(DATE_GET_SECOND(self));
4812 : : }
4813 : :
4814 : : static PyObject *
4815 : 0 : datetime_microsecond(PyDateTime_DateTime *self, void *unused)
4816 : : {
4817 : 0 : return PyLong_FromLong(DATE_GET_MICROSECOND(self));
4818 : : }
4819 : :
4820 : : static PyObject *
4821 : 0 : datetime_tzinfo(PyDateTime_DateTime *self, void *unused)
4822 : : {
4823 [ # # ]: 0 : PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
4824 : 0 : return Py_NewRef(result);
4825 : : }
4826 : :
4827 : : static PyObject *
4828 : 0 : datetime_fold(PyDateTime_DateTime *self, void *unused)
4829 : : {
4830 : 0 : return PyLong_FromLong(DATE_GET_FOLD(self));
4831 : : }
4832 : :
4833 : : static PyGetSetDef datetime_getset[] = {
4834 : : {"hour", (getter)datetime_hour},
4835 : : {"minute", (getter)datetime_minute},
4836 : : {"second", (getter)datetime_second},
4837 : : {"microsecond", (getter)datetime_microsecond},
4838 : : {"tzinfo", (getter)datetime_tzinfo},
4839 : : {"fold", (getter)datetime_fold},
4840 : : {NULL}
4841 : : };
4842 : :
4843 : : /*
4844 : : * Constructors.
4845 : : */
4846 : :
4847 : : static char *datetime_kws[] = {
4848 : : "year", "month", "day", "hour", "minute", "second",
4849 : : "microsecond", "tzinfo", "fold", NULL
4850 : : };
4851 : :
4852 : : static PyObject *
4853 : 0 : datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
4854 : : {
4855 : : PyDateTime_DateTime *me;
4856 : 0 : char aware = (char)(tzinfo != Py_None);
4857 : :
4858 [ # # # # ]: 0 : if (aware && check_tzinfo_subclass(tzinfo) < 0) {
4859 : 0 : PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
4860 : 0 : return NULL;
4861 : : }
4862 : :
4863 : 0 : me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
4864 [ # # ]: 0 : if (me != NULL) {
4865 : 0 : const char *pdata = PyBytes_AS_STRING(state);
4866 : :
4867 : 0 : memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
4868 : 0 : me->hashcode = -1;
4869 : 0 : me->hastzinfo = aware;
4870 [ # # ]: 0 : if (aware) {
4871 : 0 : me->tzinfo = Py_NewRef(tzinfo);
4872 : : }
4873 [ # # ]: 0 : if (pdata[2] & (1 << 7)) {
4874 : 0 : me->data[2] -= 128;
4875 : 0 : me->fold = 1;
4876 : : }
4877 : : else {
4878 : 0 : me->fold = 0;
4879 : : }
4880 : : }
4881 : 0 : return (PyObject *)me;
4882 : : }
4883 : :
4884 : : static PyObject *
4885 : 0 : datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
4886 : : {
4887 : 0 : PyObject *self = NULL;
4888 : : int year;
4889 : : int month;
4890 : : int day;
4891 : 0 : int hour = 0;
4892 : 0 : int minute = 0;
4893 : 0 : int second = 0;
4894 : 0 : int usecond = 0;
4895 : 0 : int fold = 0;
4896 : 0 : PyObject *tzinfo = Py_None;
4897 : :
4898 : : /* Check for invocation from pickle with __getstate__ state */
4899 [ # # # # ]: 0 : if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
4900 : 0 : PyObject *state = PyTuple_GET_ITEM(args, 0);
4901 [ # # ]: 0 : if (PyTuple_GET_SIZE(args) == 2) {
4902 : 0 : tzinfo = PyTuple_GET_ITEM(args, 1);
4903 : : }
4904 [ # # ]: 0 : if (PyBytes_Check(state)) {
4905 [ # # ]: 0 : if (PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
4906 [ # # ]: 0 : MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
4907 : : {
4908 : 0 : return datetime_from_pickle(type, state, tzinfo);
4909 : : }
4910 : : }
4911 [ # # ]: 0 : else if (PyUnicode_Check(state)) {
4912 [ # # ]: 0 : if (PyUnicode_READY(state)) {
4913 : 0 : return NULL;
4914 : : }
4915 [ # # ]: 0 : if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATETIME_DATASIZE &&
4916 [ # # ]: 0 : MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2) & 0x7F))
4917 : : {
4918 : 0 : state = PyUnicode_AsLatin1String(state);
4919 [ # # ]: 0 : if (state == NULL) {
4920 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
4921 : : /* More informative error message. */
4922 : 0 : PyErr_SetString(PyExc_ValueError,
4923 : : "Failed to encode latin1 string when unpickling "
4924 : : "a datetime object. "
4925 : : "pickle.load(data, encoding='latin1') is assumed.");
4926 : : }
4927 : 0 : return NULL;
4928 : : }
4929 : 0 : self = datetime_from_pickle(type, state, tzinfo);
4930 : 0 : Py_DECREF(state);
4931 : 0 : return self;
4932 : : }
4933 : : }
4934 : 0 : tzinfo = Py_None;
4935 : : }
4936 : :
4937 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws,
4938 : : &year, &month, &day, &hour, &minute,
4939 : : &second, &usecond, &tzinfo, &fold)) {
4940 : 0 : self = new_datetime_ex2(year, month, day,
4941 : : hour, minute, second, usecond,
4942 : : tzinfo, fold, type);
4943 : : }
4944 : 0 : return self;
4945 : : }
4946 : :
4947 : : /* TM_FUNC is the shared type of _PyTime_localtime() and
4948 : : * _PyTime_gmtime(). */
4949 : : typedef int (*TM_FUNC)(time_t timer, struct tm*);
4950 : :
4951 : : /* As of version 2015f max fold in IANA database is
4952 : : * 23 hours at 1969-09-30 13:00:00 in Kwajalein. */
4953 : : static long long max_fold_seconds = 24 * 3600;
4954 : : /* NB: date(1970,1,1).toordinal() == 719163 */
4955 : : static long long epoch = 719163LL * 24 * 60 * 60;
4956 : :
4957 : : static long long
4958 : 0 : utc_to_seconds(int year, int month, int day,
4959 : : int hour, int minute, int second)
4960 : : {
4961 : : long long ordinal;
4962 : :
4963 : : /* ymd_to_ord() doesn't support year <= 0 */
4964 [ # # # # ]: 0 : if (year < MINYEAR || year > MAXYEAR) {
4965 : 0 : PyErr_Format(PyExc_ValueError, "year %i is out of range", year);
4966 : 0 : return -1;
4967 : : }
4968 : :
4969 : 0 : ordinal = ymd_to_ord(year, month, day);
4970 : 0 : return ((ordinal * 24 + hour) * 60 + minute) * 60 + second;
4971 : : }
4972 : :
4973 : : static long long
4974 : 0 : local(long long u)
4975 : : {
4976 : : struct tm local_time;
4977 : : time_t t;
4978 : 0 : u -= epoch;
4979 : 0 : t = u;
4980 [ # # ]: 0 : if (t != u) {
4981 : 0 : PyErr_SetString(PyExc_OverflowError,
4982 : : "timestamp out of range for platform time_t");
4983 : 0 : return -1;
4984 : : }
4985 [ # # ]: 0 : if (_PyTime_localtime(t, &local_time) != 0)
4986 : 0 : return -1;
4987 : 0 : return utc_to_seconds(local_time.tm_year + 1900,
4988 : 0 : local_time.tm_mon + 1,
4989 : : local_time.tm_mday,
4990 : : local_time.tm_hour,
4991 : : local_time.tm_min,
4992 : : local_time.tm_sec);
4993 : : }
4994 : :
4995 : : /* Internal helper.
4996 : : * Build datetime from a time_t and a distinct count of microseconds.
4997 : : * Pass localtime or gmtime for f, to control the interpretation of timet.
4998 : : */
4999 : : static PyObject *
5000 : 0 : datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
5001 : : PyObject *tzinfo)
5002 : : {
5003 : : struct tm tm;
5004 : 0 : int year, month, day, hour, minute, second, fold = 0;
5005 : :
5006 [ # # ]: 0 : if (f(timet, &tm) != 0)
5007 : 0 : return NULL;
5008 : :
5009 : 0 : year = tm.tm_year + 1900;
5010 : 0 : month = tm.tm_mon + 1;
5011 : 0 : day = tm.tm_mday;
5012 : 0 : hour = tm.tm_hour;
5013 : 0 : minute = tm.tm_min;
5014 : : /* The platform localtime/gmtime may insert leap seconds,
5015 : : * indicated by tm.tm_sec > 59. We don't care about them,
5016 : : * except to the extent that passing them on to the datetime
5017 : : * constructor would raise ValueError for a reason that
5018 : : * made no sense to the user.
5019 : : */
5020 : 0 : second = Py_MIN(59, tm.tm_sec);
5021 : :
5022 : : /* local timezone requires to compute fold */
5023 [ # # # # ]: 0 : if (tzinfo == Py_None && f == _PyTime_localtime
5024 : : /* On Windows, passing a negative value to local results
5025 : : * in an OSError because localtime_s on Windows does
5026 : : * not support negative timestamps. Unfortunately this
5027 : : * means that fold detection for time values between
5028 : : * 0 and max_fold_seconds will result in an identical
5029 : : * error since we subtract max_fold_seconds to detect a
5030 : : * fold. However, since we know there haven't been any
5031 : : * folds in the interval [0, max_fold_seconds) in any
5032 : : * timezone, we can hackily just forego fold detection
5033 : : * for this time range.
5034 : : */
5035 : : #ifdef MS_WINDOWS
5036 : : && (timet - max_fold_seconds > 0)
5037 : : #endif
5038 : : ) {
5039 : : long long probe_seconds, result_seconds, transition;
5040 : :
5041 : 0 : result_seconds = utc_to_seconds(year, month, day,
5042 : : hour, minute, second);
5043 [ # # # # ]: 0 : if (result_seconds == -1 && PyErr_Occurred()) {
5044 : 0 : return NULL;
5045 : : }
5046 : :
5047 : : /* Probe max_fold_seconds to detect a fold. */
5048 : 0 : probe_seconds = local(epoch + timet - max_fold_seconds);
5049 [ # # ]: 0 : if (probe_seconds == -1)
5050 : 0 : return NULL;
5051 : 0 : transition = result_seconds - probe_seconds - max_fold_seconds;
5052 [ # # ]: 0 : if (transition < 0) {
5053 : 0 : probe_seconds = local(epoch + timet + transition);
5054 [ # # ]: 0 : if (probe_seconds == -1)
5055 : 0 : return NULL;
5056 [ # # ]: 0 : if (probe_seconds == result_seconds)
5057 : 0 : fold = 1;
5058 : : }
5059 : : }
5060 : 0 : return new_datetime_subclass_fold_ex(year, month, day, hour, minute,
5061 : : second, us, tzinfo, fold, cls);
5062 : : }
5063 : :
5064 : : /* Internal helper.
5065 : : * Build datetime from a Python timestamp. Pass localtime or gmtime for f,
5066 : : * to control the interpretation of the timestamp. Since a double doesn't
5067 : : * have enough bits to cover a datetime's full range of precision, it's
5068 : : * better to call datetime_from_timet_and_us provided you have a way
5069 : : * to get that much precision (e.g., C time() isn't good enough).
5070 : : */
5071 : : static PyObject *
5072 : 0 : datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp,
5073 : : PyObject *tzinfo)
5074 : : {
5075 : : time_t timet;
5076 : : long us;
5077 : :
5078 [ # # ]: 0 : if (_PyTime_ObjectToTimeval(timestamp,
5079 : : &timet, &us, _PyTime_ROUND_HALF_EVEN) == -1)
5080 : 0 : return NULL;
5081 : :
5082 : 0 : return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo);
5083 : : }
5084 : :
5085 : : /* Internal helper.
5086 : : * Build most accurate possible datetime for current time. Pass localtime or
5087 : : * gmtime for f as appropriate.
5088 : : */
5089 : : static PyObject *
5090 : 0 : datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
5091 : : {
5092 : 0 : _PyTime_t ts = _PyTime_GetSystemClock();
5093 : : time_t secs;
5094 : : int us;
5095 : :
5096 [ # # ]: 0 : if (_PyTime_AsTimevalTime_t(ts, &secs, &us, _PyTime_ROUND_FLOOR) < 0)
5097 : 0 : return NULL;
5098 : : assert(0 <= us && us <= 999999);
5099 : :
5100 : 0 : return datetime_from_timet_and_us(cls, f, secs, us, tzinfo);
5101 : : }
5102 : :
5103 : : /*[clinic input]
5104 : :
5105 : : @classmethod
5106 : : datetime.datetime.now
5107 : :
5108 : : tz: object = None
5109 : : Timezone object.
5110 : :
5111 : : Returns new datetime object representing current time local to tz.
5112 : :
5113 : : If no tz is specified, uses local timezone.
5114 : : [clinic start generated code]*/
5115 : :
5116 : : static PyObject *
5117 : 0 : datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
5118 : : /*[clinic end generated code: output=b3386e5345e2b47a input=80d09869c5267d00]*/
5119 : : {
5120 : : PyObject *self;
5121 : :
5122 : : /* Return best possible local time -- this isn't constrained by the
5123 : : * precision of a timestamp.
5124 : : */
5125 [ # # ]: 0 : if (check_tzinfo_subclass(tz) < 0)
5126 : 0 : return NULL;
5127 : :
5128 [ # # ]: 0 : self = datetime_best_possible((PyObject *)type,
5129 : : tz == Py_None ? _PyTime_localtime :
5130 : : _PyTime_gmtime,
5131 : : tz);
5132 [ # # # # ]: 0 : if (self != NULL && tz != Py_None) {
5133 : : /* Convert UTC to tzinfo's zone. */
5134 : 0 : PyObject *res = PyObject_CallMethodOneArg(tz, &_Py_ID(fromutc), self);
5135 : 0 : Py_DECREF(self);
5136 : 0 : return res;
5137 : : }
5138 : 0 : return self;
5139 : : }
5140 : :
5141 : : /* Return best possible UTC time -- this isn't constrained by the
5142 : : * precision of a timestamp.
5143 : : */
5144 : : static PyObject *
5145 : 0 : datetime_utcnow(PyObject *cls, PyObject *dummy)
5146 : : {
5147 : 0 : return datetime_best_possible(cls, _PyTime_gmtime, Py_None);
5148 : : }
5149 : :
5150 : : /* Return new local datetime from timestamp (Python timestamp -- a double). */
5151 : : static PyObject *
5152 : 0 : datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
5153 : : {
5154 : : PyObject *self;
5155 : : PyObject *timestamp;
5156 : 0 : PyObject *tzinfo = Py_None;
5157 : : static char *keywords[] = {"timestamp", "tz", NULL};
5158 : :
5159 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp",
5160 : : keywords, ×tamp, &tzinfo))
5161 : 0 : return NULL;
5162 [ # # ]: 0 : if (check_tzinfo_subclass(tzinfo) < 0)
5163 : 0 : return NULL;
5164 : :
5165 : 0 : self = datetime_from_timestamp(cls,
5166 [ # # ]: 0 : tzinfo == Py_None ? _PyTime_localtime :
5167 : : _PyTime_gmtime,
5168 : : timestamp,
5169 : : tzinfo);
5170 [ # # # # ]: 0 : if (self != NULL && tzinfo != Py_None) {
5171 : : /* Convert UTC to tzinfo's zone. */
5172 : 0 : PyObject *res = PyObject_CallMethodOneArg(tzinfo, &_Py_ID(fromutc), self);
5173 : 0 : Py_DECREF(self);
5174 : 0 : return res;
5175 : : }
5176 : 0 : return self;
5177 : : }
5178 : :
5179 : : /* Return new UTC datetime from timestamp (Python timestamp -- a double). */
5180 : : static PyObject *
5181 : 0 : datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
5182 : : {
5183 : : PyObject *timestamp;
5184 : 0 : PyObject *result = NULL;
5185 : :
5186 [ # # ]: 0 : if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp))
5187 : 0 : result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp,
5188 : : Py_None);
5189 : 0 : return result;
5190 : : }
5191 : :
5192 : : /* Return new datetime from _strptime.strptime_datetime(). */
5193 : : static PyObject *
5194 : 0 : datetime_strptime(PyObject *cls, PyObject *args)
5195 : : {
5196 : : static PyObject *module = NULL;
5197 : : PyObject *string, *format;
5198 : :
5199 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format))
5200 : 0 : return NULL;
5201 : :
5202 [ # # ]: 0 : if (module == NULL) {
5203 : 0 : module = PyImport_ImportModule("_strptime");
5204 [ # # ]: 0 : if (module == NULL)
5205 : 0 : return NULL;
5206 : : }
5207 : 0 : return PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime),
5208 : : cls, string, format, NULL);
5209 : : }
5210 : :
5211 : : /* Return new datetime from date/datetime and time arguments. */
5212 : : static PyObject *
5213 : 0 : datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
5214 : : {
5215 : : static char *keywords[] = {"date", "time", "tzinfo", NULL};
5216 : : PyObject *date;
5217 : : PyObject *time;
5218 : 0 : PyObject *tzinfo = NULL;
5219 : 0 : PyObject *result = NULL;
5220 : :
5221 [ # # ]: 0 : if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords,
5222 : : &PyDateTime_DateType, &date,
5223 : : &PyDateTime_TimeType, &time, &tzinfo)) {
5224 [ # # ]: 0 : if (tzinfo == NULL) {
5225 [ # # ]: 0 : if (HASTZINFO(time))
5226 : 0 : tzinfo = ((PyDateTime_Time *)time)->tzinfo;
5227 : : else
5228 : 0 : tzinfo = Py_None;
5229 : : }
5230 : 0 : result = new_datetime_subclass_fold_ex(GET_YEAR(date),
5231 : 0 : GET_MONTH(date),
5232 : 0 : GET_DAY(date),
5233 : 0 : TIME_GET_HOUR(time),
5234 : 0 : TIME_GET_MINUTE(time),
5235 : 0 : TIME_GET_SECOND(time),
5236 : 0 : TIME_GET_MICROSECOND(time),
5237 : : tzinfo,
5238 : 0 : TIME_GET_FOLD(time),
5239 : : cls);
5240 : : }
5241 : 0 : return result;
5242 : : }
5243 : :
5244 : : static PyObject *
5245 : 0 : _sanitize_isoformat_str(PyObject *dtstr)
5246 : : {
5247 : 0 : Py_ssize_t len = PyUnicode_GetLength(dtstr);
5248 [ # # ]: 0 : if (len < 7) { // All valid ISO 8601 strings are at least 7 characters long
5249 : 0 : return NULL;
5250 : : }
5251 : :
5252 : : // `fromisoformat` allows surrogate characters in exactly one position,
5253 : : // the separator; to allow datetime_fromisoformat to make the simplifying
5254 : : // assumption that all valid strings can be encoded in UTF-8, this function
5255 : : // replaces any surrogate character separators with `T`.
5256 : : //
5257 : : // The result of this, if not NULL, returns a new reference
5258 : 0 : const void* const unicode_data = PyUnicode_DATA(dtstr);
5259 : 0 : const int kind = PyUnicode_KIND(dtstr);
5260 : :
5261 : : // Depending on the format of the string, the separator can only ever be
5262 : : // in positions 7, 8 or 10. We'll check each of these for a surrogate and
5263 : : // if we find one, replace it with `T`. If there is more than one surrogate,
5264 : : // we don't have to bother sanitizing it, because the function will later
5265 : : // fail when we try to encode the string as ASCII.
5266 : : static const size_t potential_separators[3] = {7, 8, 10};
5267 : 0 : size_t surrogate_separator = 0;
5268 [ # # ]: 0 : for(size_t idx = 0;
5269 : : idx < sizeof(potential_separators) / sizeof(*potential_separators);
5270 : 0 : ++idx) {
5271 : 0 : size_t pos = potential_separators[idx];
5272 [ # # ]: 0 : if (pos > (size_t)len) {
5273 : 0 : break;
5274 : : }
5275 : :
5276 [ # # ]: 0 : if(Py_UNICODE_IS_SURROGATE(PyUnicode_READ(kind, unicode_data, pos))) {
5277 : 0 : surrogate_separator = pos;
5278 : 0 : break;
5279 : : }
5280 : : }
5281 : :
5282 [ # # ]: 0 : if (surrogate_separator == 0) {
5283 : 0 : return Py_NewRef(dtstr);
5284 : : }
5285 : :
5286 : 0 : PyObject *str_out = _PyUnicode_Copy(dtstr);
5287 [ # # ]: 0 : if (str_out == NULL) {
5288 : 0 : return NULL;
5289 : : }
5290 : :
5291 [ # # ]: 0 : if (PyUnicode_WriteChar(str_out, surrogate_separator, (Py_UCS4)'T')) {
5292 : 0 : Py_DECREF(str_out);
5293 : 0 : return NULL;
5294 : : }
5295 : :
5296 : 0 : return str_out;
5297 : : }
5298 : :
5299 : :
5300 : : static Py_ssize_t
5301 : 0 : _find_isoformat_datetime_separator(const char *dtstr, Py_ssize_t len) {
5302 : : // The valid date formats can all be distinguished by characters 4 and 5
5303 : : // and further narrowed down by character
5304 : : // which tells us where to look for the separator character.
5305 : : // Format | As-rendered | Position
5306 : : // ---------------------------------------
5307 : : // %Y-%m-%d | YYYY-MM-DD | 10
5308 : : // %Y%m%d | YYYYMMDD | 8
5309 : : // %Y-W%V | YYYY-Www | 8
5310 : : // %YW%V | YYYYWww | 7
5311 : : // %Y-W%V-%u | YYYY-Www-d | 10
5312 : : // %YW%V%u | YYYYWwwd | 8
5313 : : // %Y-%j | YYYY-DDD | 8
5314 : : // %Y%j | YYYYDDD | 7
5315 : : //
5316 : : // Note that because we allow *any* character for the separator, in the
5317 : : // case where character 4 is W, it's not straightforward to determine where
5318 : : // the separator is — in the case of YYYY-Www-d, you have actual ambiguity,
5319 : : // e.g. 2020-W01-0000 could be YYYY-Www-D0HH or YYYY-Www-HHMM, when the
5320 : : // separator character is a number in the former case or a hyphen in the
5321 : : // latter case.
5322 : : //
5323 : : // The case of YYYYWww can be distinguished from YYYYWwwd by tracking ahead
5324 : : // to either the end of the string or the first non-numeric character —
5325 : : // since the time components all come in pairs YYYYWww#HH can be
5326 : : // distinguished from YYYYWwwd#HH by the fact that there will always be an
5327 : : // odd number of digits before the first non-digit character in the former
5328 : : // case.
5329 : : static const char date_separator = '-';
5330 : : static const char week_indicator = 'W';
5331 : :
5332 [ # # ]: 0 : if (len == 7) {
5333 : 0 : return 7;
5334 : : }
5335 : :
5336 [ # # ]: 0 : if (dtstr[4] == date_separator) {
5337 : : // YYYY-???
5338 : :
5339 [ # # ]: 0 : if (dtstr[5] == week_indicator) {
5340 : : // YYYY-W??
5341 : :
5342 [ # # ]: 0 : if (len < 8) {
5343 : 0 : return -1;
5344 : : }
5345 : :
5346 [ # # # # ]: 0 : if (len > 8 && dtstr[8] == date_separator) {
5347 : : // YYYY-Www-D (10) or YYYY-Www-HH (8)
5348 [ # # ]: 0 : if (len == 9) { return -1; }
5349 [ # # # # ]: 0 : if (len > 10 && is_digit(dtstr[10])) {
5350 : : // This is as far as we'll try to go to resolve the
5351 : : // ambiguity for the moment — if we have YYYY-Www-##, the
5352 : : // separator is either a hyphen at 8 or a number at 10.
5353 : : //
5354 : : // We'll assume it's a hyphen at 8 because it's way more
5355 : : // likely that someone will use a hyphen as a separator
5356 : : // than a number, but at this point it's really best effort
5357 : : // because this is an extension of the spec anyway.
5358 : 0 : return 8;
5359 : : }
5360 : :
5361 : 0 : return 10;
5362 : : } else {
5363 : : // YYYY-Www (8)
5364 : 0 : return 8;
5365 : : }
5366 : : } else {
5367 : : // YYYY-MM-DD (10)
5368 : 0 : return 10;
5369 : : }
5370 : : } else {
5371 : : // YYYY???
5372 [ # # ]: 0 : if (dtstr[4] == week_indicator) {
5373 : : // YYYYWww (7) or YYYYWwwd (8)
5374 : 0 : size_t idx = 7;
5375 [ # # ]: 0 : for (; idx < (size_t)len; ++idx) {
5376 : : // Keep going until we run out of digits.
5377 [ # # ]: 0 : if (!is_digit(dtstr[idx])) {
5378 : 0 : break;
5379 : : }
5380 : : }
5381 : :
5382 [ # # ]: 0 : if (idx < 9) {
5383 : 0 : return idx;
5384 : : }
5385 : :
5386 [ # # ]: 0 : if (idx % 2 == 0) {
5387 : : // If the index of the last number is even, it's YYYYWww
5388 : 0 : return 7;
5389 : : } else {
5390 : 0 : return 8;
5391 : : }
5392 : : } else {
5393 : : // YYYYMMDD (8)
5394 : 0 : return 8;
5395 : : }
5396 : : }
5397 : : }
5398 : :
5399 : : static PyObject *
5400 : 0 : datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
5401 : : {
5402 : : assert(dtstr != NULL);
5403 : :
5404 [ # # ]: 0 : if (!PyUnicode_Check(dtstr)) {
5405 : 0 : PyErr_SetString(PyExc_TypeError,
5406 : : "fromisoformat: argument must be str");
5407 : 0 : return NULL;
5408 : : }
5409 : :
5410 : : // We only need to sanitize this string if the separator is a surrogate
5411 : : // character. In the situation where the separator location is ambiguous,
5412 : : // we don't have to sanitize it anything because that can only happen when
5413 : : // the separator is either '-' or a number. This should mostly be a noop
5414 : : // but it makes the reference counting easier if we still sanitize.
5415 : 0 : PyObject *dtstr_clean = _sanitize_isoformat_str(dtstr);
5416 [ # # ]: 0 : if (dtstr_clean == NULL) {
5417 : 0 : goto invalid_string_error;
5418 : : }
5419 : :
5420 : : Py_ssize_t len;
5421 : 0 : const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr_clean, &len);
5422 : :
5423 [ # # ]: 0 : if (dt_ptr == NULL) {
5424 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
5425 : : // Encoding errors are invalid string errors at this point
5426 : 0 : goto invalid_string_error;
5427 : : }
5428 : : else {
5429 : 0 : goto error;
5430 : : }
5431 : : }
5432 : :
5433 : 0 : const Py_ssize_t separator_location = _find_isoformat_datetime_separator(
5434 : : dt_ptr, len);
5435 : :
5436 : :
5437 : 0 : const char *p = dt_ptr;
5438 : :
5439 : 0 : int year = 0, month = 0, day = 0;
5440 : 0 : int hour = 0, minute = 0, second = 0, microsecond = 0;
5441 : 0 : int tzoffset = 0, tzusec = 0;
5442 : :
5443 : : // date runs up to separator_location
5444 : 0 : int rv = parse_isoformat_date(p, separator_location, &year, &month, &day);
5445 : :
5446 [ # # # # ]: 0 : if (!rv && len > separator_location) {
5447 : : // In UTF-8, the length of multi-byte characters is encoded in the MSB
5448 : 0 : p += separator_location;
5449 [ # # ]: 0 : if ((p[0] & 0x80) == 0) {
5450 : 0 : p += 1;
5451 : : }
5452 : : else {
5453 [ # # # ]: 0 : switch (p[0] & 0xf0) {
5454 : 0 : case 0xe0:
5455 : 0 : p += 3;
5456 : 0 : break;
5457 : 0 : case 0xf0:
5458 : 0 : p += 4;
5459 : 0 : break;
5460 : 0 : default:
5461 : 0 : p += 2;
5462 : 0 : break;
5463 : : }
5464 : : }
5465 : :
5466 : 0 : len -= (p - dt_ptr);
5467 : 0 : rv = parse_isoformat_time(p, len, &hour, &minute, &second,
5468 : : µsecond, &tzoffset, &tzusec);
5469 : : }
5470 [ # # ]: 0 : if (rv < 0) {
5471 : 0 : goto invalid_string_error;
5472 : : }
5473 : :
5474 : 0 : PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
5475 [ # # ]: 0 : if (tzinfo == NULL) {
5476 : 0 : goto error;
5477 : : }
5478 : :
5479 : 0 : PyObject *dt = new_datetime_subclass_ex(year, month, day, hour, minute,
5480 : : second, microsecond, tzinfo, cls);
5481 : :
5482 : 0 : Py_DECREF(tzinfo);
5483 : 0 : Py_DECREF(dtstr_clean);
5484 : 0 : return dt;
5485 : :
5486 : 0 : invalid_string_error:
5487 : 0 : PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
5488 : :
5489 : 0 : error:
5490 : 0 : Py_XDECREF(dtstr_clean);
5491 : :
5492 : 0 : return NULL;
5493 : : }
5494 : :
5495 : : /*
5496 : : * Destructor.
5497 : : */
5498 : :
5499 : : static void
5500 : 0 : datetime_dealloc(PyDateTime_DateTime *self)
5501 : : {
5502 [ # # ]: 0 : if (HASTZINFO(self)) {
5503 : 0 : Py_XDECREF(self->tzinfo);
5504 : : }
5505 : 0 : Py_TYPE(self)->tp_free((PyObject *)self);
5506 : 0 : }
5507 : :
5508 : : /*
5509 : : * Indirect access to tzinfo methods.
5510 : : */
5511 : :
5512 : : /* These are all METH_NOARGS, so don't need to check the arglist. */
5513 : : static PyObject *
5514 : 0 : datetime_utcoffset(PyObject *self, PyObject *unused) {
5515 [ # # ]: 0 : return call_utcoffset(GET_DT_TZINFO(self), self);
5516 : : }
5517 : :
5518 : : static PyObject *
5519 : 0 : datetime_dst(PyObject *self, PyObject *unused) {
5520 [ # # ]: 0 : return call_dst(GET_DT_TZINFO(self), self);
5521 : : }
5522 : :
5523 : : static PyObject *
5524 : 0 : datetime_tzname(PyObject *self, PyObject *unused) {
5525 [ # # ]: 0 : return call_tzname(GET_DT_TZINFO(self), self);
5526 : : }
5527 : :
5528 : : /*
5529 : : * datetime arithmetic.
5530 : : */
5531 : :
5532 : : /* factor must be 1 (to add) or -1 (to subtract). The result inherits
5533 : : * the tzinfo state of date.
5534 : : */
5535 : : static PyObject *
5536 : 0 : add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta,
5537 : : int factor)
5538 : : {
5539 : : /* Note that the C-level additions can't overflow, because of
5540 : : * invariant bounds on the member values.
5541 : : */
5542 : 0 : int year = GET_YEAR(date);
5543 : 0 : int month = GET_MONTH(date);
5544 : 0 : int day = GET_DAY(date) + GET_TD_DAYS(delta) * factor;
5545 : 0 : int hour = DATE_GET_HOUR(date);
5546 : 0 : int minute = DATE_GET_MINUTE(date);
5547 : 0 : int second = DATE_GET_SECOND(date) + GET_TD_SECONDS(delta) * factor;
5548 : 0 : int microsecond = DATE_GET_MICROSECOND(date) +
5549 : 0 : GET_TD_MICROSECONDS(delta) * factor;
5550 : :
5551 : : assert(factor == 1 || factor == -1);
5552 [ # # ]: 0 : if (normalize_datetime(&year, &month, &day,
5553 : : &hour, &minute, &second, µsecond) < 0) {
5554 : 0 : return NULL;
5555 : : }
5556 : :
5557 : 0 : return new_datetime_subclass_ex(year, month, day,
5558 : : hour, minute, second, microsecond,
5559 [ # # ]: 0 : HASTZINFO(date) ? date->tzinfo : Py_None,
5560 : 0 : (PyObject *)Py_TYPE(date));
5561 : : }
5562 : :
5563 : : static PyObject *
5564 : 0 : datetime_add(PyObject *left, PyObject *right)
5565 : : {
5566 [ # # ]: 0 : if (PyDateTime_Check(left)) {
5567 : : /* datetime + ??? */
5568 [ # # ]: 0 : if (PyDelta_Check(right))
5569 : : /* datetime + delta */
5570 : 0 : return add_datetime_timedelta(
5571 : : (PyDateTime_DateTime *)left,
5572 : : (PyDateTime_Delta *)right,
5573 : : 1);
5574 : : }
5575 [ # # ]: 0 : else if (PyDelta_Check(left)) {
5576 : : /* delta + datetime */
5577 : 0 : return add_datetime_timedelta((PyDateTime_DateTime *) right,
5578 : : (PyDateTime_Delta *) left,
5579 : : 1);
5580 : : }
5581 : 0 : Py_RETURN_NOTIMPLEMENTED;
5582 : : }
5583 : :
5584 : : static PyObject *
5585 : 0 : datetime_subtract(PyObject *left, PyObject *right)
5586 : : {
5587 : 0 : PyObject *result = Py_NotImplemented;
5588 : :
5589 [ # # ]: 0 : if (PyDateTime_Check(left)) {
5590 : : /* datetime - ??? */
5591 [ # # ]: 0 : if (PyDateTime_Check(right)) {
5592 : : /* datetime - datetime */
5593 : 0 : PyObject *offset1, *offset2, *offdiff = NULL;
5594 : : int delta_d, delta_s, delta_us;
5595 : :
5596 [ # # # # : 0 : if (GET_DT_TZINFO(left) == GET_DT_TZINFO(right)) {
# # ]
5597 : 0 : offset1 = Py_NewRef(Py_None);
5598 : 0 : offset2 = Py_NewRef(Py_None);
5599 : : }
5600 : : else {
5601 : 0 : offset1 = datetime_utcoffset(left, NULL);
5602 [ # # ]: 0 : if (offset1 == NULL)
5603 : 0 : return NULL;
5604 : 0 : offset2 = datetime_utcoffset(right, NULL);
5605 [ # # ]: 0 : if (offset2 == NULL) {
5606 : 0 : Py_DECREF(offset1);
5607 : 0 : return NULL;
5608 : : }
5609 [ # # ]: 0 : if ((offset1 != Py_None) != (offset2 != Py_None)) {
5610 : 0 : PyErr_SetString(PyExc_TypeError,
5611 : : "can't subtract offset-naive and "
5612 : : "offset-aware datetimes");
5613 : 0 : Py_DECREF(offset1);
5614 : 0 : Py_DECREF(offset2);
5615 : 0 : return NULL;
5616 : : }
5617 : : }
5618 [ # # # # ]: 0 : if ((offset1 != offset2) &&
5619 : 0 : delta_cmp(offset1, offset2) != 0) {
5620 : 0 : offdiff = delta_subtract(offset1, offset2);
5621 [ # # ]: 0 : if (offdiff == NULL) {
5622 : 0 : Py_DECREF(offset1);
5623 : 0 : Py_DECREF(offset2);
5624 : 0 : return NULL;
5625 : : }
5626 : : }
5627 : 0 : Py_DECREF(offset1);
5628 : 0 : Py_DECREF(offset2);
5629 : 0 : delta_d = ymd_to_ord(GET_YEAR(left),
5630 : 0 : GET_MONTH(left),
5631 : 0 : GET_DAY(left)) -
5632 : 0 : ymd_to_ord(GET_YEAR(right),
5633 : 0 : GET_MONTH(right),
5634 : 0 : GET_DAY(right));
5635 : : /* These can't overflow, since the values are
5636 : : * normalized. At most this gives the number of
5637 : : * seconds in one day.
5638 : : */
5639 : 0 : delta_s = (DATE_GET_HOUR(left) -
5640 : 0 : DATE_GET_HOUR(right)) * 3600 +
5641 : 0 : (DATE_GET_MINUTE(left) -
5642 : 0 : DATE_GET_MINUTE(right)) * 60 +
5643 : 0 : (DATE_GET_SECOND(left) -
5644 : 0 : DATE_GET_SECOND(right));
5645 : 0 : delta_us = DATE_GET_MICROSECOND(left) -
5646 : 0 : DATE_GET_MICROSECOND(right);
5647 : 0 : result = new_delta(delta_d, delta_s, delta_us, 1);
5648 [ # # ]: 0 : if (result == NULL)
5649 : 0 : return NULL;
5650 : :
5651 [ # # ]: 0 : if (offdiff != NULL) {
5652 : 0 : Py_SETREF(result, delta_subtract(result, offdiff));
5653 : 0 : Py_DECREF(offdiff);
5654 : : }
5655 : : }
5656 [ # # ]: 0 : else if (PyDelta_Check(right)) {
5657 : : /* datetime - delta */
5658 : 0 : result = add_datetime_timedelta(
5659 : : (PyDateTime_DateTime *)left,
5660 : : (PyDateTime_Delta *)right,
5661 : : -1);
5662 : : }
5663 : : }
5664 : :
5665 [ # # ]: 0 : if (result == Py_NotImplemented)
5666 : 0 : Py_INCREF(result);
5667 : 0 : return result;
5668 : : }
5669 : :
5670 : : /* Various ways to turn a datetime into a string. */
5671 : :
5672 : : static PyObject *
5673 : 0 : datetime_repr(PyDateTime_DateTime *self)
5674 : : {
5675 : 0 : const char *type_name = Py_TYPE(self)->tp_name;
5676 : : PyObject *baserepr;
5677 : :
5678 [ # # ]: 0 : if (DATE_GET_MICROSECOND(self)) {
5679 : 0 : baserepr = PyUnicode_FromFormat(
5680 : : "%s(%d, %d, %d, %d, %d, %d, %d)",
5681 : : type_name,
5682 : 0 : GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
5683 : 0 : DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
5684 : 0 : DATE_GET_SECOND(self),
5685 : 0 : DATE_GET_MICROSECOND(self));
5686 : : }
5687 [ # # ]: 0 : else if (DATE_GET_SECOND(self)) {
5688 : 0 : baserepr = PyUnicode_FromFormat(
5689 : : "%s(%d, %d, %d, %d, %d, %d)",
5690 : : type_name,
5691 : 0 : GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
5692 : 0 : DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
5693 : 0 : DATE_GET_SECOND(self));
5694 : : }
5695 : : else {
5696 : 0 : baserepr = PyUnicode_FromFormat(
5697 : : "%s(%d, %d, %d, %d, %d)",
5698 : : type_name,
5699 : 0 : GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
5700 : 0 : DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
5701 : : }
5702 [ # # # # ]: 0 : if (baserepr != NULL && DATE_GET_FOLD(self) != 0)
5703 : 0 : baserepr = append_keyword_fold(baserepr, DATE_GET_FOLD(self));
5704 [ # # # # ]: 0 : if (baserepr == NULL || ! HASTZINFO(self))
5705 : 0 : return baserepr;
5706 : 0 : return append_keyword_tzinfo(baserepr, self->tzinfo);
5707 : : }
5708 : :
5709 : : static PyObject *
5710 : 0 : datetime_str(PyDateTime_DateTime *self)
5711 : : {
5712 : 0 : PyObject *space = PyUnicode_FromString(" ");
5713 [ # # ]: 0 : if (space == NULL) {
5714 : 0 : return NULL;
5715 : : }
5716 : 0 : PyObject *res = PyObject_CallMethodOneArg((PyObject *)self,
5717 : : &_Py_ID(isoformat), space);
5718 : 0 : Py_DECREF(space);
5719 : 0 : return res;
5720 : : }
5721 : :
5722 : : static PyObject *
5723 : 0 : datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
5724 : : {
5725 : 0 : int sep = 'T';
5726 : 0 : char *timespec = NULL;
5727 : : static char *keywords[] = {"sep", "timespec", NULL};
5728 : : char buffer[100];
5729 : 0 : PyObject *result = NULL;
5730 : 0 : int us = DATE_GET_MICROSECOND(self);
5731 : : static const char *specs[][2] = {
5732 : : {"hours", "%04d-%02d-%02d%c%02d"},
5733 : : {"minutes", "%04d-%02d-%02d%c%02d:%02d"},
5734 : : {"seconds", "%04d-%02d-%02d%c%02d:%02d:%02d"},
5735 : : {"milliseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%03d"},
5736 : : {"microseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%06d"},
5737 : : };
5738 : : size_t given_spec;
5739 : :
5740 [ # # ]: 0 : if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, ×pec))
5741 : 0 : return NULL;
5742 : :
5743 [ # # # # ]: 0 : if (timespec == NULL || strcmp(timespec, "auto") == 0) {
5744 [ # # ]: 0 : if (us == 0) {
5745 : : /* seconds */
5746 : 0 : given_spec = 2;
5747 : : }
5748 : : else {
5749 : : /* microseconds */
5750 : 0 : given_spec = 4;
5751 : : }
5752 : : }
5753 : : else {
5754 [ # # ]: 0 : for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
5755 [ # # ]: 0 : if (strcmp(timespec, specs[given_spec][0]) == 0) {
5756 [ # # ]: 0 : if (given_spec == 3) {
5757 : 0 : us = us / 1000;
5758 : : }
5759 : 0 : break;
5760 : : }
5761 : : }
5762 : : }
5763 : :
5764 [ # # ]: 0 : if (given_spec == Py_ARRAY_LENGTH(specs)) {
5765 : 0 : PyErr_Format(PyExc_ValueError, "Unknown timespec value");
5766 : 0 : return NULL;
5767 : : }
5768 : : else {
5769 : 0 : result = PyUnicode_FromFormat(specs[given_spec][1],
5770 : 0 : GET_YEAR(self), GET_MONTH(self),
5771 : 0 : GET_DAY(self), (int)sep,
5772 : 0 : DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
5773 : 0 : DATE_GET_SECOND(self), us);
5774 : : }
5775 : :
5776 [ # # # # ]: 0 : if (!result || !HASTZINFO(self))
5777 : 0 : return result;
5778 : :
5779 : : /* We need to append the UTC offset. */
5780 [ # # ]: 0 : if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo,
5781 : : (PyObject *)self) < 0) {
5782 : 0 : Py_DECREF(result);
5783 : 0 : return NULL;
5784 : : }
5785 : 0 : PyUnicode_AppendAndDel(&result, PyUnicode_FromString(buffer));
5786 : 0 : return result;
5787 : : }
5788 : :
5789 : : static PyObject *
5790 : 0 : datetime_ctime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
5791 : : {
5792 : 0 : return format_ctime((PyDateTime_Date *)self,
5793 : 0 : DATE_GET_HOUR(self),
5794 : 0 : DATE_GET_MINUTE(self),
5795 : 0 : DATE_GET_SECOND(self));
5796 : : }
5797 : :
5798 : : /* Miscellaneous methods. */
5799 : :
5800 : : static PyObject *
5801 : 0 : flip_fold(PyObject *dt)
5802 : : {
5803 : 0 : return new_datetime_ex2(GET_YEAR(dt),
5804 : 0 : GET_MONTH(dt),
5805 : 0 : GET_DAY(dt),
5806 : 0 : DATE_GET_HOUR(dt),
5807 : 0 : DATE_GET_MINUTE(dt),
5808 : 0 : DATE_GET_SECOND(dt),
5809 : 0 : DATE_GET_MICROSECOND(dt),
5810 : 0 : HASTZINFO(dt) ?
5811 : : ((PyDateTime_DateTime *)dt)->tzinfo : Py_None,
5812 [ # # ]: 0 : !DATE_GET_FOLD(dt),
5813 : : Py_TYPE(dt));
5814 : : }
5815 : :
5816 : : static PyObject *
5817 : 0 : get_flip_fold_offset(PyObject *dt)
5818 : : {
5819 : : PyObject *result, *flip_dt;
5820 : :
5821 : 0 : flip_dt = flip_fold(dt);
5822 [ # # ]: 0 : if (flip_dt == NULL)
5823 : 0 : return NULL;
5824 : 0 : result = datetime_utcoffset(flip_dt, NULL);
5825 : 0 : Py_DECREF(flip_dt);
5826 : 0 : return result;
5827 : : }
5828 : :
5829 : : /* PEP 495 exception: Whenever one or both of the operands in
5830 : : * inter-zone comparison is such that its utcoffset() depends
5831 : : * on the value of its fold attribute, the result is False.
5832 : : *
5833 : : * Return 1 if exception applies, 0 if not, and -1 on error.
5834 : : */
5835 : : static int
5836 : 0 : pep495_eq_exception(PyObject *self, PyObject *other,
5837 : : PyObject *offset_self, PyObject *offset_other)
5838 : : {
5839 : 0 : int result = 0;
5840 : : PyObject *flip_offset;
5841 : :
5842 : 0 : flip_offset = get_flip_fold_offset(self);
5843 [ # # ]: 0 : if (flip_offset == NULL)
5844 : 0 : return -1;
5845 [ # # # # ]: 0 : if (flip_offset != offset_self &&
5846 : 0 : delta_cmp(flip_offset, offset_self))
5847 : : {
5848 : 0 : result = 1;
5849 : 0 : goto done;
5850 : : }
5851 : 0 : Py_DECREF(flip_offset);
5852 : :
5853 : 0 : flip_offset = get_flip_fold_offset(other);
5854 [ # # ]: 0 : if (flip_offset == NULL)
5855 : 0 : return -1;
5856 [ # # # # ]: 0 : if (flip_offset != offset_other &&
5857 : 0 : delta_cmp(flip_offset, offset_other))
5858 : 0 : result = 1;
5859 : 0 : done:
5860 : 0 : Py_DECREF(flip_offset);
5861 : 0 : return result;
5862 : : }
5863 : :
5864 : : static PyObject *
5865 : 0 : datetime_richcompare(PyObject *self, PyObject *other, int op)
5866 : : {
5867 : 0 : PyObject *result = NULL;
5868 : : PyObject *offset1, *offset2;
5869 : : int diff;
5870 : :
5871 [ # # ]: 0 : if (! PyDateTime_Check(other)) {
5872 [ # # ]: 0 : if (PyDate_Check(other)) {
5873 : : /* Prevent invocation of date_richcompare. We want to
5874 : : return NotImplemented here to give the other object
5875 : : a chance. But since DateTime is a subclass of
5876 : : Date, if the other object is a Date, it would
5877 : : compute an ordering based on the date part alone,
5878 : : and we don't want that. So force unequal or
5879 : : uncomparable here in that case. */
5880 [ # # ]: 0 : if (op == Py_EQ)
5881 : 0 : Py_RETURN_FALSE;
5882 [ # # ]: 0 : if (op == Py_NE)
5883 : 0 : Py_RETURN_TRUE;
5884 : 0 : return cmperror(self, other);
5885 : : }
5886 : 0 : Py_RETURN_NOTIMPLEMENTED;
5887 : : }
5888 : :
5889 [ # # # # : 0 : if (GET_DT_TZINFO(self) == GET_DT_TZINFO(other)) {
# # ]
5890 : 0 : diff = memcmp(((PyDateTime_DateTime *)self)->data,
5891 : 0 : ((PyDateTime_DateTime *)other)->data,
5892 : : _PyDateTime_DATETIME_DATASIZE);
5893 : 0 : return diff_to_bool(diff, op);
5894 : : }
5895 : 0 : offset1 = datetime_utcoffset(self, NULL);
5896 [ # # ]: 0 : if (offset1 == NULL)
5897 : 0 : return NULL;
5898 : 0 : offset2 = datetime_utcoffset(other, NULL);
5899 [ # # ]: 0 : if (offset2 == NULL)
5900 : 0 : goto done;
5901 : : /* If they're both naive, or both aware and have the same offsets,
5902 : : * we get off cheap. Note that if they're both naive, offset1 ==
5903 : : * offset2 == Py_None at this point.
5904 : : */
5905 [ # # # # ]: 0 : if ((offset1 == offset2) ||
5906 [ # # # # ]: 0 : (PyDelta_Check(offset1) && PyDelta_Check(offset2) &&
5907 : 0 : delta_cmp(offset1, offset2) == 0)) {
5908 : 0 : diff = memcmp(((PyDateTime_DateTime *)self)->data,
5909 : 0 : ((PyDateTime_DateTime *)other)->data,
5910 : : _PyDateTime_DATETIME_DATASIZE);
5911 [ # # # # : 0 : if ((op == Py_EQ || op == Py_NE) && diff == 0) {
# # ]
5912 : 0 : int ex = pep495_eq_exception(self, other, offset1, offset2);
5913 [ # # ]: 0 : if (ex == -1)
5914 : 0 : goto done;
5915 [ # # ]: 0 : if (ex)
5916 : 0 : diff = 1;
5917 : : }
5918 : 0 : result = diff_to_bool(diff, op);
5919 : : }
5920 [ # # # # ]: 0 : else if (offset1 != Py_None && offset2 != Py_None) {
5921 : : PyDateTime_Delta *delta;
5922 : :
5923 : : assert(offset1 != offset2); /* else last "if" handled it */
5924 : 0 : delta = (PyDateTime_Delta *)datetime_subtract((PyObject *)self,
5925 : : other);
5926 [ # # ]: 0 : if (delta == NULL)
5927 : 0 : goto done;
5928 : 0 : diff = GET_TD_DAYS(delta);
5929 [ # # ]: 0 : if (diff == 0)
5930 : 0 : diff = GET_TD_SECONDS(delta) |
5931 : 0 : GET_TD_MICROSECONDS(delta);
5932 : 0 : Py_DECREF(delta);
5933 [ # # # # : 0 : if ((op == Py_EQ || op == Py_NE) && diff == 0) {
# # ]
5934 : 0 : int ex = pep495_eq_exception(self, other, offset1, offset2);
5935 [ # # ]: 0 : if (ex == -1)
5936 : 0 : goto done;
5937 [ # # ]: 0 : if (ex)
5938 : 0 : diff = 1;
5939 : : }
5940 : 0 : result = diff_to_bool(diff, op);
5941 : : }
5942 [ # # ]: 0 : else if (op == Py_EQ) {
5943 : 0 : result = Py_NewRef(Py_False);
5944 : : }
5945 [ # # ]: 0 : else if (op == Py_NE) {
5946 : 0 : result = Py_NewRef(Py_True);
5947 : : }
5948 : : else {
5949 : 0 : PyErr_SetString(PyExc_TypeError,
5950 : : "can't compare offset-naive and "
5951 : : "offset-aware datetimes");
5952 : : }
5953 : 0 : done:
5954 : 0 : Py_DECREF(offset1);
5955 : 0 : Py_XDECREF(offset2);
5956 : 0 : return result;
5957 : : }
5958 : :
5959 : : static Py_hash_t
5960 : 0 : datetime_hash(PyDateTime_DateTime *self)
5961 : : {
5962 [ # # ]: 0 : if (self->hashcode == -1) {
5963 : : PyObject *offset, *self0;
5964 [ # # ]: 0 : if (DATE_GET_FOLD(self)) {
5965 : 0 : self0 = new_datetime_ex2(GET_YEAR(self),
5966 : 0 : GET_MONTH(self),
5967 : 0 : GET_DAY(self),
5968 : 0 : DATE_GET_HOUR(self),
5969 : 0 : DATE_GET_MINUTE(self),
5970 : 0 : DATE_GET_SECOND(self),
5971 : 0 : DATE_GET_MICROSECOND(self),
5972 [ # # ]: 0 : HASTZINFO(self) ? self->tzinfo : Py_None,
5973 : : 0, Py_TYPE(self));
5974 [ # # ]: 0 : if (self0 == NULL)
5975 : 0 : return -1;
5976 : : }
5977 : : else {
5978 : 0 : self0 = Py_NewRef(self);
5979 : : }
5980 : 0 : offset = datetime_utcoffset(self0, NULL);
5981 : 0 : Py_DECREF(self0);
5982 : :
5983 [ # # ]: 0 : if (offset == NULL)
5984 : 0 : return -1;
5985 : :
5986 : : /* Reduce this to a hash of another object. */
5987 [ # # ]: 0 : if (offset == Py_None)
5988 : 0 : self->hashcode = generic_hash(
5989 : 0 : (unsigned char *)self->data, _PyDateTime_DATETIME_DATASIZE);
5990 : : else {
5991 : : PyObject *temp1, *temp2;
5992 : : int days, seconds;
5993 : :
5994 : : assert(HASTZINFO(self));
5995 : 0 : days = ymd_to_ord(GET_YEAR(self),
5996 : 0 : GET_MONTH(self),
5997 : 0 : GET_DAY(self));
5998 : 0 : seconds = DATE_GET_HOUR(self) * 3600 +
5999 : 0 : DATE_GET_MINUTE(self) * 60 +
6000 : 0 : DATE_GET_SECOND(self);
6001 : 0 : temp1 = new_delta(days, seconds,
6002 : : DATE_GET_MICROSECOND(self),
6003 : : 1);
6004 [ # # ]: 0 : if (temp1 == NULL) {
6005 : 0 : Py_DECREF(offset);
6006 : 0 : return -1;
6007 : : }
6008 : 0 : temp2 = delta_subtract(temp1, offset);
6009 : 0 : Py_DECREF(temp1);
6010 [ # # ]: 0 : if (temp2 == NULL) {
6011 : 0 : Py_DECREF(offset);
6012 : 0 : return -1;
6013 : : }
6014 : 0 : self->hashcode = PyObject_Hash(temp2);
6015 : 0 : Py_DECREF(temp2);
6016 : : }
6017 : 0 : Py_DECREF(offset);
6018 : : }
6019 : 0 : return self->hashcode;
6020 : : }
6021 : :
6022 : : static PyObject *
6023 : 0 : datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
6024 : : {
6025 : : PyObject *clone;
6026 : : PyObject *tuple;
6027 : 0 : int y = GET_YEAR(self);
6028 : 0 : int m = GET_MONTH(self);
6029 : 0 : int d = GET_DAY(self);
6030 : 0 : int hh = DATE_GET_HOUR(self);
6031 : 0 : int mm = DATE_GET_MINUTE(self);
6032 : 0 : int ss = DATE_GET_SECOND(self);
6033 : 0 : int us = DATE_GET_MICROSECOND(self);
6034 [ # # ]: 0 : PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
6035 : 0 : int fold = DATE_GET_FOLD(self);
6036 : :
6037 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO$i:replace",
6038 : : datetime_kws,
6039 : : &y, &m, &d, &hh, &mm, &ss, &us,
6040 : : &tzinfo, &fold))
6041 : 0 : return NULL;
6042 [ # # # # ]: 0 : if (fold != 0 && fold != 1) {
6043 : 0 : PyErr_SetString(PyExc_ValueError,
6044 : : "fold must be either 0 or 1");
6045 : 0 : return NULL;
6046 : : }
6047 : 0 : tuple = Py_BuildValue("iiiiiiiO", y, m, d, hh, mm, ss, us, tzinfo);
6048 [ # # ]: 0 : if (tuple == NULL)
6049 : 0 : return NULL;
6050 : 0 : clone = datetime_new(Py_TYPE(self), tuple, NULL);
6051 [ # # ]: 0 : if (clone != NULL) {
6052 : 0 : DATE_SET_FOLD(clone, fold);
6053 : : }
6054 : 0 : Py_DECREF(tuple);
6055 : 0 : return clone;
6056 : : }
6057 : :
6058 : : static PyObject *
6059 : 0 : local_timezone_from_timestamp(time_t timestamp)
6060 : : {
6061 : 0 : PyObject *result = NULL;
6062 : : PyObject *delta;
6063 : : struct tm local_time_tm;
6064 : 0 : PyObject *nameo = NULL;
6065 : 0 : const char *zone = NULL;
6066 : :
6067 [ # # ]: 0 : if (_PyTime_localtime(timestamp, &local_time_tm) != 0)
6068 : 0 : return NULL;
6069 : : #ifdef HAVE_STRUCT_TM_TM_ZONE
6070 : 0 : zone = local_time_tm.tm_zone;
6071 : 0 : delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
6072 : : #else /* HAVE_STRUCT_TM_TM_ZONE */
6073 : : {
6074 : : PyObject *local_time, *utc_time;
6075 : : struct tm utc_time_tm;
6076 : : char buf[100];
6077 : : strftime(buf, sizeof(buf), "%Z", &local_time_tm);
6078 : : zone = buf;
6079 : : local_time = new_datetime(local_time_tm.tm_year + 1900,
6080 : : local_time_tm.tm_mon + 1,
6081 : : local_time_tm.tm_mday,
6082 : : local_time_tm.tm_hour,
6083 : : local_time_tm.tm_min,
6084 : : local_time_tm.tm_sec, 0, Py_None, 0);
6085 : : if (local_time == NULL) {
6086 : : return NULL;
6087 : : }
6088 : : if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0)
6089 : : return NULL;
6090 : : utc_time = new_datetime(utc_time_tm.tm_year + 1900,
6091 : : utc_time_tm.tm_mon + 1,
6092 : : utc_time_tm.tm_mday,
6093 : : utc_time_tm.tm_hour,
6094 : : utc_time_tm.tm_min,
6095 : : utc_time_tm.tm_sec, 0, Py_None, 0);
6096 : : if (utc_time == NULL) {
6097 : : Py_DECREF(local_time);
6098 : : return NULL;
6099 : : }
6100 : : delta = datetime_subtract(local_time, utc_time);
6101 : : Py_DECREF(local_time);
6102 : : Py_DECREF(utc_time);
6103 : : }
6104 : : #endif /* HAVE_STRUCT_TM_TM_ZONE */
6105 [ # # ]: 0 : if (delta == NULL) {
6106 : 0 : return NULL;
6107 : : }
6108 [ # # ]: 0 : if (zone != NULL) {
6109 : 0 : nameo = PyUnicode_DecodeLocale(zone, "surrogateescape");
6110 [ # # ]: 0 : if (nameo == NULL)
6111 : 0 : goto error;
6112 : : }
6113 : 0 : result = new_timezone(delta, nameo);
6114 : 0 : Py_XDECREF(nameo);
6115 : 0 : error:
6116 : 0 : Py_DECREF(delta);
6117 : 0 : return result;
6118 : : }
6119 : :
6120 : : static PyObject *
6121 : 0 : local_timezone(PyDateTime_DateTime *utc_time)
6122 : : {
6123 : : time_t timestamp;
6124 : : PyObject *delta;
6125 : : PyObject *one_second;
6126 : : PyObject *seconds;
6127 : :
6128 : 0 : delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
6129 [ # # ]: 0 : if (delta == NULL)
6130 : 0 : return NULL;
6131 : 0 : one_second = new_delta(0, 1, 0, 0);
6132 [ # # ]: 0 : if (one_second == NULL) {
6133 : 0 : Py_DECREF(delta);
6134 : 0 : return NULL;
6135 : : }
6136 : 0 : seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
6137 : : (PyDateTime_Delta *)one_second);
6138 : 0 : Py_DECREF(one_second);
6139 : 0 : Py_DECREF(delta);
6140 [ # # ]: 0 : if (seconds == NULL)
6141 : 0 : return NULL;
6142 : 0 : timestamp = _PyLong_AsTime_t(seconds);
6143 : 0 : Py_DECREF(seconds);
6144 [ # # # # ]: 0 : if (timestamp == -1 && PyErr_Occurred())
6145 : 0 : return NULL;
6146 : 0 : return local_timezone_from_timestamp(timestamp);
6147 : : }
6148 : :
6149 : : static long long
6150 : : local_to_seconds(int year, int month, int day,
6151 : : int hour, int minute, int second, int fold);
6152 : :
6153 : : static PyObject *
6154 : 0 : local_timezone_from_local(PyDateTime_DateTime *local_dt)
6155 : : {
6156 : : long long seconds;
6157 : : time_t timestamp;
6158 : 0 : seconds = local_to_seconds(GET_YEAR(local_dt),
6159 : 0 : GET_MONTH(local_dt),
6160 : 0 : GET_DAY(local_dt),
6161 : 0 : DATE_GET_HOUR(local_dt),
6162 : 0 : DATE_GET_MINUTE(local_dt),
6163 : 0 : DATE_GET_SECOND(local_dt),
6164 : 0 : DATE_GET_FOLD(local_dt));
6165 [ # # ]: 0 : if (seconds == -1)
6166 : 0 : return NULL;
6167 : : /* XXX: add bounds check */
6168 : 0 : timestamp = seconds - epoch;
6169 : 0 : return local_timezone_from_timestamp(timestamp);
6170 : : }
6171 : :
6172 : : static PyDateTime_DateTime *
6173 : 0 : datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
6174 : : {
6175 : : PyDateTime_DateTime *result;
6176 : : PyObject *offset;
6177 : : PyObject *temp;
6178 : : PyObject *self_tzinfo;
6179 : 0 : PyObject *tzinfo = Py_None;
6180 : : static char *keywords[] = {"tz", NULL};
6181 : :
6182 [ # # ]: 0 : if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords,
6183 : : &tzinfo))
6184 : 0 : return NULL;
6185 : :
6186 [ # # ]: 0 : if (check_tzinfo_subclass(tzinfo) == -1)
6187 : 0 : return NULL;
6188 : :
6189 [ # # # # ]: 0 : if (!HASTZINFO(self) || self->tzinfo == Py_None) {
6190 : 0 : naive:
6191 : 0 : self_tzinfo = local_timezone_from_local(self);
6192 [ # # ]: 0 : if (self_tzinfo == NULL)
6193 : 0 : return NULL;
6194 : : } else {
6195 : 0 : self_tzinfo = Py_NewRef(self->tzinfo);
6196 : : }
6197 : :
6198 : : /* Conversion to self's own time zone is a NOP. */
6199 [ # # ]: 0 : if (self_tzinfo == tzinfo) {
6200 : 0 : Py_DECREF(self_tzinfo);
6201 : 0 : return (PyDateTime_DateTime*)Py_NewRef(self);
6202 : : }
6203 : :
6204 : : /* Convert self to UTC. */
6205 : 0 : offset = call_utcoffset(self_tzinfo, (PyObject *)self);
6206 : 0 : Py_DECREF(self_tzinfo);
6207 [ # # ]: 0 : if (offset == NULL)
6208 : 0 : return NULL;
6209 [ # # ]: 0 : else if(offset == Py_None) {
6210 : 0 : Py_DECREF(offset);
6211 : 0 : goto naive;
6212 : : }
6213 [ # # ]: 0 : else if (!PyDelta_Check(offset)) {
6214 : 0 : Py_DECREF(offset);
6215 : 0 : PyErr_Format(PyExc_TypeError, "utcoffset() returned %.200s,"
6216 : 0 : " expected timedelta or None", Py_TYPE(offset)->tp_name);
6217 : 0 : return NULL;
6218 : : }
6219 : : /* result = self - offset */
6220 : 0 : result = (PyDateTime_DateTime *)add_datetime_timedelta(self,
6221 : : (PyDateTime_Delta *)offset, -1);
6222 : 0 : Py_DECREF(offset);
6223 [ # # ]: 0 : if (result == NULL)
6224 : 0 : return NULL;
6225 : :
6226 : : /* Make sure result is aware and UTC. */
6227 [ # # ]: 0 : if (!HASTZINFO(result)) {
6228 : 0 : temp = (PyObject *)result;
6229 : : result = (PyDateTime_DateTime *)
6230 : 0 : new_datetime_ex2(GET_YEAR(result),
6231 : 0 : GET_MONTH(result),
6232 : 0 : GET_DAY(result),
6233 : 0 : DATE_GET_HOUR(result),
6234 : 0 : DATE_GET_MINUTE(result),
6235 : 0 : DATE_GET_SECOND(result),
6236 : 0 : DATE_GET_MICROSECOND(result),
6237 : : PyDateTime_TimeZone_UTC,
6238 : 0 : DATE_GET_FOLD(result),
6239 : : Py_TYPE(result));
6240 : 0 : Py_DECREF(temp);
6241 [ # # ]: 0 : if (result == NULL)
6242 : 0 : return NULL;
6243 : : }
6244 : : else {
6245 : : /* Result is already aware - just replace tzinfo. */
6246 : 0 : Py_SETREF(result->tzinfo, Py_NewRef(PyDateTime_TimeZone_UTC));
6247 : : }
6248 : :
6249 : : /* Attach new tzinfo and let fromutc() do the rest. */
6250 [ # # ]: 0 : if (tzinfo == Py_None) {
6251 : 0 : tzinfo = local_timezone(result);
6252 [ # # ]: 0 : if (tzinfo == NULL) {
6253 : 0 : Py_DECREF(result);
6254 : 0 : return NULL;
6255 : : }
6256 : : }
6257 : : else
6258 : 0 : Py_INCREF(tzinfo);
6259 : 0 : Py_SETREF(result->tzinfo, tzinfo);
6260 : :
6261 : 0 : temp = (PyObject *)result;
6262 : : result = (PyDateTime_DateTime *)
6263 : 0 : PyObject_CallMethodOneArg(tzinfo, &_Py_ID(fromutc), temp);
6264 : 0 : Py_DECREF(temp);
6265 : :
6266 : 0 : return result;
6267 : : }
6268 : :
6269 : : static PyObject *
6270 : 0 : datetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6271 : : {
6272 : 0 : int dstflag = -1;
6273 : :
6274 [ # # # # ]: 0 : if (HASTZINFO(self) && self->tzinfo != Py_None) {
6275 : : PyObject * dst;
6276 : :
6277 : 0 : dst = call_dst(self->tzinfo, (PyObject *)self);
6278 [ # # ]: 0 : if (dst == NULL)
6279 : 0 : return NULL;
6280 : :
6281 [ # # ]: 0 : if (dst != Py_None)
6282 : 0 : dstflag = delta_bool((PyDateTime_Delta *)dst);
6283 : 0 : Py_DECREF(dst);
6284 : : }
6285 : 0 : return build_struct_time(GET_YEAR(self),
6286 : 0 : GET_MONTH(self),
6287 : 0 : GET_DAY(self),
6288 : 0 : DATE_GET_HOUR(self),
6289 : 0 : DATE_GET_MINUTE(self),
6290 : 0 : DATE_GET_SECOND(self),
6291 : : dstflag);
6292 : : }
6293 : :
6294 : : static long long
6295 : 0 : local_to_seconds(int year, int month, int day,
6296 : : int hour, int minute, int second, int fold)
6297 : : {
6298 : : long long t, a, b, u1, u2, t1, t2, lt;
6299 : 0 : t = utc_to_seconds(year, month, day, hour, minute, second);
6300 : : /* Our goal is to solve t = local(u) for u. */
6301 : 0 : lt = local(t);
6302 [ # # ]: 0 : if (lt == -1)
6303 : 0 : return -1;
6304 : 0 : a = lt - t;
6305 : 0 : u1 = t - a;
6306 : 0 : t1 = local(u1);
6307 [ # # ]: 0 : if (t1 == -1)
6308 : 0 : return -1;
6309 [ # # ]: 0 : if (t1 == t) {
6310 : : /* We found one solution, but it may not be the one we need.
6311 : : * Look for an earlier solution (if `fold` is 0), or a
6312 : : * later one (if `fold` is 1). */
6313 [ # # ]: 0 : if (fold)
6314 : 0 : u2 = u1 + max_fold_seconds;
6315 : : else
6316 : 0 : u2 = u1 - max_fold_seconds;
6317 : 0 : lt = local(u2);
6318 [ # # ]: 0 : if (lt == -1)
6319 : 0 : return -1;
6320 : 0 : b = lt - u2;
6321 [ # # ]: 0 : if (a == b)
6322 : 0 : return u1;
6323 : : }
6324 : : else {
6325 : 0 : b = t1 - u1;
6326 : : assert(a != b);
6327 : : }
6328 : 0 : u2 = t - b;
6329 : 0 : t2 = local(u2);
6330 [ # # ]: 0 : if (t2 == -1)
6331 : 0 : return -1;
6332 [ # # ]: 0 : if (t2 == t)
6333 : 0 : return u2;
6334 [ # # ]: 0 : if (t1 == t)
6335 : 0 : return u1;
6336 : : /* We have found both offsets a and b, but neither t - a nor t - b is
6337 : : * a solution. This means t is in the gap. */
6338 [ # # ]: 0 : return fold?Py_MIN(u1, u2):Py_MAX(u1, u2);
6339 : : }
6340 : :
6341 : : /* date(1970,1,1).toordinal() == 719163 */
6342 : : #define EPOCH_SECONDS (719163LL * 24 * 60 * 60)
6343 : :
6344 : : static PyObject *
6345 : 0 : datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6346 : : {
6347 : : PyObject *result;
6348 : :
6349 [ # # # # ]: 0 : if (HASTZINFO(self) && self->tzinfo != Py_None) {
6350 : : PyObject *delta;
6351 : 0 : delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch);
6352 [ # # ]: 0 : if (delta == NULL)
6353 : 0 : return NULL;
6354 : 0 : result = delta_total_seconds(delta, NULL);
6355 : 0 : Py_DECREF(delta);
6356 : : }
6357 : : else {
6358 : : long long seconds;
6359 : 0 : seconds = local_to_seconds(GET_YEAR(self),
6360 : 0 : GET_MONTH(self),
6361 : 0 : GET_DAY(self),
6362 : 0 : DATE_GET_HOUR(self),
6363 : 0 : DATE_GET_MINUTE(self),
6364 : 0 : DATE_GET_SECOND(self),
6365 : 0 : DATE_GET_FOLD(self));
6366 [ # # ]: 0 : if (seconds == -1)
6367 : 0 : return NULL;
6368 : 0 : result = PyFloat_FromDouble(seconds - EPOCH_SECONDS +
6369 : 0 : DATE_GET_MICROSECOND(self) / 1e6);
6370 : : }
6371 : 0 : return result;
6372 : : }
6373 : :
6374 : : static PyObject *
6375 : 0 : datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6376 : : {
6377 : 0 : return new_date(GET_YEAR(self),
6378 : : GET_MONTH(self),
6379 : : GET_DAY(self));
6380 : : }
6381 : :
6382 : : static PyObject *
6383 : 0 : datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6384 : : {
6385 : 0 : return new_time(DATE_GET_HOUR(self),
6386 : : DATE_GET_MINUTE(self),
6387 : : DATE_GET_SECOND(self),
6388 : : DATE_GET_MICROSECOND(self),
6389 : : Py_None,
6390 : : DATE_GET_FOLD(self));
6391 : : }
6392 : :
6393 : : static PyObject *
6394 : 0 : datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6395 : : {
6396 [ # # ]: 0 : return new_time(DATE_GET_HOUR(self),
6397 : : DATE_GET_MINUTE(self),
6398 : : DATE_GET_SECOND(self),
6399 : : DATE_GET_MICROSECOND(self),
6400 : : GET_DT_TZINFO(self),
6401 : : DATE_GET_FOLD(self));
6402 : : }
6403 : :
6404 : : static PyObject *
6405 : 0 : datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
6406 : : {
6407 : : int y, m, d, hh, mm, ss;
6408 : : PyObject *tzinfo;
6409 : : PyDateTime_DateTime *utcself;
6410 : :
6411 [ # # ]: 0 : tzinfo = GET_DT_TZINFO(self);
6412 [ # # ]: 0 : if (tzinfo == Py_None) {
6413 : 0 : utcself = (PyDateTime_DateTime*)Py_NewRef(self);
6414 : : }
6415 : : else {
6416 : : PyObject *offset;
6417 : 0 : offset = call_utcoffset(tzinfo, (PyObject *)self);
6418 [ # # ]: 0 : if (offset == NULL)
6419 : 0 : return NULL;
6420 [ # # ]: 0 : if (offset == Py_None) {
6421 : 0 : Py_DECREF(offset);
6422 : 0 : utcself = (PyDateTime_DateTime*)Py_NewRef(self);
6423 : : }
6424 : : else {
6425 : 0 : utcself = (PyDateTime_DateTime *)add_datetime_timedelta(self,
6426 : : (PyDateTime_Delta *)offset, -1);
6427 : 0 : Py_DECREF(offset);
6428 [ # # ]: 0 : if (utcself == NULL)
6429 : 0 : return NULL;
6430 : : }
6431 : : }
6432 : 0 : y = GET_YEAR(utcself);
6433 : 0 : m = GET_MONTH(utcself);
6434 : 0 : d = GET_DAY(utcself);
6435 : 0 : hh = DATE_GET_HOUR(utcself);
6436 : 0 : mm = DATE_GET_MINUTE(utcself);
6437 : 0 : ss = DATE_GET_SECOND(utcself);
6438 : :
6439 : 0 : Py_DECREF(utcself);
6440 : 0 : return build_struct_time(y, m, d, hh, mm, ss, 0);
6441 : : }
6442 : :
6443 : : /* Pickle support, a simple use of __reduce__. */
6444 : :
6445 : : /* Let basestate be the non-tzinfo data string.
6446 : : * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo).
6447 : : * So it's a tuple in any (non-error) case.
6448 : : * __getstate__ isn't exposed.
6449 : : */
6450 : : static PyObject *
6451 : 0 : datetime_getstate(PyDateTime_DateTime *self, int proto)
6452 : : {
6453 : : PyObject *basestate;
6454 : 0 : PyObject *result = NULL;
6455 : :
6456 : 0 : basestate = PyBytes_FromStringAndSize((char *)self->data,
6457 : : _PyDateTime_DATETIME_DATASIZE);
6458 [ # # ]: 0 : if (basestate != NULL) {
6459 [ # # # # ]: 0 : if (proto > 3 && DATE_GET_FOLD(self))
6460 : : /* Set the first bit of the third byte */
6461 : 0 : PyBytes_AS_STRING(basestate)[2] |= (1 << 7);
6462 [ # # # # ]: 0 : if (! HASTZINFO(self) || self->tzinfo == Py_None)
6463 : 0 : result = PyTuple_Pack(1, basestate);
6464 : : else
6465 : 0 : result = PyTuple_Pack(2, basestate, self->tzinfo);
6466 : 0 : Py_DECREF(basestate);
6467 : : }
6468 : 0 : return result;
6469 : : }
6470 : :
6471 : : static PyObject *
6472 : 0 : datetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args)
6473 : : {
6474 : : int proto;
6475 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
6476 : 0 : return NULL;
6477 : :
6478 : 0 : return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto));
6479 : : }
6480 : :
6481 : : static PyObject *
6482 : 0 : datetime_reduce(PyDateTime_DateTime *self, PyObject *arg)
6483 : : {
6484 : 0 : return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2));
6485 : : }
6486 : :
6487 : : static PyMethodDef datetime_methods[] = {
6488 : :
6489 : : /* Class methods: */
6490 : :
6491 : : DATETIME_DATETIME_NOW_METHODDEF
6492 : :
6493 : : {"utcnow", (PyCFunction)datetime_utcnow,
6494 : : METH_NOARGS | METH_CLASS,
6495 : : PyDoc_STR("Return a new datetime representing UTC day and time.")},
6496 : :
6497 : : {"fromtimestamp", _PyCFunction_CAST(datetime_fromtimestamp),
6498 : : METH_VARARGS | METH_KEYWORDS | METH_CLASS,
6499 : : PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},
6500 : :
6501 : : {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,
6502 : : METH_VARARGS | METH_CLASS,
6503 : : PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")},
6504 : :
6505 : : {"strptime", (PyCFunction)datetime_strptime,
6506 : : METH_VARARGS | METH_CLASS,
6507 : : PyDoc_STR("string, format -> new datetime parsed from a string "
6508 : : "(like time.strptime()).")},
6509 : :
6510 : : {"combine", _PyCFunction_CAST(datetime_combine),
6511 : : METH_VARARGS | METH_KEYWORDS | METH_CLASS,
6512 : : PyDoc_STR("date, time -> datetime with same date and time fields")},
6513 : :
6514 : : {"fromisoformat", (PyCFunction)datetime_fromisoformat,
6515 : : METH_O | METH_CLASS,
6516 : : PyDoc_STR("string -> datetime from a string in most ISO 8601 formats")},
6517 : :
6518 : : /* Instance methods: */
6519 : :
6520 : : {"date", (PyCFunction)datetime_getdate, METH_NOARGS,
6521 : : PyDoc_STR("Return date object with same year, month and day.")},
6522 : :
6523 : : {"time", (PyCFunction)datetime_gettime, METH_NOARGS,
6524 : : PyDoc_STR("Return time object with same time but with tzinfo=None.")},
6525 : :
6526 : : {"timetz", (PyCFunction)datetime_gettimetz, METH_NOARGS,
6527 : : PyDoc_STR("Return time object with same time and tzinfo.")},
6528 : :
6529 : : {"ctime", (PyCFunction)datetime_ctime, METH_NOARGS,
6530 : : PyDoc_STR("Return ctime() style string.")},
6531 : :
6532 : : {"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS,
6533 : : PyDoc_STR("Return time tuple, compatible with time.localtime().")},
6534 : :
6535 : : {"timestamp", (PyCFunction)datetime_timestamp, METH_NOARGS,
6536 : : PyDoc_STR("Return POSIX timestamp as float.")},
6537 : :
6538 : : {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS,
6539 : : PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")},
6540 : :
6541 : : {"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS,
6542 : : PyDoc_STR("[sep] -> string in ISO 8601 format, "
6543 : : "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n"
6544 : : "sep is used to separate the year from the time, and "
6545 : : "defaults to 'T'.\n"
6546 : : "The optional argument timespec specifies the number "
6547 : : "of additional terms\nof the time to include. Valid "
6548 : : "options are 'auto', 'hours', 'minutes',\n'seconds', "
6549 : : "'milliseconds' and 'microseconds'.\n")},
6550 : :
6551 : : {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS,
6552 : : PyDoc_STR("Return self.tzinfo.utcoffset(self).")},
6553 : :
6554 : : {"tzname", (PyCFunction)datetime_tzname, METH_NOARGS,
6555 : : PyDoc_STR("Return self.tzinfo.tzname(self).")},
6556 : :
6557 : : {"dst", (PyCFunction)datetime_dst, METH_NOARGS,
6558 : : PyDoc_STR("Return self.tzinfo.dst(self).")},
6559 : :
6560 : : {"replace", _PyCFunction_CAST(datetime_replace), METH_VARARGS | METH_KEYWORDS,
6561 : : PyDoc_STR("Return datetime with new specified fields.")},
6562 : :
6563 : : {"astimezone", _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS,
6564 : : PyDoc_STR("tz -> convert to local time in new timezone tz\n")},
6565 : :
6566 : : {"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS,
6567 : : PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
6568 : :
6569 : : {"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS,
6570 : : PyDoc_STR("__reduce__() -> (cls, state)")},
6571 : :
6572 : : {NULL, NULL}
6573 : : };
6574 : :
6575 : : static const char datetime_doc[] =
6576 : : PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n\
6577 : : \n\
6578 : : The year, month and day arguments are required. tzinfo may be None, or an\n\
6579 : : instance of a tzinfo subclass. The remaining arguments may be ints.\n");
6580 : :
6581 : : static PyNumberMethods datetime_as_number = {
6582 : : datetime_add, /* nb_add */
6583 : : datetime_subtract, /* nb_subtract */
6584 : : 0, /* nb_multiply */
6585 : : 0, /* nb_remainder */
6586 : : 0, /* nb_divmod */
6587 : : 0, /* nb_power */
6588 : : 0, /* nb_negative */
6589 : : 0, /* nb_positive */
6590 : : 0, /* nb_absolute */
6591 : : 0, /* nb_bool */
6592 : : };
6593 : :
6594 : : static PyTypeObject PyDateTime_DateTimeType = {
6595 : : PyVarObject_HEAD_INIT(NULL, 0)
6596 : : "datetime.datetime", /* tp_name */
6597 : : sizeof(PyDateTime_DateTime), /* tp_basicsize */
6598 : : 0, /* tp_itemsize */
6599 : : (destructor)datetime_dealloc, /* tp_dealloc */
6600 : : 0, /* tp_vectorcall_offset */
6601 : : 0, /* tp_getattr */
6602 : : 0, /* tp_setattr */
6603 : : 0, /* tp_as_async */
6604 : : (reprfunc)datetime_repr, /* tp_repr */
6605 : : &datetime_as_number, /* tp_as_number */
6606 : : 0, /* tp_as_sequence */
6607 : : 0, /* tp_as_mapping */
6608 : : (hashfunc)datetime_hash, /* tp_hash */
6609 : : 0, /* tp_call */
6610 : : (reprfunc)datetime_str, /* tp_str */
6611 : : PyObject_GenericGetAttr, /* tp_getattro */
6612 : : 0, /* tp_setattro */
6613 : : 0, /* tp_as_buffer */
6614 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
6615 : : datetime_doc, /* tp_doc */
6616 : : 0, /* tp_traverse */
6617 : : 0, /* tp_clear */
6618 : : datetime_richcompare, /* tp_richcompare */
6619 : : 0, /* tp_weaklistoffset */
6620 : : 0, /* tp_iter */
6621 : : 0, /* tp_iternext */
6622 : : datetime_methods, /* tp_methods */
6623 : : 0, /* tp_members */
6624 : : datetime_getset, /* tp_getset */
6625 : : 0, /* tp_base; filled in
6626 : : PyInit__datetime */
6627 : : 0, /* tp_dict */
6628 : : 0, /* tp_descr_get */
6629 : : 0, /* tp_descr_set */
6630 : : 0, /* tp_dictoffset */
6631 : : 0, /* tp_init */
6632 : : datetime_alloc, /* tp_alloc */
6633 : : datetime_new, /* tp_new */
6634 : : 0, /* tp_free */
6635 : : };
6636 : :
6637 : : /* ---------------------------------------------------------------------------
6638 : : * Module methods and initialization.
6639 : : */
6640 : :
6641 : : static PyMethodDef module_methods[] = {
6642 : : {NULL, NULL}
6643 : : };
6644 : :
6645 : : /* Get a new C API by calling this function.
6646 : : * Clients get at C API via PyDateTime_IMPORT, defined in datetime.h.
6647 : : */
6648 : : static inline PyDateTime_CAPI *
6649 : 1 : get_datetime_capi(void)
6650 : : {
6651 : 1 : PyDateTime_CAPI *capi = PyMem_Malloc(sizeof(PyDateTime_CAPI));
6652 [ - + ]: 1 : if (capi == NULL) {
6653 : 0 : PyErr_NoMemory();
6654 : 0 : return NULL;
6655 : : }
6656 : 1 : capi->DateType = &PyDateTime_DateType;
6657 : 1 : capi->DateTimeType = &PyDateTime_DateTimeType;
6658 : 1 : capi->TimeType = &PyDateTime_TimeType;
6659 : 1 : capi->DeltaType = &PyDateTime_DeltaType;
6660 : 1 : capi->TZInfoType = &PyDateTime_TZInfoType;
6661 : 1 : capi->Date_FromDate = new_date_ex;
6662 : 1 : capi->DateTime_FromDateAndTime = new_datetime_ex;
6663 : 1 : capi->Time_FromTime = new_time_ex;
6664 : 1 : capi->Delta_FromDelta = new_delta_ex;
6665 : 1 : capi->TimeZone_FromTimeZone = new_timezone;
6666 : 1 : capi->DateTime_FromTimestamp = datetime_fromtimestamp;
6667 : 1 : capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi;
6668 : 1 : capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2;
6669 : 1 : capi->Time_FromTimeAndFold = new_time_ex2;
6670 : : // Make sure this function is called after PyDateTime_TimeZone_UTC has
6671 : : // been initialized.
6672 : : assert(PyDateTime_TimeZone_UTC != NULL);
6673 : 1 : capi->TimeZone_UTC = PyDateTime_TimeZone_UTC; // borrowed ref
6674 : 1 : return capi;
6675 : : }
6676 : :
6677 : : static void
6678 : 1 : datetime_destructor(PyObject *op)
6679 : : {
6680 : 1 : void *ptr = PyCapsule_GetPointer(op, PyDateTime_CAPSULE_NAME);
6681 : 1 : PyMem_Free(ptr);
6682 : 1 : }
6683 : :
6684 : : static int
6685 : 1 : _datetime_exec(PyObject *module)
6686 : : {
6687 : : // `&...` is not a constant expression according to a strict reading
6688 : : // of C standards. Fill tp_base at run-time rather than statically.
6689 : : // See https://bugs.python.org/issue40777
6690 : 1 : PyDateTime_IsoCalendarDateType.tp_base = &PyTuple_Type;
6691 : 1 : PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType;
6692 : 1 : PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType;
6693 : :
6694 : 1 : PyTypeObject *types[] = {
6695 : : &PyDateTime_DateType,
6696 : : &PyDateTime_DateTimeType,
6697 : : &PyDateTime_TimeType,
6698 : : &PyDateTime_DeltaType,
6699 : : &PyDateTime_TZInfoType,
6700 : : &PyDateTime_TimeZoneType,
6701 : : };
6702 : :
6703 [ + + ]: 7 : for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
6704 [ - + ]: 6 : if (PyModule_AddType(module, types[i]) < 0) {
6705 : 0 : return -1;
6706 : : }
6707 : : }
6708 : :
6709 [ - + ]: 1 : if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) {
6710 : 0 : return -1;
6711 : : }
6712 : :
6713 : : #define DATETIME_ADD_MACRO(dict, c, value_expr) \
6714 : : do { \
6715 : : PyObject *value = (value_expr); \
6716 : : if (value == NULL) { \
6717 : : return -1; \
6718 : : } \
6719 : : if (PyDict_SetItemString(dict, c, value) < 0) { \
6720 : : Py_DECREF(value); \
6721 : : return -1; \
6722 : : } \
6723 : : Py_DECREF(value); \
6724 : : } while(0)
6725 : :
6726 : : /* timedelta values */
6727 : 1 : PyObject *d = PyDateTime_DeltaType.tp_dict;
6728 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
6729 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
6730 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "max",
6731 : : new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
6732 : :
6733 : : /* date values */
6734 : 1 : d = PyDateTime_DateType.tp_dict;
6735 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
6736 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
6737 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
6738 : :
6739 : : /* time values */
6740 : 1 : d = PyDateTime_TimeType.tp_dict;
6741 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
6742 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
6743 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
6744 : :
6745 : : /* datetime values */
6746 : 1 : d = PyDateTime_DateTimeType.tp_dict;
6747 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "min",
6748 : : new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
6749 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
6750 : : 999999, Py_None, 0));
6751 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
6752 : :
6753 : : /* timezone values */
6754 : 1 : d = PyDateTime_TimeZoneType.tp_dict;
6755 : 1 : PyObject *delta = new_delta(0, 0, 0, 0);
6756 [ - + ]: 1 : if (delta == NULL) {
6757 : 0 : return -1;
6758 : : }
6759 : :
6760 : 1 : PyObject *x = create_timezone(delta, NULL);
6761 : 1 : Py_DECREF(delta);
6762 [ - + ]: 1 : if (x == NULL) {
6763 : 0 : return -1;
6764 : : }
6765 [ - + ]: 1 : if (PyDict_SetItemString(d, "utc", x) < 0) {
6766 : 0 : Py_DECREF(x);
6767 : 0 : return -1;
6768 : : }
6769 : :
6770 : 1 : PyDateTime_TimeZone_UTC = x;
6771 : :
6772 : : /* bpo-37642: These attributes are rounded to the nearest minute for backwards
6773 : : * compatibility, even though the constructor will accept a wider range of
6774 : : * values. This may change in the future.*/
6775 : 1 : delta = new_delta(-1, 60, 0, 1); /* -23:59 */
6776 [ - + ]: 1 : if (delta == NULL) {
6777 : 0 : return -1;
6778 : : }
6779 : :
6780 : 1 : x = create_timezone(delta, NULL);
6781 : 1 : Py_DECREF(delta);
6782 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "min", x);
6783 : :
6784 : 1 : delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
6785 [ - + ]: 1 : if (delta == NULL) {
6786 : 0 : return -1;
6787 : : }
6788 : :
6789 : 1 : x = create_timezone(delta, NULL);
6790 : 1 : Py_DECREF(delta);
6791 [ - + - + ]: 1 : DATETIME_ADD_MACRO(d, "max", x);
6792 : :
6793 : : /* Epoch */
6794 : 1 : PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
6795 : : PyDateTime_TimeZone_UTC, 0);
6796 [ - + ]: 1 : if (PyDateTime_Epoch == NULL) {
6797 : 0 : return -1;
6798 : : }
6799 : :
6800 : : /* module initialization */
6801 [ - + ]: 1 : if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
6802 : 0 : return -1;
6803 : : }
6804 [ - + ]: 1 : if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
6805 : 0 : return -1;
6806 : : }
6807 : :
6808 : 1 : PyDateTime_CAPI *capi = get_datetime_capi();
6809 [ - + ]: 1 : if (capi == NULL) {
6810 : 0 : return -1;
6811 : : }
6812 : 1 : x = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, datetime_destructor);
6813 [ - + ]: 1 : if (x == NULL) {
6814 : 0 : PyMem_Free(capi);
6815 : 0 : return -1;
6816 : : }
6817 : :
6818 [ - + ]: 1 : if (PyModule_AddObject(module, "datetime_CAPI", x) < 0) {
6819 : 0 : Py_DECREF(x);
6820 : 0 : return -1;
6821 : : }
6822 : :
6823 [ - + ]: 1 : if (PyModule_AddObjectRef(module, "UTC", PyDateTime_TimeZone_UTC) < 0) {
6824 : 0 : return -1;
6825 : : }
6826 : :
6827 : : /* A 4-year cycle has an extra leap day over what we'd get from
6828 : : * pasting together 4 single years.
6829 : : */
6830 : : static_assert(DI4Y == 4 * 365 + 1, "DI4Y");
6831 : : assert(DI4Y == days_before_year(4+1));
6832 : :
6833 : : /* Similarly, a 400-year cycle has an extra leap day over what we'd
6834 : : * get from pasting together 4 100-year cycles.
6835 : : */
6836 : : static_assert(DI400Y == 4 * DI100Y + 1, "DI400Y");
6837 : : assert(DI400Y == days_before_year(400+1));
6838 : :
6839 : : /* OTOH, a 100-year cycle has one fewer leap day than we'd get from
6840 : : * pasting together 25 4-year cycles.
6841 : : */
6842 : : static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
6843 : : assert(DI100Y == days_before_year(100+1));
6844 : :
6845 : 1 : us_per_ms = PyLong_FromLong(1000);
6846 : 1 : us_per_second = PyLong_FromLong(1000000);
6847 : 1 : us_per_minute = PyLong_FromLong(60000000);
6848 : 1 : seconds_per_day = PyLong_FromLong(24 * 3600);
6849 [ + - + - ]: 1 : if (us_per_ms == NULL || us_per_second == NULL ||
6850 [ + - - + ]: 1 : us_per_minute == NULL || seconds_per_day == NULL) {
6851 : 0 : return -1;
6852 : : }
6853 : :
6854 : : /* The rest are too big for 32-bit ints, but even
6855 : : * us_per_week fits in 40 bits, so doubles should be exact.
6856 : : */
6857 : 1 : us_per_hour = PyLong_FromDouble(3600000000.0);
6858 : 1 : us_per_day = PyLong_FromDouble(86400000000.0);
6859 : 1 : us_per_week = PyLong_FromDouble(604800000000.0);
6860 [ + - + - : 1 : if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) {
- + ]
6861 : 0 : return -1;
6862 : : }
6863 : 1 : return 0;
6864 : : }
6865 : :
6866 : : static struct PyModuleDef datetimemodule = {
6867 : : PyModuleDef_HEAD_INIT,
6868 : : .m_name = "_datetime",
6869 : : .m_doc = "Fast implementation of the datetime type.",
6870 : : .m_size = -1,
6871 : : .m_methods = module_methods,
6872 : : };
6873 : :
6874 : : PyMODINIT_FUNC
6875 : 1 : PyInit__datetime(void)
6876 : : {
6877 : 1 : PyObject *mod = PyModule_Create(&datetimemodule);
6878 [ - + ]: 1 : if (mod == NULL)
6879 : 0 : return NULL;
6880 : :
6881 [ - + ]: 1 : if (_datetime_exec(mod) < 0) {
6882 : 0 : Py_DECREF(mod);
6883 : 0 : return NULL;
6884 : : }
6885 : :
6886 : 1 : return mod;
6887 : : }
6888 : :
6889 : : /* ---------------------------------------------------------------------------
6890 : : Some time zone algebra. For a datetime x, let
6891 : : x.n = x stripped of its timezone -- its naive time.
6892 : : x.o = x.utcoffset(), and assuming that doesn't raise an exception or
6893 : : return None
6894 : : x.d = x.dst(), and assuming that doesn't raise an exception or
6895 : : return None
6896 : : x.s = x's standard offset, x.o - x.d
6897 : :
6898 : : Now some derived rules, where k is a duration (timedelta).
6899 : :
6900 : : 1. x.o = x.s + x.d
6901 : : This follows from the definition of x.s.
6902 : :
6903 : : 2. If x and y have the same tzinfo member, x.s = y.s.
6904 : : This is actually a requirement, an assumption we need to make about
6905 : : sane tzinfo classes.
6906 : :
6907 : : 3. The naive UTC time corresponding to x is x.n - x.o.
6908 : : This is again a requirement for a sane tzinfo class.
6909 : :
6910 : : 4. (x+k).s = x.s
6911 : : This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
6912 : :
6913 : : 5. (x+k).n = x.n + k
6914 : : Again follows from how arithmetic is defined.
6915 : :
6916 : : Now we can explain tz.fromutc(x). Let's assume it's an interesting case
6917 : : (meaning that the various tzinfo methods exist, and don't blow up or return
6918 : : None when called).
6919 : :
6920 : : The function wants to return a datetime y with timezone tz, equivalent to x.
6921 : : x is already in UTC.
6922 : :
6923 : : By #3, we want
6924 : :
6925 : : y.n - y.o = x.n [1]
6926 : :
6927 : : The algorithm starts by attaching tz to x.n, and calling that y. So
6928 : : x.n = y.n at the start. Then it wants to add a duration k to y, so that [1]
6929 : : becomes true; in effect, we want to solve [2] for k:
6930 : :
6931 : : (y+k).n - (y+k).o = x.n [2]
6932 : :
6933 : : By #1, this is the same as
6934 : :
6935 : : (y+k).n - ((y+k).s + (y+k).d) = x.n [3]
6936 : :
6937 : : By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
6938 : : Substituting that into [3],
6939 : :
6940 : : x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
6941 : : k - (y+k).s - (y+k).d = 0; rearranging,
6942 : : k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
6943 : : k = y.s - (y+k).d
6944 : :
6945 : : On the RHS, (y+k).d can't be computed directly, but y.s can be, and we
6946 : : approximate k by ignoring the (y+k).d term at first. Note that k can't be
6947 : : very large, since all offset-returning methods return a duration of magnitude
6948 : : less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must
6949 : : be 0, so ignoring it has no consequence then.
6950 : :
6951 : : In any case, the new value is
6952 : :
6953 : : z = y + y.s [4]
6954 : :
6955 : : It's helpful to step back at look at [4] from a higher level: it's simply
6956 : : mapping from UTC to tz's standard time.
6957 : :
6958 : : At this point, if
6959 : :
6960 : : z.n - z.o = x.n [5]
6961 : :
6962 : : we have an equivalent time, and are almost done. The insecurity here is
6963 : : at the start of daylight time. Picture US Eastern for concreteness. The wall
6964 : : time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
6965 : : sense then. The docs ask that an Eastern tzinfo class consider such a time to
6966 : : be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
6967 : : on the day DST starts. We want to return the 1:MM EST spelling because that's
6968 : : the only spelling that makes sense on the local wall clock.
6969 : :
6970 : : In fact, if [5] holds at this point, we do have the standard-time spelling,
6971 : : but that takes a bit of proof. We first prove a stronger result. What's the
6972 : : difference between the LHS and RHS of [5]? Let
6973 : :
6974 : : diff = x.n - (z.n - z.o) [6]
6975 : :
6976 : : Now
6977 : : z.n = by [4]
6978 : : (y + y.s).n = by #5
6979 : : y.n + y.s = since y.n = x.n
6980 : : x.n + y.s = since z and y are have the same tzinfo member,
6981 : : y.s = z.s by #2
6982 : : x.n + z.s
6983 : :
6984 : : Plugging that back into [6] gives
6985 : :
6986 : : diff =
6987 : : x.n - ((x.n + z.s) - z.o) = expanding
6988 : : x.n - x.n - z.s + z.o = cancelling
6989 : : - z.s + z.o = by #2
6990 : : z.d
6991 : :
6992 : : So diff = z.d.
6993 : :
6994 : : If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
6995 : : spelling we wanted in the endcase described above. We're done. Contrarily,
6996 : : if z.d = 0, then we have a UTC equivalent, and are also done.
6997 : :
6998 : : If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
6999 : : add to z (in effect, z is in tz's standard time, and we need to shift the
7000 : : local clock into tz's daylight time).
7001 : :
7002 : : Let
7003 : :
7004 : : z' = z + z.d = z + diff [7]
7005 : :
7006 : : and we can again ask whether
7007 : :
7008 : : z'.n - z'.o = x.n [8]
7009 : :
7010 : : If so, we're done. If not, the tzinfo class is insane, according to the
7011 : : assumptions we've made. This also requires a bit of proof. As before, let's
7012 : : compute the difference between the LHS and RHS of [8] (and skipping some of
7013 : : the justifications for the kinds of substitutions we've done several times
7014 : : already):
7015 : :
7016 : : diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7]
7017 : : x.n - (z.n + diff - z'.o) = replacing diff via [6]
7018 : : x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
7019 : : x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n
7020 : : - z.n + z.n - z.o + z'.o = cancel z.n
7021 : : - z.o + z'.o = #1 twice
7022 : : -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo
7023 : : z'.d - z.d
7024 : :
7025 : : So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal,
7026 : : we've found the UTC-equivalent so are done. In fact, we stop with [7] and
7027 : : return z', not bothering to compute z'.d.
7028 : :
7029 : : How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by
7030 : : a dst() offset, and starting *from* a time already in DST (we know z.d != 0),
7031 : : would have to change the result dst() returns: we start in DST, and moving
7032 : : a little further into it takes us out of DST.
7033 : :
7034 : : There isn't a sane case where this can happen. The closest it gets is at
7035 : : the end of DST, where there's an hour in UTC with no spelling in a hybrid
7036 : : tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During
7037 : : that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
7038 : : UTC) because the docs insist on that, but 0:MM is taken as being in daylight
7039 : : time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local
7040 : : clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
7041 : : standard time. Since that's what the local clock *does*, we want to map both
7042 : : UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous
7043 : : in local time, but so it goes -- it's the way the local clock works.
7044 : :
7045 : : When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
7046 : : so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
7047 : : z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
7048 : : (correctly) concludes that z' is not UTC-equivalent to x.
7049 : :
7050 : : Because we know z.d said z was in daylight time (else [5] would have held and
7051 : : we would have stopped then), and we know z.d != z'.d (else [8] would have held
7052 : : and we would have stopped then), and there are only 2 possible values dst() can
7053 : : return in Eastern, it follows that z'.d must be 0 (which it is in the example,
7054 : : but the reasoning doesn't depend on the example -- it depends on there being
7055 : : two possible dst() outcomes, one zero and the other non-zero). Therefore
7056 : : z' must be in standard time, and is the spelling we want in this case.
7057 : :
7058 : : Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
7059 : : concerned (because it takes z' as being in standard time rather than the
7060 : : daylight time we intend here), but returning it gives the real-life "local
7061 : : clock repeats an hour" behavior when mapping the "unspellable" UTC hour into
7062 : : tz.
7063 : :
7064 : : When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
7065 : : the 1:MM standard time spelling we want.
7066 : :
7067 : : So how can this break? One of the assumptions must be violated. Two
7068 : : possibilities:
7069 : :
7070 : : 1) [2] effectively says that y.s is invariant across all y belong to a given
7071 : : time zone. This isn't true if, for political reasons or continental drift,
7072 : : a region decides to change its base offset from UTC.
7073 : :
7074 : : 2) There may be versions of "double daylight" time where the tail end of
7075 : : the analysis gives up a step too early. I haven't thought about that
7076 : : enough to say.
7077 : :
7078 : : In any case, it's clear that the default fromutc() is strong enough to handle
7079 : : "almost all" time zones: so long as the standard offset is invariant, it
7080 : : doesn't matter if daylight time transition points change from year to year, or
7081 : : if daylight time is skipped in some years; it doesn't matter how large or
7082 : : small dst() may get within its bounds; and it doesn't even matter if some
7083 : : perverse time zone returns a negative dst()). So a breaking case must be
7084 : : pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
7085 : : --------------------------------------------------------------------------- */
|