Bug 15685
Summary: | at-3.1.7: Mishandles Time Zones | ||||||
---|---|---|---|---|---|---|---|
Product: | [Retired] Red Hat Linux | Reporter: | John Kono <jkono> | ||||
Component: | at | Assignee: | Crutcher Dunnavant <crutcher> | ||||
Status: | CLOSED RAWHIDE | QA Contact: | |||||
Severity: | medium | Docs Contact: | |||||
Priority: | medium | ||||||
Version: | 6.1 | ||||||
Target Milestone: | --- | ||||||
Target Release: | --- | ||||||
Hardware: | i386 | ||||||
OS: | Linux | ||||||
Whiteboard: | |||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2000-08-23 15:18:56 UTC | Type: | --- | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Attachments: |
|
Description
John Kono
2000-08-07 22:08:38 UTC
I agree, this is borken behavior on at's part. I've looked about in the at code, haven't found right way to fix it yet. It uses a bison parser :( After spending about an hour looking at the source code for at-3.1.7, I'm convinced that at is doing the right thing and that the fault is in the time-related functions in libc. The at command uses timezone (see CTIME(3) manpage and parsetime() in at-3.1.7/y.tab.c) to calculate the correct local time from UTC. Unfortunately, timezone returns a positive number for PST/PDT instead of a negative value. Okay, after taking some caffine and spending another hour playing with the time functions, I'm back to my original position. It looks like the timezone external returns the value of UTC - LOCAL_TIME, rather than LOCAL_TIME - UTC (which would be a more intuitive value, IMHO). So, to fix the bug, it looks like the following change needs to be made in line 306 of parsetime.y: exectime += timezone; to: exectime -= timezone; The actual modification and testing of fix is left as an exercise for the reader. :^) Yep, it's on crack. from time.h: extern long int __timezone; /* Seconds west of UTC. */ ^^^^ Guaranteeing that UTC TIME + timezone != Local Time. This is stupid. Putting in the fix. Okay, so there is something else screwing with the timezones. THis doesn't fix it. Still looking Created attachment 2878 [details]
at-3.1.8-UTC.patch
Okay, so THAT is the fix. In all the little files that use this, you need to: if (isgmt) { - exectime += timezone; + exectime -= timezone; if (daylight) { - exectime -= 3600; + exectime += 3600; } After some additional consideration (and a good night's sleep), I think that a slightly more elegant fix would be: if ( daylight = 0 ) exectime -= altzone; else exectime -= timezone; That should take care of DST conversions correctly for all values of TZ that have the correct DST info, as well as those that don't observe DST (e.g. Hawaii). Er, that should be: if ( daylight > 0 ) exectime -= altzone; else exectime -= timezone; Ooops. :( *Sigh* It looks like the altzone isn't defined in time.h with the current Linux distribution. This means that using the 3600 second offset if daylight is 1 is the quickest solution to the problem. Unfortunately, since some values of TZ have DST offsets other than 3600, the 3.1.8-UTC.patch may produce unexpected results. Also, if DST info is not available for a TZ, then daylight (and tm->tm_isdst) is supposed to be set to -1, which will also result in incorrect results. So, what's the solution? Well, it looks like a combination of our two fixes is the best we can do short-term, though people in places that use DST values other than 3600 will still have problems. exectime -= timezone; if (daylight > 0) exectime += 3600; I'll keep looking (as time permits) and, if a more elegant solution presents itself, I'll report it here. Okay, how about this? if (isgmt) { - exectime += timezone; - if (daylight) { + if (daylight > 0) { - exectime -= 3600; + exectime -= mktime( gmtime(&currtime) ) - + mktime( localtime(&currtime) ); + } else { + exectime -= timezone; } } The main assumption made by this fix is that the system is handling non-standard DST conversions (as defined in /usr/share/zoneinfo files) correctly for those TZs that use them. If not, well, that's a different bug... (sombody_elses_problem = TRUE; :^) Also, this may cause some problems if at is run before a DST switch date with a scheduled time after the switch, but then so does the current code and I can't think of a simple way to fix that short of major modifications. Ignore my last comment: localtime() does not take DST into account. Grr. So, in Linux, just how does one go about determining the correct DST offset for an arbitrary timezone? In SVR4, it's stored in altzone. I think the 'right' answer to this one is "use UTC". Anyone who is serious about time scheduling won't use a system that use daylight savings time (an idea whose time is waay over.) Short term, looks like we do the stupid thing, and use daylight > 0, and forget about it. (The alternative being, um, non-trivial.) |