Skip to content

Trim unncessary code in datetime/np_datetime.c #21962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 22 additions & 160 deletions pandas/_libs/src/datetime/np_datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,7 @@ NPY_NO_EXPORT void add_seconds_to_datetimestruct(npy_datetimestruct *dts,
* Fills in the year, month, day in 'dts' based on the days
* offset from 1970.
*/
static void set_datetimestruct_days(npy_int64 days,
npy_datetimestruct *dts) {
static void set_datetimestruct_days(npy_int64 days, npy_datetimestruct *dts) {
const int *month_lengths;
int i;

Expand Down Expand Up @@ -318,7 +317,7 @@ int cmp_npy_datetimestruct(const npy_datetimestruct *a,

/*
*
* Tests for and converts a Python datetime.datetime or datetime.date
* Converts a Python datetime.datetime or datetime.date
* object into a NumPy npy_datetimestruct. Uses tzinfo (if present)
* to convert to UTC time.
*
Expand All @@ -330,68 +329,22 @@ int cmp_npy_datetimestruct(const npy_datetimestruct *a,
* Returns -1 on error, 0 on success, and 1 (with no error set)
* if obj doesn't have the needed date or datetime attributes.
*/
int convert_pydatetime_to_datetimestruct(PyObject *obj,
int convert_pydatetime_to_datetimestruct(PyDateTime_Date *obj,
npy_datetimestruct *out) {
// Assumes that obj is a valid datetime object
PyObject *tmp;
int isleap;

/* Initialize the output to all zeros */
memset(out, 0, sizeof(npy_datetimestruct));
out->month = 1;
out->day = 1;

/* Need at least year/month/day attributes */
if (!PyObject_HasAttrString(obj, "year") ||
!PyObject_HasAttrString(obj, "month") ||
!PyObject_HasAttrString(obj, "day")) {
return 1;
}

/* Get the year */
tmp = PyObject_GetAttrString(obj, "year");
if (tmp == NULL) {
return -1;
}
out->year = PyInt_AsLong(tmp);
if (out->year == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);

/* Get the month */
tmp = PyObject_GetAttrString(obj, "month");
if (tmp == NULL) {
return -1;
}
out->month = PyInt_AsLong(tmp);
if (out->month == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);

/* Get the day */
tmp = PyObject_GetAttrString(obj, "day");
if (tmp == NULL) {
return -1;
}
out->day = PyInt_AsLong(tmp);
if (out->day == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);
out->year = PyInt_AsLong(PyObject_GetAttrString(obj, "year"));
out->month = PyInt_AsLong(PyObject_GetAttrString(obj, "month"));
out->day = PyInt_AsLong(PyObject_GetAttrString(obj, "day"));

/* Validate that the month and day are valid for the year */
if (out->month < 1 || out->month > 12) {
goto invalid_date;
}
isleap = is_leapyear(out->year);
if (out->day < 1 ||
out->day > days_per_month_table[isleap][out->month - 1]) {
goto invalid_date;
}
// TODO: If we can get PyDateTime_IMPORT to work, we could use
// PyDateTime_Check here, and less verbose attribute lookups.

/* Check for time attributes (if not there, return success as a date) */
if (!PyObject_HasAttrString(obj, "hour") ||
Expand All @@ -401,61 +354,13 @@ int convert_pydatetime_to_datetimestruct(PyObject *obj,
return 0;
}

/* Get the hour */
tmp = PyObject_GetAttrString(obj, "hour");
if (tmp == NULL) {
return -1;
}
out->hour = PyInt_AsLong(tmp);
if (out->hour == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);
out->hour = PyInt_AsLong(PyObject_GetAttrString(obj, "hour"));
out->min = PyInt_AsLong(PyObject_GetAttrString(obj, "minute"));
out->sec = PyInt_AsLong(PyObject_GetAttrString(obj, "second"));
out->us = PyInt_AsLong(PyObject_GetAttrString(obj, "microsecond"));

/* Get the minute */
tmp = PyObject_GetAttrString(obj, "minute");
if (tmp == NULL) {
return -1;
}
out->min = PyInt_AsLong(tmp);
if (out->min == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);

/* Get the second */
tmp = PyObject_GetAttrString(obj, "second");
if (tmp == NULL) {
return -1;
}
out->sec = PyInt_AsLong(tmp);
if (out->sec == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);

/* Get the microsecond */
tmp = PyObject_GetAttrString(obj, "microsecond");
if (tmp == NULL) {
return -1;
}
out->us = PyInt_AsLong(tmp);
if (out->us == -1 && PyErr_Occurred()) {
Py_DECREF(tmp);
return -1;
}
Py_DECREF(tmp);

if (out->hour < 0 || out->hour >= 24 || out->min < 0 || out->min >= 60 ||
out->sec < 0 || out->sec >= 60 || out->us < 0 || out->us >= 1000000) {
goto invalid_time;
}

/* Apply the time zone offset if it exists */
if (PyObject_HasAttrString(obj, "tzinfo")) {
/* Apply the time zone offset if datetime obj is tz-aware */
if (PyObject_HasAttrString((PyObject*)obj, "tzinfo")) {
tmp = PyObject_GetAttrString(obj, "tzinfo");
if (tmp == NULL) {
return -1;
Expand Down Expand Up @@ -497,50 +402,15 @@ int convert_pydatetime_to_datetimestruct(PyObject *obj,
}

return 0;

invalid_date:
PyErr_Format(PyExc_ValueError,
"Invalid date (%d,%d,%d) when converting to NumPy datetime",
(int)out->year, (int)out->month, (int)out->day);
return -1;

invalid_time:
PyErr_Format(PyExc_ValueError,
"Invalid time (%d,%d,%d,%d) when converting "
"to NumPy datetime",
(int)out->hour, (int)out->min, (int)out->sec, (int)out->us);
return -1;
}

npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT fr,
npy_datetimestruct *d) {
npy_datetime result = NPY_DATETIME_NAT;

convert_datetimestruct_to_datetime(fr, d, &result);
return result;
}

void pandas_datetime_to_datetimestruct(npy_datetime val, NPY_DATETIMEUNIT fr,
npy_datetimestruct *result) {
convert_datetime_to_datetimestruct(fr, val, result);
}

void pandas_timedelta_to_timedeltastruct(npy_timedelta val,
NPY_DATETIMEUNIT fr,
pandas_timedeltastruct *result) {
convert_timedelta_to_timedeltastruct(fr, val, result);
}


/*
* Converts a datetime from a datetimestruct to a datetime based
* on a metadata unit. The date is assumed to be valid.
*
* Returns 0 on success, -1 on failure.
*/
int convert_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
const npy_datetimestruct *dts,
npy_datetime *out) {
npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
const npy_datetimestruct *dts) {
npy_datetime ret;

if (base == NPY_FR_Y) {
Expand Down Expand Up @@ -632,17 +502,14 @@ int convert_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
return -1;
}
}

*out = ret;

return 0;
return ret;
}

/*
* Converts a datetime based on the given metadata into a datetimestruct
*/
int convert_datetime_to_datetimestruct(NPY_DATETIMEUNIT base,
npy_datetime dt,
void pandas_datetime_to_datetimestruct(npy_datetime dt,
NPY_DATETIMEUNIT base,
npy_datetimestruct *out) {
npy_int64 perday;

Expand Down Expand Up @@ -850,10 +717,8 @@ int convert_datetime_to_datetimestruct(NPY_DATETIMEUNIT base,
PyErr_SetString(PyExc_RuntimeError,
"NumPy datetime metadata is corrupted with invalid "
"base unit");
return -1;
}

return 0;
}

/*
Expand All @@ -862,8 +727,8 @@ int convert_datetime_to_datetimestruct(NPY_DATETIMEUNIT base,
*
* Returns 0 on success, -1 on failure.
*/
int convert_timedelta_to_timedeltastruct(NPY_DATETIMEUNIT base,
npy_timedelta td,
void pandas_timedelta_to_timedeltastruct(npy_timedelta td,
NPY_DATETIMEUNIT base,
pandas_timedeltastruct *out) {
npy_int64 frac;
npy_int64 sfrac;
Expand Down Expand Up @@ -953,8 +818,5 @@ int convert_timedelta_to_timedeltastruct(NPY_DATETIMEUNIT base,
PyErr_SetString(PyExc_RuntimeError,
"NumPy timedelta metadata is corrupted with "
"invalid base unit");
return -1;
}

return 0;
}
12 changes: 4 additions & 8 deletions pandas/_libs/src/datetime/np_datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt
#define PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_H_

#include <numpy/ndarraytypes.h>
#include <datetime.h>

typedef struct {
npy_int64 days;
Expand All @@ -30,11 +31,11 @@ extern const npy_datetimestruct _NS_MAX_DTS;
// stuff pandas needs
// ----------------------------------------------------------------------------

int convert_pydatetime_to_datetimestruct(PyObject *obj,
int convert_pydatetime_to_datetimestruct(PyDateTime_Date *obj,
npy_datetimestruct *out);

npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT fr,
npy_datetimestruct *d);
npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
const npy_datetimestruct *dts);

void pandas_datetime_to_datetimestruct(npy_datetime val, NPY_DATETIMEUNIT fr,
npy_datetimestruct *result);
Expand Down Expand Up @@ -74,9 +75,4 @@ void
add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes);


int
convert_datetime_to_datetimestruct(NPY_DATETIMEUNIT base,
npy_datetime dt,
npy_datetimestruct *out);

#endif // PANDAS__LIBS_SRC_DATETIME_NP_DATETIME_H_
7 changes: 4 additions & 3 deletions pandas/_libs/src/ujson/python/objToJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,16 +481,17 @@ static void *NpyDateTimeScalarToJSON(JSOBJ _obj, JSONTypeContext *tc,
npy_datetimestruct dts;
PyDatetimeScalarObject *obj = (PyDatetimeScalarObject *)_obj;
PRINTMARK();
// TODO: Does not appear to be reached in tests.

pandas_datetime_to_datetimestruct(
obj->obval, (NPY_DATETIMEUNIT)obj->obmeta.base, &dts);
pandas_datetime_to_datetimestruct(obj->obval,
(NPY_DATETIMEUNIT)obj->obmeta.base, &dts);
return PandasDateTimeStructToJSON(&dts, tc, outValue, _outLen);
}

static void *PyDateTimeToJSON(JSOBJ _obj, JSONTypeContext *tc, void *outValue,
size_t *_outLen) {
npy_datetimestruct dts;
PyObject *obj = (PyObject *)_obj;
PyDateTime_Date *obj = (PyDateTime_Date *)_obj;

PRINTMARK();

Expand Down
6 changes: 4 additions & 2 deletions pandas/_libs/tslibs/np_datetime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ cdef inline void td64_to_tdstruct(int64_t td64,

cdef inline int64_t pydatetime_to_dt64(datetime val,
npy_datetimestruct *dts):
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an explicit check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called by some very perf-sensitive code, all uses of which already handle this carefully. I think its sufficiently internal to be OK without.

Note we are assuming that the datetime object is timezone-naive.
"""
dts.year = PyDateTime_GET_YEAR(val)
dts.month = PyDateTime_GET_MONTH(val)
dts.day = PyDateTime_GET_DAY(val)
Expand All @@ -158,8 +161,7 @@ cdef inline int64_t pydatetime_to_dt64(datetime val,
return dtstruct_to_dt64(dts)


cdef inline int64_t pydate_to_dt64(date val,
npy_datetimestruct *dts):
cdef inline int64_t pydate_to_dt64(date val, npy_datetimestruct *dts):
dts.year = PyDateTime_GET_YEAR(val)
dts.month = PyDateTime_GET_MONTH(val)
dts.day = PyDateTime_GET_DAY(val)
Expand Down