Skip to content

Commit 4b12c10

Browse files
author
Jonathan Eliashiv
committed
include get_localtime wrapper
1 parent 52665c6 commit 4b12c10

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

pandas/_libs/tslibs/src/datetime/np_datetime_strings.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,77 @@ This file implements string parsing and creation for NumPy datetime.
5151
typedef time_t NPY_TIME_T;
5252
#endif
5353

54+
/*
55+
* Wraps `localtime` functionality for multiple platforms. This
56+
* converts a time value to a time structure in the local timezone.
57+
* If size(NPY_TIME_T) == 4, then years must be between 1970 and 2038. If
58+
* size(NPY_TIME_T) == 8, then years must be later than 1970. If the years are
59+
* not in this range, then get_localtime() will fail on some platforms.
60+
*
61+
* Returns 0 on success, -1 on failure.
62+
*
63+
* Notes:
64+
* 1) If NPY_TIME_T is 32 bit (i.e. sizeof(NPY_TIME_T) == 4), then the
65+
* maximum year it can represent is 2038 (see [1] for more details). Trying
66+
* to use a higher date like 2041 in the 32 bit "ts" variable below will
67+
* typically result in "ts" being a negative number (corresponding roughly
68+
* to a year ~ 1905). If NPY_TIME_T is 64 bit, then there is no such
69+
* problem in practice.
70+
* 2) If the "ts" argument to localtime() is negative, it represents
71+
* years < 1970 both for 32 and 64 bits (for 32 bits the earliest year it can
72+
* represent is 1901, while 64 bits can represent much earlier years).
73+
* 3) On Linux, localtime() works for negative "ts". On Windows and in Wine,
74+
* localtime() as well as the localtime_s() and _localtime64_s() functions
75+
* will fail for any negative "ts" and return a nonzero exit number
76+
* (localtime_s, _localtime64_s) or NULL (localtime). This behavior is the
77+
* same for both 32 and 64 bits.
78+
*
79+
* From this it follows that get_localtime() is only guaranteed to work
80+
* correctly on all platforms for years between 1970 and 2038 for 32bit
81+
* NPY_TIME_T and years higher than 1970 for 64bit NPY_TIME_T. For
82+
* multiplatform code, get_localtime() should never be used outside of this
83+
* range.
84+
*
85+
* [1] https://en.wikipedia.org/wiki/Year_2038_problem
86+
*/
87+
static int
88+
get_localtime(NPY_TIME_T *ts, struct tm *tms)
89+
{
90+
char *func_name = "<unknown>";
91+
#if defined(_WIN32)
92+
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
93+
if (localtime_s(tms, ts) != 0) {
94+
func_name = "localtime_s";
95+
goto fail;
96+
}
97+
#elif defined(NPY_MINGW_USE_CUSTOM_MSVCR)
98+
if (_localtime64_s(tms, ts) != 0) {
99+
func_name = "_localtime64_s";
100+
goto fail;
101+
}
102+
#else
103+
struct tm *tms_tmp;
104+
tms_tmp = localtime(ts);
105+
if (tms_tmp == NULL) {
106+
func_name = "localtime";
107+
goto fail;
108+
}
109+
memcpy(tms, tms_tmp, sizeof(struct tm));
110+
#endif
111+
#else
112+
if (localtime_r(ts, tms) == NULL) {
113+
func_name = "localtime_r";
114+
goto fail;
115+
}
116+
#endif
117+
118+
return 0;
119+
120+
fail:
121+
PyErr_Format(PyExc_OSError, "Failed to use '%s' to convert "
122+
"to a local time", func_name);
123+
return -1;
124+
}
54125

55126
/*
56127
* Parses (almost) standard ISO 8601 date strings. The differences are:

0 commit comments

Comments
 (0)