Mail Archives: djgpp/2000/12/20/16:06:32
ftilley AT azstarnet DOT cyberbromo DOT com (Felix Tilley) wrote:
> All of the GMT offsets are wrong. Dates and times are correct, but
> the GMT offsets are wrong.
There appears to be a bug in strftime() when using the %z format.
Well, actually not so much a bug as a feature. ;-)
At the moment, the number of seconds offset from GMT is used, unless
it is negative, in which case 0000 is used.
I've patched strftime.c to fix this. The patch is attached at the
bottom of this message. There is also some more test code to
demonstrate the problem.
Note: The original code posted by Felix, poked values into the
tm_gmtoff and tm_zone fields to simulate a time-zone shift. I don't
know if that's a valid method (mktime() seems to reset those fields
without using their values) but it works well enough as a test case
for this patch.
With existing strftime the test program outputs:
Wed, 20 Dec 2000 20:35:42 +0000 GMT
Wed, 20 Dec 2000 20:35:42 +0000 GMT
Wed, 20 Dec 2000 08:01:42 -0000 TEST1
Thu, 21 Dec 2000 09:09:42 +45240 TEST2
After patching the test program outputs:
Wed, 20 Dec 2000 20:36:21 +0000 GMT
Wed, 20 Dec 2000 20:36:21 +0000 GMT
Wed, 20 Dec 2000 08:02:21 -1234 TEST1
Thu, 21 Dec 2000 09:10:21 +1234 TEST2
Here is the test program:
/******************* start of test code ********************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void PrintTime(const char *fmt, const struct tm *tm);
int main(void)
{
time_t now;
struct tm *tm;
const char *fmt = "%a, %d %b %Y %X %z %Z";
time(&now);
PrintTime(fmt, gmtime(&now));
PrintTime(fmt, localtime(&now));
tm = gmtime(&now);
tm->tm_hour -= 12;
tm->tm_min -= 34;
tm->tm_gmtoff = difftime(mktime(tm), now);
tm->tm_zone = "TEST1";
PrintTime(fmt, tm);
tm = gmtime(&now);
tm->tm_hour += 12;
tm->tm_min += 34;
tm->tm_gmtoff = difftime(mktime(tm), now);
tm->tm_zone = "TEST2";
PrintTime(fmt, tm);
return 0;
}
void PrintTime(const char *fmt, const struct tm *tm)
{
char str[256];
if (strftime(str, sizeof(str), fmt, tm) > 0)
puts(str);
else
puts("oops!");
}
/******************* end of test code ********************/
Here is the patch:
--- src/libc/ansi/time/strftime.c.orig Thu Jun 3 13:27:34 1999
+++ src/libc/ansi/time/strftime.c Wed Dec 20 19:25:00 2000
@@ -61,6 +61,8 @@
static size_t
_fmt(const char *format, const struct tm *t, int upcase)
{
+ long gmtoffset, gmtoffset_mins, gmtoffset_hrs;
+
for (; *format; ++format)
{
if (*format == '%')
@@ -218,10 +220,23 @@
return 0;
continue;
case 'z':
- if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
- return 0;
- if (!_conv(t->__tm_gmtoff, 4, pad))
- return 0;
+ gmtoffset_mins = (t->__tm_gmtoff / 60) % 60;
+ gmtoffset_hrs = t->__tm_gmtoff / 3600;
+ gmtoffset = (gmtoffset_hrs * 100) + gmtoffset_mins;
+ if (gmtoffset<0)
+ {
+ if (!_add("-", 0))
+ return 0;
+ if (!_conv(-gmtoffset, 4, pad))
+ return 0;
+ }
+ else
+ {
+ if (!_add("+", 0))
+ return 0;
+ if (!_conv(gmtoffset, 4, pad))
+ return 0;
+ }
continue;
case 'Z':
if (!t->tm_zone || !_add(t->tm_zone, upcase))
- Raw text -