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