-
Notifications
You must be signed in to change notification settings - Fork 33
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
Inconsistency in strftime method #23
Comments
I'm assuming the error you are pointing out is: Or basically setting a timezone even though using a gmt time still causes the wrong month? |
Yes, exactly:
Well, not just setting any timezone. It's only the |
If I squint my eyes the same as you I would actually expect to see different dates for these two
Compare the above with the
So to my mind the only correct call from your list of "right" examples is the So I think the bug actually comes from Perl's core time functions not dealing with the TAI ("right") timezones properly. |
Right, that's exactly what I was thinking. But I think something must be wrong somewhere if
Maybe the bug isn't with Time::Piece at all. Maybe it's with Except ... The POSIX module has to follow the POSIX standard, even if the standard is wrong. And, from my (limited) reading on the topic, POSIX is wrong when it comes to leap seconds. And, anyway, I'm pretty sure that So if we do definitely decide the bug is in |
At least one of the assumptions in my first comment is wrong. According to the documentation
So now that I think I know what I know better we could test everything a bit more clearly. I have adjusted the epoch value below for my time zone in order to cross the day boundary.
The above looks like this here:
So I went back and looked at the documentation for So I don't see a bug as such. I see some confusing similarly-named functions that expect different inputs. |
What catches my eye is:
Time::Piece::strftime and POSIX::strftime both call the glibc/libc strftime: http://linux.die.net/man/3/strftime and so should always be the same. The problem is that native strftime expects the tm struct which is different on every platform. For Time::Piece, I changed the call to XS to pass the epoch value which in turn is passed to the native libc gmtime or localtime which guarantees to return the correct tm struct for the platform which can be passed straight into libc strftime. I do not think POSIX::strftime has the luxury of calling the native gmtime (internal perl gmtime returns its own version of the tm struct) and it therefore tries to guess the best values for the native tm struct before passing off to libc strftime. Hard to say which one would be more "right". For the most part, nearly all function calls made by Time::Piece::strftime are native and I would assume that if there are any issues it is platform related. But this also means that the individual Time::Piece elements ($tp->mon, $tp->min, etc) may not line up exactly with native strftime. I'll try and figure out why Time::Piece::strftime and POSIX::strftime are not lining up in this test case as a starting point. |
Here is perhaps a simpler test case to use as a starting point. It does
On my Debian host this outputs the following:
The question is under the "right/UTC" timezone which value is correct? As I understand perl's gmtime it is always UNIX time (i.e. no leap Mark Lawrence |
Here is another question: is it even valid to be using "right/" timezones on a machine whose hardware clock is not set to TAI? |
Oh, I have no idea about that. Basically all I was trying to do when I found it was to run a test in every possible timezone to verify that my code would work no matter where (or when, I suppose) it was being run. So I was just rifling through all my timezone files, and roughly half of those are under What I find most interesting in your example up above is that, when you use But I'm still confused about where the bug is. I'm still pretty sure there is one, because things should agree (as @smith153 says up above). They don't, and that seems problematic. But one of them seems to be saying, "the selected timezone has leap seconds, so we have to honor that, therefore March" and the other one seems to be saying "ah, but UTC is defined as no leap seconds, so therefore April." But which one is right? No clue. |
Any further thoughts on this? I really think this:
is the crux of it. |
This will be mostly a brain dump but perhaps I can better articulate it at another time... The issue is we don't know what is right from the following:
The next issue is that Time::Piece is somewhat deceiving. You'd think that as an object, when you call methods on it, those methods just return data based on it's internal state. That would be nice, but is not always the case... At it's core, TP contains an array of a simplified version of the libc tm struct which consists of the year, dom, month, etc (aka "the broken down time"). In some cases, calling methods on TP simply return this data (like Now onto where the data from Calling gmtime (with TP loaded) fetches a broken down time via But core gmtime returns a broken down time struct and not an epoch... so So setting And what about So what does the native libc So TP is built by a call to a home grown But what about the case that using Hence why setting So ultimately I think strftime is right. In my own code, I mostly just use TP to call strftime since it mostly just uses native libc calls (that I trust more). And also to allude to the fact that leap seconds do affect UTC is the following using the normal
So the question is where to from here? And to that, I'm not really sure. Will require more thought :) *Note my understanding of how all this works could just be very wrong..... |
And for the next phase of this analysis... I'm trying to find docs on what exactly the "right" timezones mean. Not having much luck. The readme for the linux tzdata package states:
Which is weird as TAI does not have leap seconds. Leap seconds are applied to UTC so it stays within one second of UT1, correct? And we know UTC is behind TAI. Using I had high hopes for this article, and though long, it did not provide much info. But the phases "If the system clock is kept in TAI and a right/* timezone is used ..." is a repeated a couple of times. Are we perhaps reading this wrong? It seems POSIX (along with Unix time/epoch) have no support for leap seconds, it is up to something external to adjust the hardware clock to account for the second. And the unix epoch is defined as the number of seconds since 1970 minus the leap seconds (since leap seconds are not added to the epoch). Is it then perhaps that the |
@barefootcoder Any thoughts on any of this? Hoping your silence is due to contemplation and not because I'm way off base 😄 |
I'm not 100% sure, but I think this is a bug. Demonstrating it is easy, if you happen to have a sufficiently Linux-like OS:
(You might have to substitute something else for
/etc/timezone
if your OS is less Linux-like. I wouldn't even begin to know how to reproduce it on Windows.)Now, this might not be a bug at all ... if I twiddle my eyes just right, I can see how any leap seconds added prior to 4/1/1995 (of which there were 19, according to Wikipedia) might mean that 796694400 is actually a few seconds before midnight on the date in question. But that doesn't explain the inconsistency with
gmtime
in scalar context, or withPOSIX::strftime
. So I'm pretty sure it's a bug, although possibly not a bug with Time::Piece.But do note that only
$t->strftime
gives the surprising result:So I think the problem is probably with Time::Piece, since it seems to be internally inconsistent.
Or is there something deeper that I'm not understanding?
The text was updated successfully, but these errors were encountered: