If we're to view mktime as a general-purpose converter from struct tm to time_t, there's a gotcha waiting: struct tm doesn't contain any time zone information (the isdst flag doesn't help) and hence this conversion is ambiguous, unless you assume the local time zone or gmtime or some such thing. That's not a good assumption to make. In my implementation, I added two fields to struct tm, for the hours and minutes in the time zone (both are negative for us in the USA; well, I guess -0 is still 0 for the minutes) which resolved the ambiguity. I'm not sure if this change can be made in general without breaking things, and it could have been done with one field. The offset defines the tme zone the actual value in the struct tm is in; the isdst flag doesn't really have anything to do with it. Mark
That's a reasonable point, though I think most of the argument for mktime has been as an inverter of localtime(), and there simply using the timezone info from TZ is the right thing to do. However, I can certainly see uses where converting from some other timezone would be a nice ability to have - especially parsing rfc822 style Date: lines. But I think this is a pretty specialized usage, there aren't that many other applications where the necessary zone information is going to be available in just the right form. Most places where times are used with the zone included, the zone is converted to its zone name form, and that is not an invertible operation - there is no definable mapping from zone names to numeric offsets, so the ability to make this transformation correctly isn't going to happen all that often. What's more, in cases where I simply want to convert a local time in struct tm format to a time_t, I am not necessarily going to know what the zone is. Consider the use of mktime() inside date(1). Some user types a date/time which is easy to parse into a struct tm, from there it should be possible to use mktime() to get the time_t. But if you have to know the zone first things aren't nearly that easy. It certainly isn't a constant - it depends on the particular time that the user typed. So, I would suggest a new function to handle mktime() with a supplied zone, which would look at extra info in the struct tm. I have a couple of misgivings about your implementation though. I'm not sure exactly what the point of having 2 fields for hours and minutes is - that assumes that the offset is an even number of minutes (no odd seconds) which while likely, isn't something I would want to bet my life upon (I would assume that the USG people assumed it likely that there would be no minute offsets, only even hours when doing the standard Sys III/Sys V implementation...) So, I would suggest a single field that contains the offset in seconds from GMT. Secondly, I'm not sure why you chose to have West of Greenwich being negative. All previous uses of timezone offsets in Unix have been the other way - West of Greenwich positive. I know that the ISO standard defines it as West == negative, but its surely an arbitrary choice, its trivial to negate the value anywhere an ISO form of offset is needed, and keeping this compatability with current (old) usages (from v6 through 4.3bsd, and pwb to Sys V) certainly seems to be a worthwhile objective. Finally .. such a field just happens to be in the new struct tm that is used with the latest mods I made to localtime and returned to elsie!ado just a few days ago.... (localtime provides this information for every time_t it converts to a srtuct tm. I also added the zone name in struct tm. Both of those had been suggested before by others, and both seemed to be clearly the right thing to do.) On another subject, since I'm sending this to the list... Perverting mktime to be able to deal with out of range struct tm's is clearly absurd. It can't be done correctly - I don't know who suggested this to x3j11 but I suspect that they were simply looking at their implementation, seeing that this "seems to work" and that it "seems to be useful" so deciding to standardise it. I have no contact whatever with x3j11, but I suspect some of the readers of this list do, so please ask them how they cope with this example (change the details to be more relevant in the US if you prefer). According to the rationale, I'm supposed to be able to add an hour to a struct tm, and convert that to a time_t, to produce the corresponding effect to the time_t. For that to make any sense at all, I must also be able to subtract an hour from a struct tm and have mktime convert that to the corresponding time_t. Consider tm.{tm_year = 86, tm_mon = 9 /*October*/, tm_mday = 19, tm_hour = 1, tm_min=30, tm_sec = 0} That just happens to be 30 minutes before daylight saving switched on here (Australia) this summer. now consider tm.tm_hour++; t = mktime(&tm); tm = *localtime(&t); tm.tm_hour--; t = mktime(&tm); tm = *localtime(&t); What is supposed to happen here exactly? X3J11 have (apparently) defined mktime() to work even when the time_t is out of range, so the first call to mktime() must succeed. Beats me what value it returns, but there had better be one. Now since localtime() and mktime() are supposed to be inverses, the first call to localtime should simply have the effect of "normalizing" the struct tm after the addition, it will represent the value mktime() returned. In any rational system of arithmetic, subtracting 1 has the effect of reversing a previous addition of 1, so the final value of tm above should be the same thing as it was before we started. (As long as we haven't ever gone outside the range of legal values of course). Any other result is too absurd to consider. Does anyone here want to find me a version of mktime() that will actually achieve this? I would kind of suspect that the result of the first localtime is going to be 03:30 (which is one hour elapsed time more than 01:30 where we started, which is what the aim of all this is). Subtract an hour from that, and you get 02:30 in the tm, which is the exact same value that was there when an hour was added to the 01:30 we started with. How is mktime() supposed to distinguish those two cases? But the second time its supposed to resolve the illegal time the other way and give 01:30. Some hope! Any rational mktime() would define the first call above to be an error, since the time handed to it does not (never did, never will) exist. Doing that means that the values have gone out of range, and arithmetic no longer needs to behave normally, so everything is OK. Its probably possible to play similar games with the times around when daylight saving switches off. Trying to do arithmetic on non-continuous domains (is this the right word?) isn't productive, and struct tm's aren't continuous. Clearly the right thing to do is to do arithmetic on time_t's which are nicely continuous. I'm not sure exactly what's going on here, but I suspect that x3j11 are allowing for the possibility that a time_t is not an integral type represnting seconds since the epoch. Is that right? I suppose that they do realize that changing that is going to break just about every program using time_t's written in C anywhere? Though that doesn't seem to have bothered x3j11 much anywhere else. I really do wish that posix would completely cut itself away from that abortion - not depend on it anywhere. kre
participants (2)
-
Robert Elz -
seismo!cbpavo.MIS.OH.ATT.COM!mark