Skip to content

Commit 7c4ae97

Browse files
committed
BUG: port skts_strftime to Cython, hopefully fix mingw32 issues #1360
1 parent a8c4d56 commit 7c4ae97

File tree

8 files changed

+183
-248
lines changed

8 files changed

+183
-248
lines changed

pandas/src/datetime.pxd

-57
Original file line numberDiff line numberDiff line change
@@ -112,60 +112,3 @@ cdef extern from "datetime/np_datetime_strings.h":
112112
int get_datetime_iso_8601_strlen(int local, PANDAS_DATETIMEUNIT base)
113113

114114
# int parse_python_string(object obj, pandas_datetimestruct *out) except -1
115-
116-
cdef extern from "period.h":
117-
ctypedef struct date_info:
118-
int64_t absdate
119-
double abstime
120-
double second
121-
int minute
122-
int hour
123-
int day
124-
int month
125-
int quarter
126-
int year
127-
int day_of_week
128-
int day_of_year
129-
int calendar
130-
131-
ctypedef struct asfreq_info:
132-
int from_week_end
133-
int to_week_end
134-
135-
int from_a_year_end
136-
int to_a_year_end
137-
138-
int from_q_year_end
139-
int to_q_year_end
140-
141-
ctypedef int64_t (*freq_conv_func)(int64_t, char, asfreq_info*)
142-
143-
int64_t asfreq(int64_t dtordinal, int freq1, int freq2, char relation) except INT32_MIN
144-
freq_conv_func get_asfreq_func(int fromFreq, int toFreq)
145-
void get_asfreq_info(int fromFreq, int toFreq, asfreq_info *af_info)
146-
147-
int64_t get_period_ordinal(int year, int month, int day,
148-
int hour, int minute, int second,
149-
int freq) except INT32_MIN
150-
151-
int64_t get_python_ordinal(int64_t period_ordinal, int freq) except INT32_MIN
152-
153-
char *skts_strftime(int64_t value, int freq, PyObject *args)
154-
char *period_to_string(int64_t value, int freq)
155-
char *period_to_string2(int64_t value, int freq, char *fmt)
156-
157-
int get_date_info(int64_t ordinal, int freq, date_info *dinfo) except INT32_MIN
158-
double getAbsTime(int, int64_t, int64_t)
159-
160-
int pyear(int64_t ordinal, int freq) except INT32_MIN
161-
int pqyear(int64_t ordinal, int freq) except INT32_MIN
162-
int pquarter(int64_t ordinal, int freq) except INT32_MIN
163-
int pmonth(int64_t ordinal, int freq) except INT32_MIN
164-
int pday(int64_t ordinal, int freq) except INT32_MIN
165-
int pweekday(int64_t ordinal, int freq) except INT32_MIN
166-
int pday_of_week(int64_t ordinal, int freq) except INT32_MIN
167-
int pday_of_year(int64_t ordinal, int freq) except INT32_MIN
168-
int pweek(int64_t ordinal, int freq) except INT32_MIN
169-
int phour(int64_t ordinal, int freq) except INT32_MIN
170-
int pminute(int64_t ordinal, int freq) except INT32_MIN
171-
int psecond(int64_t ordinal, int freq) except INT32_MIN

pandas/src/numpy_helper.h

+9
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ get_c_string(PyObject* obj) {
116116
#endif
117117
}
118118

119+
PANDAS_INLINE PyObject*
120+
char_to_string(char* data) {
121+
#if PY_VERSION_HEX >= 0x03000000
122+
return PyUnicode_FromString(data);
123+
#else
124+
return PyString_FromString(data);
125+
#endif
126+
}
127+
119128
// PANDAS_INLINE int
120129
// is_string(PyObject* obj) {
121130
// #if PY_VERSION_HEX >= 0x03000000

pandas/src/period.c

+31-167
Original file line numberDiff line numberDiff line change
@@ -1162,190 +1162,54 @@ char *str_replace(const char *s, const char *old, const char *new) {
11621162
// function to generate a nice string representation of the period
11631163
// object, originally from DateObject_strftime
11641164

1165-
char *skts_strftime(npy_int64 ordinal, int freq, PyObject *args)
1166-
{
1167-
char *orig_fmt_str, *fmt_str;
1168-
char *result;
1165+
char* c_strftime(struct date_info *tmp, char *fmt) {
1166+
struct tm c_date;
1167+
char* result;
1168+
struct date_info dinfo = *tmp;
1169+
int result_len = strlen(fmt) + 50;
1170+
1171+
c_date.tm_sec = (int)dinfo.second;
1172+
c_date.tm_min = dinfo.minute;
1173+
c_date.tm_hour = dinfo.hour;
1174+
c_date.tm_mday = dinfo.day;
1175+
c_date.tm_mon = dinfo.month - 1;
1176+
c_date.tm_year = dinfo.year - 1900;
1177+
c_date.tm_wday = (dinfo.day_of_week + 1) % 7;
1178+
c_date.tm_yday = dinfo.day_of_year - 1;
1179+
c_date.tm_isdst = -1;
11691180

1170-
int num_extra_fmts = 3;
1181+
result = malloc(result_len * sizeof(char));
11711182

1172-
char extra_fmts[3][2][10] = {{"%q", "^`AB`^"},
1173-
{"%f", "^`CD`^"},
1174-
{"%F", "^`EF`^"}};
1183+
strftime(result, result_len, fmt, &c_date);
11751184

1176-
int extra_fmts_found[3] = {0,0,0};
1177-
int extra_fmts_found_one = 0;
1178-
struct tm c_date;
1179-
struct date_info tempDate;
1180-
npy_int64 absdate, daily_ord;
1181-
double abstime;
1182-
int i, result_len;
1183-
PyObject *py_result;
1185+
return result;
1186+
}
11841187

1185-
npy_int64 (*toDaily)(npy_int64, char, asfreq_info*) = NULL;
1188+
int get_yq(npy_int64 ordinal, int freq, int *quarter, int *year) {
11861189
asfreq_info af_info;
1187-
1188-
if (!PyArg_ParseTuple(args, "s:strftime(fmt)", &orig_fmt_str))
1189-
return NULL;
1190+
int qtr_freq;
1191+
npy_int64 daily_ord;
1192+
npy_int64 (*toDaily)(npy_int64, char, asfreq_info*) = NULL;
11901193

11911194
toDaily = get_asfreq_func(freq, FR_DAY);
11921195
get_asfreq_info(freq, FR_DAY, &af_info);
11931196

11941197
daily_ord = toDaily(ordinal, 'E', &af_info);
1195-
abstime = get_abs_time(freq, daily_ord, ordinal);
1196-
1197-
if (abstime < 0) {
1198-
abstime += 86400;
1199-
daily_ord -= 1;
1200-
}
1201-
1202-
/* printf("daily_ord: %d, abstime: %f \n", (int) daily_ord, abstime); */
1203-
1204-
if(dInfoCalc_SetFromAbsDateTime(&tempDate, daily_ord + ORD_OFFSET, abstime,
1205-
GREGORIAN_CALENDAR)) return NULL;
1206-
1207-
// populate standard C date struct with info from our date_info struct
1208-
c_date.tm_sec = (int)tempDate.second;
1209-
c_date.tm_min = tempDate.minute;
1210-
c_date.tm_hour = tempDate.hour;
1211-
c_date.tm_mday = tempDate.day;
1212-
c_date.tm_mon = tempDate.month - 1;
1213-
c_date.tm_year = tempDate.year - 1900;
1214-
c_date.tm_wday = (tempDate.day_of_week + 1) % 7;
1215-
c_date.tm_yday = tempDate.day_of_year - 1;
1216-
c_date.tm_isdst = -1;
1217-
1218-
result_len = strlen(orig_fmt_str) + 50;
1219-
if ((result = PyArray_malloc(result_len * sizeof(char))) == NULL) {
1220-
return (char*)PyErr_NoMemory();
1221-
}
1222-
1223-
fmt_str = orig_fmt_str;
1224-
1225-
// replace any special format characters with their place holder
1226-
for(i=0; i < num_extra_fmts; i++) {
1227-
char *special_loc;
1228-
if ((special_loc = strstr(fmt_str,extra_fmts[i][0])) != NULL) {
1229-
char *tmp_str = fmt_str;
1230-
fmt_str = str_replace(fmt_str, extra_fmts[i][0],
1231-
extra_fmts[i][1]);
1232-
/* only free the previous loop value if this is not the first
1233-
special format string found */
1234-
if (extra_fmts_found_one) { free(tmp_str); }
12351198

1236-
if (fmt_str == NULL) {return NULL;}
1199+
if (get_freq_group(freq) == FR_QTR) {
1200+
qtr_freq = freq;
1201+
} else { qtr_freq = FR_QTR; }
1202+
get_asfreq_info(FR_DAY, qtr_freq, &af_info);
12371203

1238-
extra_fmts_found[i] = 1;
1239-
extra_fmts_found_one = 1;
1240-
}
1241-
}
1204+
if(DtoQ_yq(daily_ord, &af_info, year, quarter) == INT_ERR_CODE)
1205+
return -1;
12421206

1243-
strftime(result, result_len, fmt_str, &c_date);
1244-
if (extra_fmts_found_one) { free(fmt_str); }
1245-
1246-
// replace any place holders with the appropriate value
1247-
for(i=0; i < num_extra_fmts; i++) {
1248-
if (extra_fmts_found[i]) {
1249-
char *tmp_str = result;
1250-
char *extra_str;
1251-
1252-
if (strcmp(extra_fmts[i][0], "%q") == 0 ||
1253-
strcmp(extra_fmts[i][0], "%f") == 0 ||
1254-
strcmp(extra_fmts[i][0], "%F") == 0) {
1255-
1256-
asfreq_info af_info;
1257-
int qtr_freq, year, quarter, year_len;
1258-
1259-
if (get_freq_group(freq) == FR_QTR) {
1260-
qtr_freq = freq;
1261-
} else { qtr_freq = FR_QTR; }
1262-
get_asfreq_info(FR_DAY, qtr_freq, &af_info);
1263-
1264-
if(DtoQ_yq(daily_ord, &af_info, &year, &quarter) == INT_ERR_CODE)
1265-
{ return NULL; }
1266-
1267-
if(strcmp(extra_fmts[i][0], "%q") == 0) {
1268-
if ((extra_str = PyArray_malloc(2 * sizeof(char))) == NULL) {
1269-
free(tmp_str);
1270-
return (char *)PyErr_NoMemory();
1271-
}
1272-
sprintf(extra_str, "%i", quarter);
1273-
} else {
1274-
if ((qtr_freq % 1000) > 12) { year -= 1; }
1275-
1276-
if (strcmp(extra_fmts[i][0], "%f") == 0) {
1277-
year_len = 2;
1278-
year = year % 100;
1279-
} else { year_len = 4; }
1280-
1281-
if ((extra_str = PyArray_malloc((year_len+1) * sizeof(char))) == NULL) {
1282-
free(tmp_str);
1283-
return (char *)PyErr_NoMemory();
1284-
}
1285-
1286-
if (year_len == 2 && year < 10) {
1287-
sprintf(extra_str, "0%i", year);
1288-
} else { sprintf(extra_str, "%i", year); }
1289-
}
1290-
1291-
} else {
1292-
PyErr_SetString(PyExc_RuntimeError,"Unrecognized format string");
1293-
return NULL;
1294-
}
1207+
return 0;
1208+
}
12951209

1296-
result = str_replace(result, extra_fmts[i][1], extra_str);
1297-
free(tmp_str);
1298-
free(extra_str);
1299-
if (result == NULL) { return NULL; }
1300-
}
1301-
}
13021210

1303-
return result;
1304-
}
13051211

1306-
char *period_to_string(npy_int64 value, int freq)
1307-
{
1308-
int freq_group = get_freq_group(freq);
1309-
PyObject *string_arg;
1310-
char *retval;
1311-
1312-
string_arg = NULL;
1313-
if (freq_group == FR_UND) {
1314-
int digits = log10(value) + 1;
1315-
if ((retval = PyArray_malloc(digits * sizeof(char))) == NULL) {
1316-
return (char *)PyErr_NoMemory();
1317-
}
1318-
sprintf(retval, "%ld", (long int) value);
1319-
return retval;
1320-
}
1321-
else if (freq_group == FR_ANN) { string_arg = Py_BuildValue("(s)", "%Y"); }
1322-
else if (freq_group == FR_QTR) { string_arg = Py_BuildValue("(s)", "%FQ%q"); }
1323-
else if (freq_group == FR_MTH) { string_arg = Py_BuildValue("(s)", "%b-%Y"); }
1324-
else if (freq_group == FR_DAY ||
1325-
freq_group == FR_BUS ||
1326-
freq_group == FR_WK) { string_arg = Py_BuildValue("(s)", "%d-%b-%Y"); }
1327-
else if (freq_group == FR_HR) { string_arg = Py_BuildValue("(s)", "%d-%b-%Y %H:00"); }
1328-
else if (freq_group == FR_MIN) { string_arg = Py_BuildValue("(s)", "%d-%b-%Y %H:%M"); }
1329-
else if (freq_group == FR_SEC) { string_arg = Py_BuildValue("(s)", "%d-%b-%Y %H:%M:%S"); }
1330-
1331-
if (string_arg == NULL) { return (char *)NULL; }
1332-
1333-
retval = skts_strftime(value, freq, string_arg);
1334-
Py_DECREF(string_arg);
1335-
1336-
return retval;
1337-
}
13381212

1339-
char *period_to_string2(npy_int64 value, int freq, char *fmt)
1340-
{
1341-
PyObject *string_arg;
1342-
char *retval;
1343-
string_arg = Py_BuildValue("(s)", fmt);
1344-
if (string_arg == NULL) { return (char *)NULL; }
1345-
retval = skts_strftime(value, freq, string_arg);
1346-
Py_DECREF(string_arg);
1347-
return retval;
1348-
}
13491213

13501214
static int _quarter_year(npy_int64 ordinal, int freq, int *year, int *quarter) {
13511215
asfreq_info af_info;

pandas/src/period.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,6 @@ npy_int64 get_period_ordinal(int year, int month, int day,
135135

136136
npy_int64 get_python_ordinal(npy_int64 period_ordinal, int freq);
137137

138-
char *skts_strftime(npy_int64 value, int freq, PyObject *args);
139-
char *period_to_string(npy_int64 value, int freq);
140-
char *period_to_string2(npy_int64 value, int freq, char *fmt);
141-
142138
int get_date_info(npy_int64 ordinal, int freq, struct date_info *dinfo);
143139
freq_conv_func get_asfreq_func(int fromFreq, int toFreq);
144140
void get_asfreq_info(int fromFreq, int toFreq, asfreq_info *af_info);
@@ -155,6 +151,9 @@ int pweek(npy_int64 ordinal, int freq);
155151
int phour(npy_int64 ordinal, int freq);
156152
int pminute(npy_int64 ordinal, int freq);
157153
int psecond(npy_int64 ordinal, int freq);
154+
158155
double getAbsTime(int freq, npy_int64 dailyDate, npy_int64 originalDate);
156+
char *c_strftime(struct date_info *dinfo, char *fmt);
157+
int get_yq(int64_t ordinal, int freq, int *quarter, int *year);
159158

160159
#endif

0 commit comments

Comments
 (0)