public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* mktime result may depend on previous calls
@ 2023-01-18 15:39 Max Nikulin
  2023-01-18 22:12 ` Paul Eggert
  0 siblings, 1 reply; 6+ messages in thread
From: Max Nikulin @ 2023-01-18 15:39 UTC (permalink / raw)
  To: libc-alpha

Hi,

I have noticed that the mktime function may return different values for 
the same argument. More precisely, result may depend on previous calls.

I am aware that POSIX underspecifies behavior of mktime in the case of 
backward jump of local time (and that is impossible to disambiguate if 
the value before or after time transition should be used when DST is not 
changed), but I am still surprised. Is it intended that hidden state 
affects returned value?

The following output is obtained for glibc-2.31. I am sorry for the 
noise if it has changed in the development version.

The following time transition keeps isdst=0:

zdump -v Africa/Juba | grep 2021
Africa/Juba  Sun Jan 31 20:59:59 2021 UT = Sun Jan 31 23:59:59 2021 EAT 
isdst=0 gmtoff=10800
Africa/Juba  Sun Jan 31 21:00:00 2021 UT = Sun Jan 31 23:00:00 2021 CAT 
isdst=0 gmtoff=7200

Notice that same input on lines 4 and 10 causes different conversion 
result 5-6 and 11-12

      1	input:          +121!00-31 22:00:00 dst:-1 w:0  j:0
      2	     1612119600 +121!00-31 22:00:00 dst:0  w:0  j:30
      3	strptime:       2021-01-31 22:00:00 +0300 EAT

      4	input:          +121!00-31 23:30:00 dst:-1 w:0  j:0
      5	     1612125000 +121!00-31 23:30:00 dst:0  w:0  j:30
      6	strptime:       2021-01-31 23:30:00 +0300 EAT

      7	input:          +121!01-01 01:00:00 dst:-1 w:0  j:0
      8	     1612134000 +121!01-01 01:00:00 dst:0  w:1  j:31
      9	strptime:       2021-02-01 01:00:00 +0200 CAT

     10	input:          +121!00-31 23:30:00 dst:-1 w:0  j:0
     11	     1612128600 +121!00-31 23:30:00 dst:0  w:0  j:30
     12	strptime:       2021-01-31 23:30:00 +0200 CAT

I use the following script and C code to test mktime:

TZ=Africa/Juba ./mktime-state <<EOF | nl
2021  1 31 22  0  0 -1
2021  1 31 23 30  0 -1
2021  2  1  1  0  0 -1
2021  1 31 23 30  0 -1
EOF

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>

void print_tm(const struct tm *bt) {
	printf(
		"%+04d!%02d-%02d %02d:%02d:%02d dst:%-2d w:%-2d j:%-3d",
		bt->tm_year, bt->tm_mon, bt->tm_mday,
		bt->tm_hour, bt->tm_min, bt->tm_sec,
		bt->tm_isdst, bt->tm_wday, bt->tm_yday);
}

int main() {
	struct tm bt;
	char buf[64];
	while (1) {
		memset(&bt, 0, sizeof(bt));
		bt.tm_isdst = -1;
		if (7 != scanf(
			"%d%d%d%d%d%d%d",
			&bt.tm_year, &bt.tm_mon, &bt.tm_mday,
			&bt.tm_hour, &bt.tm_min, &bt.tm_sec, &bt.tm_isdst)
		) {
			break;
		}
		bt.tm_year -= 1900;
		bt.tm_mon -= 1;
		printf("%-15s ", "input:");
		print_tm(&bt);
		putchar('\n');
		errno = 0;
		time_t ts = mktime(&bt);
		if (ts == -1 && errno != 0) {
			printf("error: %s", strerror(errno));
			continue;
		}
		printf("%15zd ", ts);
		print_tm(&bt);
		putchar('\n');
		strftime(buf, sizeof(buf) - 1, "%F %T %z %Z", &bt);
		printf("%-15s %s\n\n", "strptime:", buf);
	}
	return 0;
}

At first I experimented with another cases, a usual DST transition and

Europe/Kyiv  Sat Jun 30 21:59:59 1990 UT = Sun Jul  1 01:59:59 1990 MSD 
isdst=1 gmtoff=14400
Europe/Kyiv  Sat Jun 30 22:00:00 1990 UT = Sun Jul  1 01:00:00 1990 EEST 
isdst=1 gmtoff=10800

At some moment I was sure that mktime return value depends on tm_isdst 
of its argument. Later I have realized that I got different results due 
to other calls.

A more funny result is hysteresis loop when time is increased and then 
decreased in steps around time transition moment:
https://list.orgmode.org/tq6lg6$9m2$1@ciao.gmane.io/2-mktime-hyst.png


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-01-20  9:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-18 15:39 mktime result may depend on previous calls Max Nikulin
2023-01-18 22:12 ` Paul Eggert
2023-01-19  3:00   ` Max Nikulin
2023-01-19  4:34     ` Paul Eggert
2023-01-19  7:10       ` Max Nikulin
2023-01-20  9:21         ` Paul Eggert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).