mirror of https://github.com/python/cpython
gh-71587: Establish global state in `_datetime` (#110475)
* Use explicit initialiser for m_base * Add module state stub; establish global state on stack * Put conversion factors in state struct * Move PyDateTime_TimeZone_UTC to state * Move PyDateTime_Epoch to state struct * Fix ref leaks in and clean up initialisation
This commit is contained in:
parent
ea530f2f9a
commit
ec5622d197
|
@ -40,6 +40,27 @@
|
||||||
|
|
||||||
#define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType)
|
#define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* Conversion factors. */
|
||||||
|
PyObject *us_per_ms; // 1_000
|
||||||
|
PyObject *us_per_second; // 1_000_000
|
||||||
|
PyObject *us_per_minute; // 1e6 * 60 as Python int
|
||||||
|
PyObject *us_per_hour; // 1e6 * 3600 as Python int
|
||||||
|
PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int
|
||||||
|
PyObject *us_per_week; // 1e6 * 3600 * 24 * 7 as Python int
|
||||||
|
PyObject *seconds_per_day; // 3600 * 24 as Python int
|
||||||
|
|
||||||
|
/* The interned UTC timezone instance */
|
||||||
|
PyObject *utc;
|
||||||
|
|
||||||
|
/* The interned Unix epoch datetime instance */
|
||||||
|
PyObject *epoch;
|
||||||
|
} datetime_state;
|
||||||
|
|
||||||
|
static datetime_state _datetime_global_state;
|
||||||
|
|
||||||
|
#define STATIC_STATE() (&_datetime_global_state)
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
module datetime
|
module datetime
|
||||||
class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
|
class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
|
||||||
|
@ -1139,11 +1160,6 @@ typedef struct
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
} PyDateTime_TimeZone;
|
} PyDateTime_TimeZone;
|
||||||
|
|
||||||
/* The interned UTC timezone instance */
|
|
||||||
static PyObject *PyDateTime_TimeZone_UTC;
|
|
||||||
/* The interned Epoch datetime instance */
|
|
||||||
static PyObject *PyDateTime_Epoch;
|
|
||||||
|
|
||||||
/* Create new timezone instance checking offset range. This
|
/* Create new timezone instance checking offset range. This
|
||||||
function does not check the name argument. Caller must assure
|
function does not check the name argument. Caller must assure
|
||||||
that offset is a timedelta instance and name is either NULL
|
that offset is a timedelta instance and name is either NULL
|
||||||
|
@ -1177,7 +1193,8 @@ new_timezone(PyObject *offset, PyObject *name)
|
||||||
assert(name == NULL || PyUnicode_Check(name));
|
assert(name == NULL || PyUnicode_Check(name));
|
||||||
|
|
||||||
if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
|
if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
|
||||||
return Py_NewRef(PyDateTime_TimeZone_UTC);
|
datetime_state *st = STATIC_STATE();
|
||||||
|
return Py_NewRef(st->utc);
|
||||||
}
|
}
|
||||||
if ((GET_TD_DAYS(offset) == -1 &&
|
if ((GET_TD_DAYS(offset) == -1 &&
|
||||||
GET_TD_SECONDS(offset) == 0 &&
|
GET_TD_SECONDS(offset) == 0 &&
|
||||||
|
@ -1390,7 +1407,8 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
// Create a timezone from offset in seconds (0 returns UTC)
|
// Create a timezone from offset in seconds (0 returns UTC)
|
||||||
if (tzoffset == 0) {
|
if (tzoffset == 0) {
|
||||||
return Py_NewRef(PyDateTime_TimeZone_UTC);
|
datetime_state *st = STATIC_STATE();
|
||||||
|
return Py_NewRef(st->utc);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
|
PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
|
||||||
|
@ -1807,19 +1825,6 @@ cmperror(PyObject *a, PyObject *b)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
|
||||||
* Cached Python objects; these are set by the module init function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Conversion factors. */
|
|
||||||
static PyObject *us_per_ms = NULL; /* 1000 */
|
|
||||||
static PyObject *us_per_second = NULL; /* 1000000 */
|
|
||||||
static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */
|
|
||||||
static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */
|
|
||||||
static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */
|
|
||||||
static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */
|
|
||||||
static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Class implementations.
|
* Class implementations.
|
||||||
*/
|
*/
|
||||||
|
@ -1845,7 +1850,8 @@ delta_to_microseconds(PyDateTime_Delta *self)
|
||||||
x1 = PyLong_FromLong(GET_TD_DAYS(self));
|
x1 = PyLong_FromLong(GET_TD_DAYS(self));
|
||||||
if (x1 == NULL)
|
if (x1 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
x2 = PyNumber_Multiply(x1, seconds_per_day); /* days in seconds */
|
datetime_state *st = STATIC_STATE();
|
||||||
|
x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */
|
||||||
if (x2 == NULL)
|
if (x2 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_SETREF(x1, NULL);
|
Py_SETREF(x1, NULL);
|
||||||
|
@ -1862,7 +1868,7 @@ delta_to_microseconds(PyDateTime_Delta *self)
|
||||||
/* x1 = */ x2 = NULL;
|
/* x1 = */ x2 = NULL;
|
||||||
|
|
||||||
/* x3 has days+seconds in seconds */
|
/* x3 has days+seconds in seconds */
|
||||||
x1 = PyNumber_Multiply(x3, us_per_second); /* us */
|
x1 = PyNumber_Multiply(x3, st->us_per_second); /* us */
|
||||||
if (x1 == NULL)
|
if (x1 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_SETREF(x3, NULL);
|
Py_SETREF(x3, NULL);
|
||||||
|
@ -1917,7 +1923,8 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
|
||||||
PyObject *num = NULL;
|
PyObject *num = NULL;
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
|
||||||
tuple = checked_divmod(pyus, us_per_second);
|
datetime_state *st = STATIC_STATE();
|
||||||
|
tuple = checked_divmod(pyus, st->us_per_second);
|
||||||
if (tuple == NULL) {
|
if (tuple == NULL) {
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
@ -1935,7 +1942,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
|
||||||
num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
|
num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
|
||||||
Py_DECREF(tuple);
|
Py_DECREF(tuple);
|
||||||
|
|
||||||
tuple = checked_divmod(num, seconds_per_day);
|
tuple = checked_divmod(num, st->seconds_per_day);
|
||||||
if (tuple == NULL)
|
if (tuple == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_DECREF(num);
|
Py_DECREF(num);
|
||||||
|
@ -2535,28 +2542,29 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
|
y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
|
datetime_state *st = STATIC_STATE();
|
||||||
if (ms) {
|
if (ms) {
|
||||||
y = accum("milliseconds", x, ms, us_per_ms, &leftover_us);
|
y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (second) {
|
if (second) {
|
||||||
y = accum("seconds", x, second, us_per_second, &leftover_us);
|
y = accum("seconds", x, second, st->us_per_second, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (minute) {
|
if (minute) {
|
||||||
y = accum("minutes", x, minute, us_per_minute, &leftover_us);
|
y = accum("minutes", x, minute, st->us_per_minute, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (hour) {
|
if (hour) {
|
||||||
y = accum("hours", x, hour, us_per_hour, &leftover_us);
|
y = accum("hours", x, hour, st->us_per_hour, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (day) {
|
if (day) {
|
||||||
y = accum("days", x, day, us_per_day, &leftover_us);
|
y = accum("days", x, day, st->us_per_day, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (week) {
|
if (week) {
|
||||||
y = accum("weeks", x, week, us_per_week, &leftover_us);
|
y = accum("weeks", x, week, st->us_per_week, &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (leftover_us) {
|
if (leftover_us) {
|
||||||
|
@ -2711,7 +2719,8 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
if (total_microseconds == NULL)
|
if (total_microseconds == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second);
|
datetime_state *st = STATIC_STATE();
|
||||||
|
total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second);
|
||||||
|
|
||||||
Py_DECREF(total_microseconds);
|
Py_DECREF(total_microseconds);
|
||||||
return total_seconds;
|
return total_seconds;
|
||||||
|
@ -3943,8 +3952,10 @@ timezone_repr(PyDateTime_TimeZone *self)
|
||||||
to use Py_TYPE(self)->tp_name here. */
|
to use Py_TYPE(self)->tp_name here. */
|
||||||
const char *type_name = Py_TYPE(self)->tp_name;
|
const char *type_name = Py_TYPE(self)->tp_name;
|
||||||
|
|
||||||
if (((PyObject *)self) == PyDateTime_TimeZone_UTC)
|
datetime_state *st = STATIC_STATE();
|
||||||
|
if (((PyObject *)self) == st->utc) {
|
||||||
return PyUnicode_FromFormat("%s.utc", type_name);
|
return PyUnicode_FromFormat("%s.utc", type_name);
|
||||||
|
}
|
||||||
|
|
||||||
if (self->name == NULL)
|
if (self->name == NULL)
|
||||||
return PyUnicode_FromFormat("%s(%R)", type_name, self->offset);
|
return PyUnicode_FromFormat("%s(%R)", type_name, self->offset);
|
||||||
|
@ -3964,11 +3975,14 @@ timezone_str(PyDateTime_TimeZone *self)
|
||||||
if (self->name != NULL) {
|
if (self->name != NULL) {
|
||||||
return Py_NewRef(self->name);
|
return Py_NewRef(self->name);
|
||||||
}
|
}
|
||||||
if ((PyObject *)self == PyDateTime_TimeZone_UTC ||
|
datetime_state *st = STATIC_STATE();
|
||||||
|
if ((PyObject *)self == st->utc ||
|
||||||
(GET_TD_DAYS(self->offset) == 0 &&
|
(GET_TD_DAYS(self->offset) == 0 &&
|
||||||
GET_TD_SECONDS(self->offset) == 0 &&
|
GET_TD_SECONDS(self->offset) == 0 &&
|
||||||
GET_TD_MICROSECONDS(self->offset) == 0))
|
GET_TD_MICROSECONDS(self->offset) == 0))
|
||||||
|
{
|
||||||
return PyUnicode_FromString("UTC");
|
return PyUnicode_FromString("UTC");
|
||||||
|
}
|
||||||
/* Offset is normalized, so it is negative if days < 0 */
|
/* Offset is normalized, so it is negative if days < 0 */
|
||||||
if (GET_TD_DAYS(self->offset) < 0) {
|
if (GET_TD_DAYS(self->offset) < 0) {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
|
@ -6134,7 +6148,8 @@ local_timezone(PyDateTime_DateTime *utc_time)
|
||||||
PyObject *one_second;
|
PyObject *one_second;
|
||||||
PyObject *seconds;
|
PyObject *seconds;
|
||||||
|
|
||||||
delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
|
datetime_state *st = STATIC_STATE();
|
||||||
|
delta = datetime_subtract((PyObject *)utc_time, st->epoch);
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
one_second = new_delta(0, 1, 0, 0);
|
one_second = new_delta(0, 1, 0, 0);
|
||||||
|
@ -6246,6 +6261,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
datetime_state *st = STATIC_STATE();
|
||||||
/* Make sure result is aware and UTC. */
|
/* Make sure result is aware and UTC. */
|
||||||
if (!HASTZINFO(result)) {
|
if (!HASTZINFO(result)) {
|
||||||
temp = (PyObject *)result;
|
temp = (PyObject *)result;
|
||||||
|
@ -6257,7 +6273,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
DATE_GET_MINUTE(result),
|
DATE_GET_MINUTE(result),
|
||||||
DATE_GET_SECOND(result),
|
DATE_GET_SECOND(result),
|
||||||
DATE_GET_MICROSECOND(result),
|
DATE_GET_MICROSECOND(result),
|
||||||
PyDateTime_TimeZone_UTC,
|
st->utc,
|
||||||
DATE_GET_FOLD(result),
|
DATE_GET_FOLD(result),
|
||||||
Py_TYPE(result));
|
Py_TYPE(result));
|
||||||
Py_DECREF(temp);
|
Py_DECREF(temp);
|
||||||
|
@ -6266,7 +6282,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Result is already aware - just replace tzinfo. */
|
/* Result is already aware - just replace tzinfo. */
|
||||||
Py_SETREF(result->tzinfo, Py_NewRef(PyDateTime_TimeZone_UTC));
|
Py_SETREF(result->tzinfo, Py_NewRef(st->utc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach new tzinfo and let fromutc() do the rest. */
|
/* Attach new tzinfo and let fromutc() do the rest. */
|
||||||
|
@ -6370,8 +6386,9 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
if (HASTZINFO(self) && self->tzinfo != Py_None) {
|
if (HASTZINFO(self) && self->tzinfo != Py_None) {
|
||||||
|
datetime_state *st = STATIC_STATE();
|
||||||
PyObject *delta;
|
PyObject *delta;
|
||||||
delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch);
|
delta = datetime_subtract((PyObject *)self, st->epoch);
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
result = delta_total_seconds(delta, NULL);
|
result = delta_total_seconds(delta, NULL);
|
||||||
|
@ -6692,10 +6709,11 @@ get_datetime_capi(void)
|
||||||
capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi;
|
capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi;
|
||||||
capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2;
|
capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2;
|
||||||
capi->Time_FromTimeAndFold = new_time_ex2;
|
capi->Time_FromTimeAndFold = new_time_ex2;
|
||||||
// Make sure this function is called after PyDateTime_TimeZone_UTC has
|
// Make sure this function is called after utc has
|
||||||
// been initialized.
|
// been initialized.
|
||||||
assert(PyDateTime_TimeZone_UTC != NULL);
|
datetime_state *st = STATIC_STATE();
|
||||||
capi->TimeZone_UTC = PyDateTime_TimeZone_UTC; // borrowed ref
|
assert(st->utc != NULL);
|
||||||
|
capi->TimeZone_UTC = st->utc; // borrowed ref
|
||||||
return capi;
|
return capi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6706,6 +6724,85 @@ datetime_destructor(PyObject *op)
|
||||||
PyMem_Free(ptr);
|
PyMem_Free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
datetime_clear(PyObject *module)
|
||||||
|
{
|
||||||
|
datetime_state *st = STATIC_STATE();
|
||||||
|
|
||||||
|
Py_CLEAR(st->us_per_ms);
|
||||||
|
Py_CLEAR(st->us_per_second);
|
||||||
|
Py_CLEAR(st->us_per_minute);
|
||||||
|
Py_CLEAR(st->us_per_hour);
|
||||||
|
Py_CLEAR(st->us_per_day);
|
||||||
|
Py_CLEAR(st->us_per_week);
|
||||||
|
Py_CLEAR(st->seconds_per_day);
|
||||||
|
Py_CLEAR(st->utc);
|
||||||
|
Py_CLEAR(st->epoch);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
create_timezone_from_delta(int days, int sec, int ms, int normalize)
|
||||||
|
{
|
||||||
|
PyObject *delta = new_delta(days, sec, ms, normalize);
|
||||||
|
if (delta == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *tz = create_timezone(delta, NULL);
|
||||||
|
Py_DECREF(delta);
|
||||||
|
return tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_state(datetime_state *st)
|
||||||
|
{
|
||||||
|
st->us_per_ms = PyLong_FromLong(1000);
|
||||||
|
if (st->us_per_ms == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
st->us_per_second = PyLong_FromLong(1000000);
|
||||||
|
if (st->us_per_second == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
st->us_per_minute = PyLong_FromLong(60000000);
|
||||||
|
if (st->us_per_minute == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
st->seconds_per_day = PyLong_FromLong(24 * 3600);
|
||||||
|
if (st->seconds_per_day == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The rest are too big for 32-bit ints, but even
|
||||||
|
* us_per_week fits in 40 bits, so doubles should be exact.
|
||||||
|
*/
|
||||||
|
st->us_per_hour = PyLong_FromDouble(3600000000.0);
|
||||||
|
if (st->us_per_hour == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
st->us_per_day = PyLong_FromDouble(86400000000.0);
|
||||||
|
if (st->us_per_day == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
st->us_per_week = PyLong_FromDouble(604800000000.0);
|
||||||
|
if (st->us_per_week == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init UTC timezone */
|
||||||
|
st->utc = create_timezone_from_delta(0, 0, 0, 0);
|
||||||
|
if (st->utc == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init Unix epoch */
|
||||||
|
st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0);
|
||||||
|
if (st->epoch == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_datetime_exec(PyObject *module)
|
_datetime_exec(PyObject *module)
|
||||||
{
|
{
|
||||||
|
@ -6727,23 +6824,23 @@ _datetime_exec(PyObject *module)
|
||||||
|
|
||||||
for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
|
for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
|
||||||
if (PyModule_AddType(module, types[i]) < 0) {
|
if (PyModule_AddType(module, types[i]) < 0) {
|
||||||
return -1;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) {
|
if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) {
|
||||||
return -1;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DATETIME_ADD_MACRO(dict, c, value_expr) \
|
#define DATETIME_ADD_MACRO(dict, c, value_expr) \
|
||||||
do { \
|
do { \
|
||||||
PyObject *value = (value_expr); \
|
PyObject *value = (value_expr); \
|
||||||
if (value == NULL) { \
|
if (value == NULL) { \
|
||||||
return -1; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
if (PyDict_SetItemString(dict, c, value) < 0) { \
|
if (PyDict_SetItemString(dict, c, value) < 0) { \
|
||||||
Py_DECREF(value); \
|
Py_DECREF(value); \
|
||||||
return -1; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
Py_DECREF(value); \
|
Py_DECREF(value); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
@ -6775,77 +6872,54 @@ _datetime_exec(PyObject *module)
|
||||||
999999, Py_None, 0));
|
999999, Py_None, 0));
|
||||||
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
||||||
|
|
||||||
|
datetime_state *st = STATIC_STATE();
|
||||||
|
if (init_state(st) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
/* timezone values */
|
/* timezone values */
|
||||||
d = PyDateTime_TimeZoneType.tp_dict;
|
d = PyDateTime_TimeZoneType.tp_dict;
|
||||||
PyObject *delta = new_delta(0, 0, 0, 0);
|
if (PyDict_SetItemString(d, "utc", st->utc) < 0) {
|
||||||
if (delta == NULL) {
|
goto error;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *x = create_timezone(delta, NULL);
|
|
||||||
Py_DECREF(delta);
|
|
||||||
if (x == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (PyDict_SetItemString(d, "utc", x) < 0) {
|
|
||||||
Py_DECREF(x);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDateTime_TimeZone_UTC = x;
|
|
||||||
|
|
||||||
/* bpo-37642: These attributes are rounded to the nearest minute for backwards
|
/* bpo-37642: These attributes are rounded to the nearest minute for backwards
|
||||||
* compatibility, even though the constructor will accept a wider range of
|
* compatibility, even though the constructor will accept a wider range of
|
||||||
* values. This may change in the future.*/
|
* values. This may change in the future.*/
|
||||||
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
|
|
||||||
if (delta == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = create_timezone(delta, NULL);
|
/* -23:59 */
|
||||||
Py_DECREF(delta);
|
PyObject *min = create_timezone_from_delta(-1, 60, 0, 1);
|
||||||
DATETIME_ADD_MACRO(d, "min", x);
|
DATETIME_ADD_MACRO(d, "min", min);
|
||||||
|
|
||||||
delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
|
/* +23:59 */
|
||||||
if (delta == NULL) {
|
PyObject *max = create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0);
|
||||||
return -1;
|
DATETIME_ADD_MACRO(d, "max", max);
|
||||||
}
|
|
||||||
|
|
||||||
x = create_timezone(delta, NULL);
|
/* Add module level attributes */
|
||||||
Py_DECREF(delta);
|
|
||||||
DATETIME_ADD_MACRO(d, "max", x);
|
|
||||||
|
|
||||||
/* Epoch */
|
|
||||||
PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
|
|
||||||
PyDateTime_TimeZone_UTC, 0);
|
|
||||||
if (PyDateTime_Epoch == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* module initialization */
|
|
||||||
if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
|
if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
|
||||||
return -1;
|
goto error;
|
||||||
}
|
}
|
||||||
if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
|
if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
|
||||||
return -1;
|
goto error;
|
||||||
|
}
|
||||||
|
if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) {
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At last, set up and add the encapsulated C API */
|
||||||
PyDateTime_CAPI *capi = get_datetime_capi();
|
PyDateTime_CAPI *capi = get_datetime_capi();
|
||||||
if (capi == NULL) {
|
if (capi == NULL) {
|
||||||
return -1;
|
goto error;
|
||||||
}
|
}
|
||||||
x = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, datetime_destructor);
|
PyObject *capsule = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME,
|
||||||
if (x == NULL) {
|
datetime_destructor);
|
||||||
|
if (capsule == NULL) {
|
||||||
PyMem_Free(capi);
|
PyMem_Free(capi);
|
||||||
return -1;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (PyModule_Add(module, "datetime_CAPI", capsule) < 0) {
|
||||||
if (PyModule_Add(module, "datetime_CAPI", x) < 0) {
|
PyMem_Free(capi);
|
||||||
return -1;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
if (PyModule_AddObjectRef(module, "UTC", PyDateTime_TimeZone_UTC) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A 4-year cycle has an extra leap day over what we'd get from
|
/* A 4-year cycle has an extra leap day over what we'd get from
|
||||||
|
@ -6866,54 +6940,16 @@ _datetime_exec(PyObject *module)
|
||||||
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
|
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
|
||||||
assert(DI100Y == days_before_year(100+1));
|
assert(DI100Y == days_before_year(100+1));
|
||||||
|
|
||||||
us_per_ms = PyLong_FromLong(1000);
|
|
||||||
if (us_per_ms == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
us_per_second = PyLong_FromLong(1000000);
|
|
||||||
if (us_per_second == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
us_per_minute = PyLong_FromLong(60000000);
|
|
||||||
if (us_per_minute == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
seconds_per_day = PyLong_FromLong(24 * 3600);
|
|
||||||
if (seconds_per_day == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The rest are too big for 32-bit ints, but even
|
|
||||||
* us_per_week fits in 40 bits, so doubles should be exact.
|
|
||||||
*/
|
|
||||||
us_per_hour = PyLong_FromDouble(3600000000.0);
|
|
||||||
if (us_per_hour == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
us_per_day = PyLong_FromDouble(86400000000.0);
|
|
||||||
if (us_per_day == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
us_per_week = PyLong_FromDouble(604800000000.0);
|
|
||||||
if (us_per_week == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(us_per_ms);
|
datetime_clear(module);
|
||||||
Py_XDECREF(us_per_second);
|
|
||||||
Py_XDECREF(us_per_minute);
|
|
||||||
Py_XDECREF(us_per_hour);
|
|
||||||
Py_XDECREF(us_per_day);
|
|
||||||
Py_XDECREF(us_per_week);
|
|
||||||
Py_XDECREF(seconds_per_day);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#undef DATETIME_ADD_MACRO
|
||||||
|
|
||||||
static struct PyModuleDef datetimemodule = {
|
static struct PyModuleDef datetimemodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
.m_name = "_datetime",
|
.m_name = "_datetime",
|
||||||
.m_doc = "Fast implementation of the datetime type.",
|
.m_doc = "Fast implementation of the datetime type.",
|
||||||
.m_size = -1,
|
.m_size = -1,
|
||||||
|
|
|
@ -418,20 +418,12 @@ Modules/_ctypes/_ctypes.c - _unpickle -
|
||||||
Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache -
|
Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache -
|
||||||
Modules/_cursesmodule.c - ModDict -
|
Modules/_cursesmodule.c - ModDict -
|
||||||
Modules/_datetimemodule.c datetime_strptime module -
|
Modules/_datetimemodule.c datetime_strptime module -
|
||||||
Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC -
|
|
||||||
Modules/_datetimemodule.c - PyDateTime_Epoch -
|
|
||||||
Modules/_datetimemodule.c - us_per_ms -
|
|
||||||
Modules/_datetimemodule.c - us_per_second -
|
|
||||||
Modules/_datetimemodule.c - us_per_minute -
|
|
||||||
Modules/_datetimemodule.c - us_per_hour -
|
|
||||||
Modules/_datetimemodule.c - us_per_day -
|
|
||||||
Modules/_datetimemodule.c - us_per_week -
|
|
||||||
Modules/_datetimemodule.c - seconds_per_day -
|
|
||||||
|
|
||||||
## state
|
## state
|
||||||
Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache -
|
Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache -
|
||||||
Modules/_ctypes/_ctypes.c - global_state -
|
Modules/_ctypes/_ctypes.c - global_state -
|
||||||
Modules/_ctypes/ctypes.h - global_state -
|
Modules/_ctypes/ctypes.h - global_state -
|
||||||
|
Modules/_datetimemodule.c - _datetime_global_state -
|
||||||
Modules/_tkinter.c - tcl_lock -
|
Modules/_tkinter.c - tcl_lock -
|
||||||
Modules/_tkinter.c - excInCmd -
|
Modules/_tkinter.c - excInCmd -
|
||||||
Modules/_tkinter.c - valInCmd -
|
Modules/_tkinter.c - valInCmd -
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Reference in New Issue