tags 364975 patch
thanks
The following patch seems to be the quick and dirty way to fix this
problem:
diff -Naur a/parsetime.y b/parsetime.y
--- a/parsetime.y 2005-08-05 03:31:04.000000000 +0000
+++ b/parsetime.y 2007-09-26 14:24:26.000000000 +0000
@@ -503,8 +503,8 @@
return 0;
if (isgmt) {
exectime -= timezone;
- if (currtm.tm_isdst && !exectm.tm_isdst)
- exectime -= 3600;
+ if (exectm.tm_isdst > 0)
+ exectime += 3600;
}
if (exectime < currtime)
panic("refusing to create job destined in the past");
However, I believe this isn't good enough. Skip to the next paragraph
unless interested in a lengthy discussion of why I think so.
The fix seems to work in almost all cases, but might fail in subtle
ways when 'at' is invoked just before a DST forward adjustment in the
spring. For example, in timezone +01:00 with DST changeover to +02:00
at 02:00, consider the time specification "00:00 UTC + 2 hours". This
will cause 'at' to schedule commands for execution at 03:00 (+02:00).
This seems incorrect, at least when considering that "00:00 UTC + 3 hours"
will cause 'at' to schedule commands to be executed at 05:00 (+02:00).
This problem seem somehow to be related to the way DST shifts are
accounted for in the function add_seconds in file parsetime.y.
Also, the code fails when DST is observed and the DST shift is
anything other than 1 hour, which seems to be the case in at least
some rare locations. (But, since the DST shift is user-configurable by
setting the TZ environment variable, I think that other DST shifts
should be supported for this reason as well.)
So, I have also included a patch which attempts to be independent from
whether DST is observed in the handling of UTC, by setting the TZ
environment variable to UTC while parsing and converting the time
specification. This is suggested by the glibc documentation (section
21.4.3) as the most portable way to convert "broken-down time" (struct
tm) in UTC to "simple time" (time_t).
Unfortunately this requires somewhat more complicated code. This
includes setting TZ to UTC as soon as the UTC token is encountered in
the parsing of the time specification. This seems to be required
because during the parsing, some functions which rely on the TZ
variable, like mktime, might get called. Setting TZ at this point has
the effect that, for example when 'at' is issued just before a DST
fall-back, the time specification "23:00 UTC + 10 hours" will not be
interpreted as if really 11 hours is to be added instead of 10 (to
account for the DST shift), which would have been the case had "UTC"
not been specified. I believe this behavior is reasonable.
Also, the location in the code where TZ is set relies on the
requirement (which by chance is satisfied) that the time of day part
of the time specification (which contains the UTC token if it is
present) must be parsed before the date part, because it seems to be
only for tokens in the date part that such functions are called.
There also is code to restore the original state of the TZ environment
variable when the parsing and conversion are done, so that for example
the commands scheduled by at won't be affected by the changes to TZ.
diff -Naur a/parsetime.y b/parsetime.y
--- a/parsetime.y 2005-08-05 03:31:04.000000000 +0000
+++ b/parsetime.y 2007-11-23 19:39:29.000000000 +0000
@@ -4,12 +4,15 @@
#include <string.h>
#include <stdio.h>
#include "parsetime.h"
+#include "at.h"
+#include "panic.h"
#define YYDEBUG 1
static const char *svnid = "$Id$";
struct tm exectm;
static int isgmt;
+static char *tz = NULL;
static int yearspec;
static int time_only;
@@ -170,6 +173,12 @@
timezone_name : UTC
{
isgmt = 1;
+ if (getenv("TZ")) {
+ tz = (char *) mymalloc(strlen(getenv("TZ")) + 1);
+ strcpy(tz, getenv("TZ"));
+ }
+ if (setenv("TZ", "UTC0", 1) == -1)
+ panic("Virtual memory exhausted");
}
;
@@ -502,9 +511,13 @@
if (exectime == (time_t)-1)
return 0;
if (isgmt) {
- exectime -= timezone;
- if (currtm.tm_isdst && !exectm.tm_isdst)
- exectime -= 3600;
+ if (tz) {
+ if (setenv("TZ", tz, 1) == -1)
+ panic("Virtual memory exhausted");
+ free(tz);
+ }
+ else
+ unsetenv("TZ");
}
if (exectime < currtime)
panic("refusing to create job destined in the past");