-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Datetime failures with MinGW (Trac #2108) #568
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
Comments
@rgommers wrote on 2012-04-16 It's not yet clear to me how much of datetime would be unusable on Windows if we would do a release right now. Can anyone comment on that? If it's a major part, then I think this is a blocker. If it's a minor issue, then we may decide to ignore it (there's an experimental label for a reason). |
@rgommers wrote on 2012-07-15 Latest output from our XP buildbot:
|
@rgommers wrote on 2012-07-15 Related tickets / PRs: |
@rgommers wrote on 2012-07-15 Last discussion on this: http://thread.gmane.org/gmane.comp.python.numeric.general/50907/focus=50918 |
As of today (69c06da), here is how to reproduce it:
|
The problem seems to be in
where the |
Applying the following patch: diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multi
index 32009bb..e1c6130 100644
--- a/numpy/core/src/multiarray/datetime_strings.c
+++ b/numpy/core/src/multiarray/datetime_strings.c
@@ -47,14 +47,12 @@ get_localtime(NPY_TIME_T *ts, struct tm *tms)
func_name = "localtime_s";
goto fail;
}
- #elif defined(NPY_MINGW_USE_CUSTOM_MSVCR)
- if (_localtime64_s(tms, ts) != 0) {
- func_name = "_localtime64_s";
- goto fail;
- }
#else
struct tm *tms_tmp;
+ printf("localtime1: %d\n", ts);
+ printf("localtime2: %d\n", *ts);
tms_tmp = localtime(ts);
+ printf("localtime3: %d\n", tms_tmp == NULL);
if (tms_tmp == NULL) {
func_name = "localtime";
goto fail; I have found, that sometimes, the I also noticed, that it doesn't matter if This all seems to suggest, that |
Here is a minimal example to reproduce the problem:
With a little experimenting, it turns out that dates up to 2038 work, but not over 2038. Citing the reference:
this suggests that for whatever reason, the wine that we use in Ubuntu is 32bit inside and thus the localtime does not allow dates over 2038. This is obvious. What is not obvious is why do we test for dates over 2038 in numpy? Or is this a bug in how datetime64 is implemented? |
The real problem is exposed by this C code: #include <stdio.h>
#include <time.h>
int main ()
{
time_t rawtime;
struct tm *info;
char buffer[80];
//time( &rawtime );
rawtime = -2025246196;
printf("localtime2: %d\n", rawtime);
info = localtime(&rawtime);
if (info == NULL) {
printf("sorry, it's null...\n");
} else {
printf("Current local time and date: %s", asctime(info));
}
return 0;
} Which in the 32 bit Ubuntu (in Vagrant) prints
while in Wine under mingw in the same Ubuntu prints:
But if you use something positive (just uncomment the
and Wine gives
So for positive values, |
I think this problem was introduced by b1e5fa0 in the |
On Wed, Dec 26, 2012 at 8:05 PM, Ondřej Čertík [email protected]:
Chuck |
I am still digging into this, I really need to get at the bottom of this datetime + time_t issue first, to really understand what is going on here. I've already found at least part of the real problem. In the patch 1ef79b7 from Feb 19, 2012 Mark (correctly) introduced a fix not to call localtime() for dates < 1970, because on Windows this does not work, as I independently found out above. However, as I found out above, the localtime is still being called with "negative" values on 32 bits, that is, with values over 2038. So something does not work here. I strongly suspect the hack introduced previously in b1e5fa0 from Sep 30, 2011 (just search for the word "HACK" in that patch), either it's doing something wrong, or it works but doesn't come into effect, so the years roll over on 32 bits, and then localtime() fails. I am still digging into this. |
On Wed, Dec 26, 2012 at 8:45 PM, Ondřej Čertík [email protected]:
Yes, it's a mess. Linus has made some, well, Linus like remarks on the Chuck |
Yep, I read pretty much everything that was written on this issue, in numpy, Linus and mingw. I will keep posting random stuff here as I learn things. Then I'll look at all this tomorrow with fresh eyes, I feel I am close to nail this down. I found out, that in Wine,
At the same time I printed the
and I got:
when I executed
I am still confused whether the Also, I need to test how numpy behaves in 32 bit Ubuntu directly (i.e. not in Wine). |
I found it!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Here is a fix: diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multi
index 32009bb..794f13b 100644
--- a/numpy/core/src/multiarray/datetime_strings.c
+++ b/numpy/core/src/multiarray/datetime_strings.c
@@ -48,10 +48,16 @@ get_localtime(NPY_TIME_T *ts, struct tm *tms)
goto fail;
}
#elif defined(NPY_MINGW_USE_CUSTOM_MSVCR)
+ printf("sizeof(NPY_TIME_T) = %d\n", sizeof(NPY_TIME_T));
+ printf("ts = %d\n", *ts);
+ printf("ts = %ld\n", *ts);
+ printf("ts = %lld\n", *ts);
if (_localtime64_s(tms, ts) != 0) {
+ printf("fail\n");
func_name = "_localtime64_s";
goto fail;
}
+ printf("ok\n");
#else
struct tm *tms_tmp;
tms_tmp = localtime(ts);
@@ -189,7 +195,7 @@ convert_datetimestruct_utc_to_local(npy_datetimestruct *out_
* we drop the seconds value from the npy_datetimestruct, everything
* is ok for this operation.
*/
- rawtime = (time_t)get_datetimestruct_days(out_dts_local) * 24 * 60 * 60;
+ rawtime = (NPY_TIME_T)get_datetimestruct_days(out_dts_local) * 24 * 60 * 60
rawtime += dts_utc->hour * 60 * 60;
rawtime += dts_utc->min * 60;
You can ignore the print statements, they are there for clarification. Without the
and with it:
That's it. This was typing a 64 bit integer into a 32 bit one, thus rolling over, becoming a negative number, and then when you pass a negative number into a 64 bit localtime(), it fails on Windows... I would bet that on 32 bit linux, it returns something like the year 1905, so we have a bug there as well, I am surprised that nobody noticed this before... All clear now. The rest should follow quite straightforwardly now. But why do we need the to use _localtime64_s in Mingw in the first place? Why not to use localtime()? It would simplify things, and if we remove the NPY_TIME_T, then actually things will start working. So the real bug was actually introduced in this patch: 5d0e0aa |
Ok, actually 1/2 of the bug was introduced in the patch b1e5fa0, because it introduced a macro |
I just posted a PR #2856 that fixes this issue. Now I get:
Yes!!! I started working on this at 6:30am and finished 8:40pm, so good 14 hours... This was definitely a bug. If we are lucky, it actually fixes everything. But this datetime/time_t issue is a horrible mess... Anyway, I am going to bed now. Feel free to merge the PR if tests pass. |
Previously, two (critical) parts of the code used `time_t` instead of `NPY_TIME_T`. Due to the fact, that most of the time `NPY_TIME_T` was equal to `time_t`, this bug didn't show up. But in mingw, `NPY_TIME_T` is actually equal to `__time64_t` and then this causes 64 bit integers to be cast into 32 bit integers (thus becoming negative), which causes localtime() to fail in mingw. Fixes numpygh-568.
As Chuck suggested, I am reopening this issue, until we carefully verify that things are fixed. Also I want to better document what is going on. |
After understanding the issues with datetime (see numpygh-568), I have documented my understanding as comments in the code, so that the next time there are problems with datetime on some platform, one can quickly figure out what is going on from the code + comments.
I've documented my current understanding in #2858. After that is in, I think we can close this issue. |
Tested it on my MinGW install, works like a charm with both Python 2.6 and 3.2. Thanks Ondrej! Will now have a look if I understand your changes and documentation. |
Thanks Ralf! |
After understanding the issues with datetime (see numpygh-568), I have documented my understanding as comments in the code, so that the next time there are problems with datetime on some platform, one can quickly figure out what is going on from the code + comments.
Original ticket http://projects.scipy.org/numpy/ticket/2108 on 2012-04-16 by @rgommers, assigned to unknown.
See #214
These failures are hard to fix for MinGW 3.4.5. Until we can do everything with MinGW 4.x (including distributing binaries) we do have a problem.
The text was updated successfully, but these errors were encountered: