Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001533 [1003.1(2016/18)/Issue7+TC2] Base Definitions and Headers Editorial Enhancement Request 2021-11-08 22:04 2022-06-30 15:38
Reporter steffen View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Resolved  
Name steffen
Organization
User Reference
Section time.h
Page Number 425
Line Number 14451
Interp Status ---
Final Accepted Text Note: 0005878
Summary 0001533: struct tm: add tm_gmtoff (and tm_zone) field(s)
Description Hello.

Regarding the MUA i maintain i was pinged by a user who needs to
use the timezone Europe/Dublin. He wrote

      In 2018, the tzdata maintainers (IANA) corrected a historical mistake
      with the Europe/Dublin timezone. The mistake was rooted in a
      misunderstanding of whether IST meant "Irish Summer Time" or "Irish
      Standard Time".

      The problem was discussed at great length
      (http://mm.icann.org/pipermail/tz/2018-January/thread.html) [^] and it was
      concluded that IST really meant Irish *Standard* Time (in constrast
      with, say, British *Summer* Time), and that this standard time is
      defined as UTC+0100.
[.]
      Once the question was settled, the only possible solution for keeping
      the Irish local time in sync with the rest of the world (for example,
      Belfast & London) was for IANA to _reverse_ the functioning of the DST
      flag for Ireland. The result is that in the current IANA timezone
      database (2021e), Europe/Dublin has DST applied in *winter*, with an
      adjustment of -1h (that is, negative).
[.]
      It turns out that the introduction of a negative DST adjustment caused
      all sorts of bugs back in 2018; in the source distribution of IANA's
      tzdata, one can spot this inside ./europe:

        # In January 2018 we discovered that the negative SAVE values in the
        # Eire rules cause problems with tests for ICU [...] and with tests
        # for OpenJDK [...]
        # To work around this problem, the build procedure can translate the
        # following data into two forms, one with negative SAVE values and the
        # other form with a traditional approximation for Irish timestamps
        # after 1971-10-31 02:00 UTC; although this approximation has tm_isdst
        # flags that are reversed, its UTC offsets are correct and this often
        # suffices. This source file currently uses only nonnegative SAVE
        # values, but this is intended to change and downstream code should
        # not rely on it.

      So, a temporary hack was put in place in order to allow distro
      maintainers to retain the old broken convention of IST and support
      buggy software, but it is clear that the current (and technically, and
      politically, correct) implementation of a negative DST adjustment for
      Ireland is there to stay.
      As a matter of fact, the distro maintainer can choose to compile
      tzdata to keep buggy software happy ("make DATAFORM=rearguard"),
      which replicates the behaviour of tzdata prior to 2018. Many distros
      seem to be doing that for one reason or another, while some have passed
      the upstream change down to their users (probably, without knowing).

Anyhow, all the simple minded software, including the MUA
i maintain, used to do something like

   if((t2 = mktime(gmtime(&t))) == (time_t)-1){
      t = 0;
      goto jredo;
   }
   tzdiff = t - t2;
   if((tmp = localtime(&t)) == NULL){
      t = 0;
      goto jredo;
   }

   tzdiff_hour = (int)(tzdiff / 60);
   tzdiff_min = tzdiff_hour % 60;
   tzdiff_hour /= 60;
   if (tmp->tm_isdst > 0)
      tzdiff_hour++;

Note the .tm_isdst plus positive summer time adjustment.
This was overly primitive, and i recognize that POSIX supports the
%z (and %Z) formats for strftime(3), and in general code as below
is used by projects, so doing it right is very expensive but
doable with POSIX as of today.

However, all BSDs and Linux with either of GNU and musl C library
support the .tm_gmtoff (and .tm_zone) members of "struct tm", in
general all users of the public domain (and standardized) IANA TZ
project can bake it in upon their own desire.. With .tm_gmtoff
being available, code gets as simple as
  s64
  time_tzdiff(s64 secsepoch, struct tm const *utcp_or_nil,
        struct tm const *localp_or_nil){
     struct tm tmbuf[2], *tmx;
     time_t t;
     s64 rv;
     UNUSED(utcp_or_nil);

     rv = 0;

     if(localp_or_nil == NIL){
        t = S(time_t,secsepoch);
        while((tmx = localtime(&t)) == NIL){
           if(t == 0)
              goto jleave;
           t = 0;
        }
        tmbuf[0] = *tmx;
        localp_or_nil = &tmbuf[0];
     }

  #ifdef HAVE_TM_GMTOFF
     rv = localp_or_nil->tm_gmtoff;

  #else
     if(utcp_or_nil == NIL){
        t = S(time_t,secsepoch);
        while((tmx = gmtime(&t)) == NIL){
           if(t == 0)
              goto jleave;
           t = 0;
        }
        tmbuf[1] = *tmx;
        utcp_or_nil = &tmbuf[1];
     }

     rv = ((((localp_or_nil->tm_hour - utcp_or_nil->tm_hour) * 60) +
           (localp_or_nil->tm_min - utcp_or_nil->tm_min)) * 60) +
           (localp_or_nil->tm_sec - utcp_or_nil->tm_sec);

     if((t = (localp_or_nil->tm_yday - utcp_or_nil->tm_yday)) != 0){
        s64 const ds = 24 * 60 * 60;

        rv += (t == 1) ? ds : -S(s64,ds);
     }
  #endif

  jleave:
     return rv;
  }
Desired Action Insert at the given location

<code>
 int tm_gmtoff Seconds east of UTC
 const char *tm_zone Timezone abbreviation
</code>

Maybe cross-reference with strftime(3) and note relationship to the %z and %Z formats.
Tags issue8
Attached Files

- Relationships

-  Notes
(0005529)
steffen (reporter)
2021-11-21 22:28

P.S.: even though "Object or binary code portability" is outside the "1.1 Scope" of POSIX i want to add, just in case that the strftime(3) formats are yet part of the standard whereas tm_gmtoff is not even though it exists for long is because of binary compatibility nonetheless, that with dynamic library symbol versioning binary compatibility is overall not an issue, or, simpler via compile-time preprocessor switches, or even specific #pragma compiler directives (Solaris seems to use "#pragma redefine_extname") at least newly compiled code does not have issues.
As you all know, of course.
(0005530)
geoffclare (manager)
2021-11-22 09:47

Re Note: 0005529 The compatibility issue is not simply one of handling the increased structure size; there is also a behavioural difference.

On an implementation that lacks tm_gmtoff and tm_zone, if you change TZ after obtaining a struct tm from localtime(), the strftime() %z and %Z conversions use the values for the new TZ. Adding tm_gmtoff and tm_zone would change the behaviour such that %z and %Z use the values for the old TZ. This could break existing applications when they are recompiled and consequently start using the new ABI.
(0005531)
geoffclare (manager)
2021-11-22 10:12

I started wondering about where tm_zone points (since there is no function to free it), and came across this on the MacOS localtime(3) man page (under BUGS):
The tm_zone field of a returned tm structure points to a static array of characters, which will also be overwritten by any subsequent calls (as well as by subsequent calls to tzset(3) and tzsetwall(3)).
So perhaps what I wrote in my previous note about %Z using the old TZ is not true (at least for some implementations that support tm_zone).

If we want to add tm_gmtoff and tm_zone, the standard will need to go into this kind of detail.
(0005532)
geoffclare (manager)
2021-11-22 10:50

The desired action has tm_gmtoff as an int, but in glibc and MacOS it is a long. If there are implementations where it is an int, then to add it to the standard we would need to introduce a new type such as gmtoff_t.

MacOS also doesn't have the const on tm_zone, but I doubt if adding it would cause any problems.
(0005533)
steffen (reporter)
2021-11-22 15:26

Re Note: 0005530 and Note: 0005531
I see. Yes, strftime(3) notes on page 2047 regarding %Z on TZ change!
Standard is hard .. i had a single file DB with a TOC of names at the end pointing to data at the front, if a non-builtin one was needed then all was there to stay after being loaded. I see.
musl does it like

<code>
const char *__tm_to_tzname(const struct tm *tm)
{
        const void *p = tm->__tm_zone;
        LOCK(lock);
        do_tzset();
        if (p != __utc && p != __tzname[0] && p != __tzname[1] &&
            (!zi || (uintptr_t)p-(uintptr_t)abbrevs >= abbrevs_end - abbrevs))
                p = "";
        UNLOCK(lock);
        return p;
}
</code>

therefore even using .tm_zone as a verification that %Z applies to the correct struct tm, which is an assertion beyond the usual "behaviour is undefined".

Re 0005532:
Oh! Indeed they use long not int, sorry! No, i do not know a system where this is int, actually -- sorry for this! I am afraid the standard cannot correct this; i personally never worked on a system where int was 16-bit, where that decision would make some sense. gmtoff_t does not seem to be needed:

<code>
#?0|kent:free-src.git$ git grep tm_gmtoff origin/main:include
origin/main:include:time.h: long tm_gmtoff; /* offset from UTC in seconds */
#?0|kent:free-src.git$ cd ../open-src.git/
#?0|kent:open-src.git$ git grep tm_gmtoff origin/master:include
origin/master:include:time.h: long tm_gmtoff; /* offset from UTC in seconds */
#?0|kent:open-src.git$ cd ../net-src.git/
#?0|kent:net-src.git$ git grep tm_gmtoff origin/trunk:include
origin/trunk:include:time.h: long tm_gmtoff; /* offset from UTC in seconds */
#?0|kent:net-src.git$ cd ../dfly-src.git/
#?0|kent:dfly-src.git$ git grep tm_gmtoff origin/master:include
origin/master:include:time.h: long tm_gmtoff; /* offset from UTC in seconds */
</code>

..even..

<code>
#?0|kent:unix-hist$ git grep tm_gmtoff BSD-SCCS-END
BSD-SCCS-END:usr/src/include/time.h: long tm_gmtoff; /* offset from CUT in seconds */
BSD-SCCS-END:usr/src/lib/libc/gen/ctime.3:long tm_gmtoff; /\(** offset from UTC in seconds \(**/
BSD-SCCS-END:usr/src/lib/libc/gen/ctime.3:.Fa tm_gmtoff
BSD-SCCS-END:usr/src/lib/libc/gen/ctime.c: tmp->tm_gmtoff = offset;
BSD-SCCS-END:usr/src/lib/libcompat/4.1/ftime.c: if (tm->tm_isdst) { /* tm_gmtoff has an offset applied */
BSD-SCCS-END:usr/src/lib/libcompat/4.1/ftime.c: tp->timezone = -localtime(&zero)->tm_gmtoff / 60;
BSD-SCCS-END:usr/src/lib/libcompat/4.1/ftime.c: tp->timezone = -tm->tm_gmtoff / 60;
BSD-SCCS-END:usr/src/share/zoneinfo/Makefile:# -DTM_GMTOFF=tm_gmtoff
BSD-SCCS-END:usr/src/share/zoneinfo/Makefile:# -DTM_GMTOFF=_tm_gmtoff
BSD-SCCS-END:usr/src/share/zoneinfo/Makefile:CFLAGS= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone
BSD-SCCS-END:usr/src/usr.bin/chpass/util.c: tval -= lt->tm_gmtoff;
</code>

and

<code>
#?128|kent:unix-hist$ git blame BSD-SCCS-END -- usr/src/include/time.h
..
aec2dfdbbb2 (Keith Bostic 1989-03-08 23:45:57 -0800 49) long tm_gmtoff; /* offset from CUT in seconds */
aec2dfdbbb2 (Keith Bostic 1989-03-08 23:45:57 -0800 50) char *tm_zone; /* timezone abbreviation */
..

#?0|kent:unix-hist$ git blame aec2dfdbbb2^ -- usr/src/include/time.h
...
434fabe335c (Keith Bostic 1987-03-05 01:28:35 -0800 22) long tm_gmtoff;
434fabe335c (Keith Bostic 1987-03-05 01:28:35 -0800 23) char *tm_zone;
</code>

..and we come to..

<code>
commit 434fabe335c23dd3f16ab2d4ff3878b9bc69be50
Author: Keith Bostic <bostic@ucbvax.Berkeley.EDU>
AuthorDate: 1987-03-05 01:28:35 -0800
Commit: Keith Bostic <bostic@ucbvax.Berkeley.EDU>
CommitDate: 1987-03-05 01:28:35 -0800

    added Robert Elz's additions for new time package

    SCCS-vsn: include/time.h 1.2
---
 usr/src/include/time.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/usr/src/include/time.h b/usr/src/include/time.h
index 8eb62c0453..0233380029 100644
--- a/usr/src/include/time.h
+++ b/usr/src/include/time.h
@@ -1,4 +1,10 @@
-/* time.h 1.1 85/03/13 */
+/*
+ * Copyright (c) 1983, 1987 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)time.h 1.2 (Berkeley) %G%
+ */

 /*
  * Structure returned by gmtime and localtime calls (see ctime(3)).
@@ -13,6 +19,8 @@ struct tm {
        int tm_wday;
        int tm_yday;
        int tm_isdst;
+ long tm_gmtoff;
+ char *tm_zone;
 };

 extern struct tm *gmtime(), *localtime();
</code>

at which time i have to say Hello and a nice day dear Robert Elz!

So given this is from 1987 i would think 34 years give the guarantee that all possible UNIX systems go for long here. Apologies!
(0005534)
steffen (reporter)
2021-11-22 15:36

P.S.: it seems to me not having "const" for tm_zone roots in incomplete transition to modern times here and there. ..Is this only a documentation miss or also a code negligence? Bit rot here, bit rot there, bit rot is just everywhere, ha-ha. Hrm, sorry. Was it Wheeler with "Programming is an iterative task"? Also applies to bit rot anyhow, const, volatile, restrict, atomic_t, ten years ago i was overrun when i said it needs to be volatile atomic_t instead of simple int or volatile int on some perl list/forum, just a few weeks ago i was corrected for not doing it, ... anyway this is all off-topic. const i always liked, today even rodata is put into the text section .. likely to have an excuse to create hundreds of specialized object file sections for whatever purpose. Terrible, volatile ok, but why atomic_t, aehh, ...
(0005656)
shware_systems (reporter)
2022-02-03 16:58

Re: 5534

The tm struct predates const being added as a keyword to the language, so stays without the const for backwards compatibility. Adding const would be in the province of a new struct and interfaces using it, that I see.
(0005657)
Don Cragun (manager)
2022-02-03 17:32

This was discussed in the February 3, 2022 teleconference. There were no objections to adding these fields; however, we need a more fully fleshed-out proposal including details of how the storage for tm_zone may be affected by later calls (including tzset()). This is likely to be different for localtime() and localtime_r(). There will also be changes needed to the strftime() page, for example, where it lists the tm members that affect each conversion.

Please submit a new note with the desired replacement for the Desired Action field in this issue.
(0005658)
kre (reporter)
2022-02-03 18:41

Despite not being affected personally (our implementation contains those
fields already, and kind of obviously I think they're a good idea, even if
tm_zone was perhaps not all that well designed) I'm not sure that adding them
to the standard is an appropriate thing to do.

For an implementation to keep any kind of ABI compatibility with an older
version of struct tm is unbelievably hard - this is (partly) why (I believe)
that no-one who has moved to 64 bit time_t has taken the step of making
tm_year a wider integer (or adding a new field to accomplish the same),
so it can represent all of the timestamps that a time_t can hold. The
systems which added tm_gmtoff and tm_zone added those so long ago, that there
was nothing anyone really cared to retain binary compat with, just
recompile the world, and everyone is happy. That's no longer possible.

Further we really need a whole new variant of struct tm, that can be designed properly to cope with current uses - as well as a wider tm_year, it should
also contain sub-second information (so it can properly handle times from
timevals and timespecs, and other similar things that exist). That could
have tm_zone done better (if it really needs to exist at all - these time zone
abbreviations are close to useless these days - they're undefined, ambiguous,
... anything that cares simply uses the numeric offset rather that one of
those names).

The new struct then needs a whole new set of functions (all the localtime()
gmtime() ctime() ... nmed to change - though if the replacements are well
designed, an implementation can probably provide a set of #defines to map
the old interfaces into the new, so that old source code needs less changes).

Of course, doing this is *not* a project for this group - someone needs to
do the work (and there's lots of it), then have that reviewed and fixed,
and finally get it implemented, used, tested, and fixed again, until it
stabilises into something actually useful, before we should be taking any
notice of it here.

But the need for all that, along with the difficulties that would be dumped
upon implementations should the standard require changes to the tm struct,
makes me believe that making changes now is not the right thing to do, as
unfortunate as that might be. These changes are not enough to be truly
useful long term, yet enough to be an implementation nightmare (for
implementations currently lacking them.)

Lastly, as struct tm is defined in the standard now, it represents what is
probably the longest remaining unchanged (and still used) structure in unix
systems, It would be a pity to lose that...
(0005660)
steffen (reporter)
2022-02-03 22:18

re #0005657:

  Please submit a new note with the desired replacement for the Desired Action field in this issue.

Thanks for considering this.
I .. will have to reread Geoff's concerns and spend real time with preparing a note, judiciously looking into that instead of just throwing code words. This will take some time, but i will do this.

re #0005658:
Dear kre; in reality this code is much too simple minded per se, as it only ever was designed to deal with so-called Christian calendars, while users of other programming languages than ISO/POSIX C have a notion of lots of others.

It seems to me that breaking down super high precision times to second intervals is good enough to describe human calendars however, human sense of time is not a stock exchange where market values of gold diggers, Mercedes-Benz or LandRover or Suzuki or you name it, varies on microsecond level; they also bet on the life on animals who's mothers are not even born yet, this surely is bizarrely schizophrenic and if you would listen to your own crown prince or his "dear papa" that we unfortunately lost last year you would surely make a distinction in between life and art. And while we all will not witness it, to make it plain that if future humans could do time travels our generations would surely have been suspended to avoid that much loss of life, in my opinion, extending the year field to more than 32-bit seems unnecessary for the planet that we live on; whether it still can support living by then, or whether the clowds, if any remain, will look like upside down pyramids, as people seem to have suggested in a 70s film from New Zealand i think it was ... is surely completely off-topic.

Will do when i have some hours time for this!
(0005664)
mirabilos (reporter)
2022-02-06 11:37

@kre I’ve switched tm_year to type time_t as part of the “make time_t 64-bit on i386” conversions in MirBSD, where binary backwards compatibility was a nōn-issue, on 2004-11-22. It was required to pass the mktime test of GNU autoconf as shipped in GNU CVS, at that time, and in general works better.

The downside was the huge amount of patches needed to do…

- res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ",
- gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday,
+ res = fprintf(ofile, "%04lld%02d%02d%02d%02d%02d %u %u %u %u %x ",
+ (long long)gtm->tm_year + 1900LL, gtm->tm_mon + 1, gtm->tm_mday,
            gtm->tm_hour, gtm->tm_min, gtm->tm_sec,
            otype, otests, otries, osize, ogenerator);

(example from OpenSSH) to all kinds of third-party software. As of this year, I’m in the process of reverting that; I’ve added suitable functionality to pass the GNU mktime test otherwise. (At the same time, though, I’m switching the other MirBSD architecture’s time_t to 64 bit, so I’ll lack the 32-bit case in the future. Not a bad thing, though.)

For the record, we have…

        long tm_gmtoff; /* seconds offset from UTC to the east */
        char *tm_zone; /* abbreviation of timezone name */

… probably for hysteric raisins, but I’m all in favour of const-correctness for new APIs (and am retrofitting them over existing APIs where I can, such as writev(2) use of struct iovec).

Considering C’s desire to make operations on signed integers UB, I’d have preferred tm_gmtoff to be an int (whose minimum width is wider in POSIX anyway), but changing this now would probably be bad for many OSes.

@steffen no, “struct tm” does not work with the “Christian” calendars, it works with the proleptic Gregorian calendar (e.g. tm_year has “years since 1900”, not the Gregorian year number (in which a year 0 did not exist) or Julian years from before the switchover (which differed by location anyway)), and I think this is sensible. Any timekeeping application going that far into the past will need to do its own conversions anyway (taking the location of the query into account to determine when the switch between Julian and Gregorian occurred, for example).
(0005667)
kre (reporter)
2022-02-06 23:28

Re Note: 0005664

Yes, Anyone who got to define their struct tm late enough in time could
have made tm_year wider (not sure I would have picked time_t though - it
certainly guarantees that tm_year can represent any year that a time_t can
represent, but it makes tm dependent upon the time_t type, and since the
former ie very very difficult to ever change, it kind of locks you into a
specific time_t as well).

And Re Note: 0005660

Whether sub-second precision is useful or not all depends upon the
application, when used for things like syslog message logging (anything
similar) sub-second precision is almost a requirement. Further, it is
possible today, just ugly, one just uses strftime() with a format that
ends with "%S", then sprintf(".%u") as appropriate to get the sub-second
precisiion needed, and then if needed, another strftime() to get anything
that is needed after the time. It is just ugly.

Making that data available in a struct tm replacement would make all of this
much simpler, It was never there originally only because back when tm was
designed there was no way to access the time more accurately than seconds
(the time() sys call - gettimeofday() etc didn't yet exist).
(0005745)
steffen (reporter)
2022-03-14 00:31
edited on: 2022-03-15 15:55

Hello.

So i apologize for the long duration that it took before i was
able to look into the outcome of the standard's February 3, 2022
teleconference, as Don Cragun noted in #5657:

        [.] we need a more fully fleshed-out proposal including
        details of how the storage for tm_zone may be affected by
        later calls (including tzset()). This is likely to be
        different for localtime() and localtime_r(). There will
        also be changes needed to the strftime() page, for
        example, where it lists the tm members that affect each
        conversion.

I want to start with responding to Geoff Clare's note #5530, which
i also never seem to have done before.

        #5530
        On an implementation that lacks tm_gmtoff and tm_zone, if
        you change TZ after obtaining a struct tm from
        localtime(), the strftime() %z and %Z conversions use the
        values for the new TZ. Adding tm_gmtoff and tm_zone would
        change the behaviour such that %z and %Z use the values
        for the old TZ. This could break existing applications
        when they are recompiled and consequently start
        using the new ABI.

The standard already seems to be prepared to handle these concerns
by leaving the according behaviour undefined. On page 2047,
starting with line 65628 (in 2018 Edition of Issue 7) one can read
in the description for strftime():

        If a struct tm broken-down time structure is created by
        localtime( ) or localtime_r( ), or modified by mktime( ),
        and the value of TZ is subsequently modified, the results
        of the %Z and %z strftime( ) conversion specifiers are
        undefined, when strftime( ) is called with such
        a broken-down time structure.

This makes it clear that strftime() only produces valid results if
the value of $TZ equals the one that was in use once localtime()
or localtime_r() filled in a struct tm.
"Undefined" behaviour is a very strong wording already today.

In direct succession one can read for gmtime(_r)?():

        If a struct tm broken-down time structure is created or
        modified by gmtime( ) or gmtime_r( ), it is unspecified
        whether the result of the %Z and %z conversion specifiers
        shall refer to UTC or the current local timezone, when
        strftime( ) is called with such a broken-down time
        structure.

This also seems to neatlessly fit a standard extension that brings
.tm_gmtoff and .tm_zone, a change of $TZ in between gmtime() and
strftime() will either be honoured, or not, if the information is
at all accessed.

For time.h, struct tm, on page 425, append after the struct tm
member listing after line 14450,

        long tm_gmtoff Seconds east of UTC.
        const char *tm_zone Timezone abbreviation.

And after line 14452

        If the value of tm_zone is accessed after the value of TZ
        is modified, and the zone name was not "UTC", the
        behaviour is undefined.

For gmtime, on page 1113, lines 37692 ff., append after

        Upon successful completion, gmtime_r( ) shall return the
        address of the structure pointed to by the argument
        result.

the sentence

        The structures tm_zone member shall be set to the string
        "UTC", which shall have permanently valid storage scope.

For localtime, on page 1265, lines 42225 ff., append after

        Unlike localtime( ), the localtime_r( ) function is not
        required to set tzname. If localtime_r( ) sets tzname, it
        shall also set daylight and timezone. If localtime_r( )
        does not set tzname, it shall not set daylight and shall
        not set timezone.

the sentence

        If the struct tm member tm_zone is accessed after the
        value of TZ is subsequently modified, the behaviour is
        undefined.

For strftime, on page 2047, lines 65619 ff., change

        z Replaced by the offset from UTC in the ISO 8601: 2004
        standard format (+hhmm or −hhmm), or by no characters if
        no timezone is determinable. For example, "−0430" means
        4 hours 30 minutes behind UTC (west of Greenwich). If
        tm_isdst is zero, the standard time offset is used. If
        tm_isdst is greater than zero, the daylight savings time
        offset is used. If tm_isdst is negative, no characters are
        returned. [tm_isdst]

to

        [.] [tm_isdst, tm_gmtoff]

and lines 65624 ff. from

        Z Replaced by the timezone name or abbreviation, or by
        no bytes if no timezone information exists. [tm_isdst]

to

        [.] [tm_isdst, tm_zone]

For tzset, on page 2185, append after the lines 69918 ff.:

        The tzset( ) function shall set the external variable
        tzname as follows:
                tzname[0] = "std";
                tzname[1] = "dst";
        where std and dst are as described in XBD Chapter 8 (on
        page 173).

the sentence

        The TZ name "UTC" shall be made available in permanently
        valid storage scope.

Since the standard already makes clear, on the lines 69926 ff.,
that thread-safety cannot be expected:

        If a thread accesses tzname, daylight, or timezone
        directly while another thread is in a call to tzset( ), or
        to any function that is required or allowed to set
        timezone information as if by calling tzset( ), the
        behavior is undefined.

The data backing the timezone information can always be accessed
"atomically" from the user's point of view.
Explicitly adding words for the tm_zone fields of struct tm
a second time seems redundant. (It may be beneficial to add
wording to the daylight, timezone, tzname in time.h, page 427, and
refer to the documentation of tzset().)

(0005878)
geoffclare (manager)
2022-06-30 15:37

For time.h, struct tm, on page 425, append to the struct tm member listing after line 14450,
<tt>long tm_gmtoff</tt> Seconds east of UTC.
<tt>const char *tm_zone</tt> Timezone abbreviation.

And after line 14452
If the value of tm_zone is accessed after the value of TZ is subsequently modified, and the tm_zone value was not set by a call to gmtime() or gmtime_r(), the behaviour is undefined.


For gmtime, on page 1113, lines 37692 ff., append after
Upon successful completion, gmtime_r( ) shall return the address of the structure pointed to by the argument result.
the sentence
The structure's tm_zone member shall be set to a pointer to the string "UTC", which shall have static storage duration.

For localtime, on page 1265, lines 42225 ff., append after
Unlike localtime( ), the localtime_r( ) function is not required to set tzname. If localtime_r( ) sets tzname, it shall also set daylight and timezone. If localtime_r( ) does not set tzname, it shall not set daylight and shall not set timezone.
the sentence
If the struct tm member tm_zone is accessed after the value of TZ is subsequently modified, the behaviour is undefined.

For strftime, on page 2047, line 65623 (z conversion), change
[tm_isdst]
to
[tm_isdst, tm_gmtoff]

and line 65625 (Z conversion) from
[tm_isdst]
to
[tm_isdst, tm_zone]

- Issue History
Date Modified Username Field Change
2021-11-08 22:04 steffen New Issue
2021-11-08 22:04 steffen Name => steffen
2021-11-08 22:04 steffen Section => time.h
2021-11-08 22:04 steffen Page Number => 425
2021-11-08 22:04 steffen Line Number => 14451
2021-11-21 22:28 steffen Note Added: 0005529
2021-11-22 09:47 geoffclare Note Added: 0005530
2021-11-22 10:12 geoffclare Note Added: 0005531
2021-11-22 10:50 geoffclare Note Added: 0005532
2021-11-22 15:26 steffen Note Added: 0005533
2021-11-22 15:36 steffen Note Added: 0005534
2022-02-03 16:58 shware_systems Note Added: 0005656
2022-02-03 17:32 Don Cragun Note Added: 0005657
2022-02-03 18:41 kre Note Added: 0005658
2022-02-03 22:18 steffen Note Added: 0005660
2022-02-06 11:37 mirabilos Note Added: 0005664
2022-02-06 23:28 kre Note Added: 0005667
2022-03-14 00:31 steffen Note Added: 0005745
2022-03-15 15:55 steffen Note Edited: 0005745
2022-06-30 15:37 geoffclare Note Added: 0005878
2022-06-30 15:38 geoffclare Interp Status => ---
2022-06-30 15:38 geoffclare Final Accepted Text => Note: 0005878
2022-06-30 15:38 geoffclare Status New => Resolved
2022-06-30 15:38 geoffclare Resolution Open => Accepted As Marked
2022-06-30 15:38 geoffclare Tag Attached: issue8


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker