Since %Z gives timezone, and %z is available for use, the patch below
(against 3.5-STABLE) for /usr/src/lib/libc/stdtime/strftime.c will add
the desired functionality, provided that ISO8601_TIMEZONES is defined.
This is experimental, and there is no bounds checking for bad values in
the struct tm, so the patch does nothing to define ISO8601_TIMEZONES.
>How-To-Repeat:
Use strftime(3).
>Fix:
--- /usr/src/lib/libc/stdtime/strftime.c Tue Mar 14 21:54:50 2000
+++ strftime.c Mon Jul 24 23:54:12 2000
@@ -388,6 +388,31 @@
pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
pt, ptlim);
continue;
+#ifdef ISO8601_TIMEZONES
+ case 'z':
+ {
+ long offabs;
+ int offhr;
+ int offmin;
+ char offsign[2];
+
+ offsign[1] = '\0';
+ if (t->tm_gmtoff < 0) {
+ *offsign = '-';
+ offabs = - t->tm_gmtoff;
+ } else {
+ *offsign = '+';
+ offabs = t->tm_gmtoff;
+ }
+ offhr = offabs / 3600;
+ offmin = (offabs - offhr*3600) / 60;
+
+ pt = _add(offsign, pt, ptlim);
+ pt = _conv(offhr, "%02d", pt, ptlim);
+ pt = _conv(offmin, "%02d", pt, ptlim);
+ }
+ continue;
+#endif /* defined ISO8601_TIMEZONES */
case 'Z':
if (t->tm_zone != NULL)
pt = _add(t->tm_zone, pt, ptlim);
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majo...@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
> >Synopsis: strftime() can't produce ISO8601 format timezone representation
I have been informed that GNU strftime() implements this same behaviour,
using %z in the same way. My only available reference is an old Debian
box which does not document this. I have not examined the code. This
is a clean-room implementation.
Thinking about -0000 ("not telling you my timezone") - I seem to recall
that there was a struct tm entry which could be used for this. An old
fuzzy memory suggests tm_isdst, but this is not documented on FreeBSD
strftime(3). strftime.c has %Z giving '?' if tm_isdst is not either 0
or 1 - my memory suggests -1. This would have been either Solaris or
GNU, from documentation read some time ago. If an definitive answer for
this can be given, the code mod is trivial.
A feature request (already!) is to support +nn:nn which allegedly the
GNU version can't handle. Could someone with appropriate authority
please say if it is acceptable to use %Ez? I suspect not. :^/
--
Phil Pennock <p...@nl.demon.net> <Phil.P...@thus.net>
Demon Internet Nederland -- Network Operations Centre -- Systems Administrator
Libertes philosophica.
Sales: +31 20 422 20 00 Support: 0800 33 6666 8
According to the new C Standard (C99), %z is supposed to be replaced by
"the offset from UTC in the ISO 8601 format 荘ュ0430鋳 (meaning 4 hours
30 minutes behind UTC, west of Greenwich), or by no characters if no
time zone is determinable." It's not determinable if tm_isdst is
negative.
%Z ought to be replaced by "the locale痴 time zone name or abbreviation,
or by no characters if no time zone is determinable.". The names are
locale-dependent, and in the C locale they are implementation-defined.
In the old Standard (C89) %z is undefined, and %Z is defined to be
replaced by "the time zone name, or by no characters if no time zone is
determinable."
I think if strftime() were to be modified then the implementation ought
to follow the C99 Standard.
> Thinking about -0000 ("not telling you my timezone") - I seem to recall
> that there was a struct tm entry which could be used for this. An old
> fuzzy memory suggests tm_isdst, but this is not documented on FreeBSD
> strftime(3). strftime.c has %Z giving '?' if tm_isdst is not either 0
If I understand correctly, tm_isdst is in fact the flag to indicate
this, but the result should really be "no characters" if the TZ is
unknown.
FreeBSD's not documenting may be due to the fact that the system is
always running in a known TZ, defaulting to UTC.
> or 1 - my memory suggests -1. This would have been either Solaris or
According to the Standard, positive means 'daylight saving time', 0
means 'normal time' and negative means 'unknown'.
> GNU, from documentation read some time ago. If an definitive answer for
> this can be given, the code mod is trivial.
>
> A feature request (already!) is to support +nn:nn which allegedly the
> GNU version can't handle. Could someone with appropriate authority
> please say if it is acceptable to use %Ez? I suspect not. :^/
Neither %z nor %Z have an E or O modifier defined by the Standard; that
would be undefined behaviour then, which FreeBSD's implementation would
take the liberty to define. IMHO that's ok (the compiler can do anything
it likes if the source contains undefined behaviour, including something
sensible), but all the sources using the feature would be unportable.
(There's also a new 'struct tmx' in C99, which contains a member
'tm_zone' providing the timezone directly in minutes. It's used by
mkxtime(), strfxtime() and related functions. You still don't get a %Ez
from this, though.)
The Standard is available at
http://anubis.dkuug.dk/JTC1/SC22/open/n2794/n2794.pdf in a draft
version.
Coo - and thanks for the PDF reference. I'll read C99 RSN.
> "the offset from UTC in the ISO 8601 format ``0430'' (meaning 4 hours
> 30 minutes behind UTC, west of Greenwich), or by no characters if no
> time zone is determinable." It's not determinable if tm_isdst is
> negative.
The patch is trivially modifiable to do this "no characters", now that
the nudge has been given to provide it.
> %Z ought to be replaced by "the locale's time zone name or abbreviation,
> or by no characters if no time zone is determinable.". The names are
> locale-dependent, and in the C locale they are implementation-defined.
>
> In the old Standard (C89) %z is undefined, and %Z is defined to be
> replaced by "the time zone name, or by no characters if no time zone is
> determinable."
The current implementation does not follow either standard. If tm_isdst
is 0 or 1, then the timezone is inserted, otherwise the character '?'.
The timezone name is drawn from the discouraged[*] tzname[] and not the
char *tm_zone member - which only seems to make sense if you don't trust
tm_zone to have been set.
[*] ctime(3) BUGS section
> I think if strftime() were to be modified then the implementation ought
> to follow the C99 Standard.
Fine by me. Would you like an alternate patch, or is the one which I
supplied an adequate base?
> FreeBSD's not documenting may be due to the fact that the system is
> always running in a known TZ, defaulting to UTC.
So is there a supported method for an application which doesn't want to
reveal its timezone to do this with strftime(), other than just
hardcoding the string -0000 into the format string and handling this
logic at a higher level?
The use of -0000 comes from use in various rfc822-style headers -
primarily Received: - although I don't have a handy reference indicating
the appropriate RFC - it's not 822.
--
Phil Pennock <p...@nl.demon.net> <Phil.P...@thus.net>
Demon Internet Nederland -- Network Operations Centre -- Systems Administrator
Libertes philosophica.
Sales: +31 20 422 20 00 Support: 0800 33 6666 8
The bibliography for rfc822 references:
ANSI. "Representations of Universal Time, Local Time Differen-
tials, and United States Time Zone References for Information
Interchange," X3.51-1975. American National Standards Insti-
tute: New York (1975).
I don't have access to that document to check it. It would be
interesting to know if C99 is contradicting an ANSI standard or merely
established MTA practice for 'not telling you' timezone representation.
I don't consider myself to be knowledgeable enough to judge if your
patch is adequate. Although I have been programming C for some time, I'm
only just beginning with FreeBSD. For example, 'tm_gmtoff' is news to
me, as are '_add' and '_conv'. But, judging from the names, it looks
adequate.
However, In my /usr/src/lib/libc/stdtime/strftime.c (4.1-RC as of Mon
Jul 17) both 'Z' and 'z' are already implemented (in a way almost
equaling your patch). I suggest to migrate that source back into 3.5, in
order to avoid source splitting.
(The 4.1-RC source still has the problem of asking is tm_isdst is ==1
(should be >0), and it uses a '?' if the TZ is unknown (should be
nothing).)
> > FreeBSD's not documenting may be due to the fact that the system is
> > always running in a known TZ, defaulting to UTC.
>
> So is there a supported method for an application which doesn't want to
> reveal its timezone to do this with strftime(), other than just
> hardcoding the string -0000 into the format string and handling this
> logic at a higher level?
I'd say, strftime() cannot, if asked to provide the timezone, lie about
it. The application ought not to ask for %z or %Z if it doesn't want the
TZ in the string IMHO.
> The use of -0000 comes from use in various rfc822-style headers -
> primarily Received: - although I don't have a handy reference indicating
> the appropriate RFC - it's not 822.
I guess (but don't know as a fact) that these mail servers are really
running in UTC? I can't think of a reason why a mail server should want
to hide its timezone.
Greetings,
Bernd
I'd say, if ISO 8601 and the C Standard agree, then that ought to be
good enough.
As to the 'not telling you' in 'received:'-headers: not telling the TZ
essentially invalidates the time stamp, because if you don't know the TZ
then the time stamp doesn't tell you anything. Hence, these mail servers
not only hide their TZ but also the 'received'-time. I don't think this
is a good practice.
Concerning RFC 822 and time specifications, RFC 1123 has corrections and
clarifications:
--------------8<------------
All mail software SHOULD use 4-digit years in dates, to ease the
transition to the next century.
There is a strong trend towards the use of numeric timezone indicators,
and implementations SHOULD use numeric timezones instead of timezone
names. However, all implementations MUST accept either notation. If
timezone names are used, they MUST be exactly as defined in RFC-822.
The military time zones are specified incorrectly in RFC-822: they count
the wrong way from UT (the signs are reversed). As a result, military
time zones in RFC-822 headers carry no information.
Finally, note that there is a typo in the definition of "zone" in the
syntax summary of appendix D; the correct definition occurs in Section 3
of RFC-822.
--------------8<------------