]>
Commit | Line | Data |
---|---|---|
e507cc56 | 1 | /* Test program from Paul Eggert and Tony Leneis. */ |
302cadd3 | 2 | |
f1034472 FW |
3 | #include <array_length.h> |
4 | #include <errno.h> | |
302cadd3 | 5 | #include <limits.h> |
f1034472 | 6 | #include <stdio.h> |
e507cc56 | 7 | #include <stdlib.h> |
f1034472 FW |
8 | #include <support/check.h> |
9 | #include <time.h> | |
e507cc56 RM |
10 | #include <unistd.h> |
11 | ||
82c9a4f8 L |
12 | /* True if the arithmetic type T is signed. */ |
13 | #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) | |
14 | ||
15 | /* The maximum and minimum values for the integer type T. These | |
16 | macros have undefined behavior if T is signed and has padding bits. | |
17 | If this is a problem for you, please let us know how to fix it for | |
18 | your host. */ | |
19 | #define TYPE_MINIMUM(t) \ | |
20 | ((t) (! TYPE_SIGNED (t) \ | |
21 | ? (t) 0 \ | |
22 | : ~ TYPE_MAXIMUM (t))) | |
23 | #define TYPE_MAXIMUM(t) \ | |
24 | ((t) (! TYPE_SIGNED (t) \ | |
25 | ? (t) -1 \ | |
26 | : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1))) | |
27 | ||
28 | #ifndef TIME_T_MIN | |
29 | # define TIME_T_MIN TYPE_MINIMUM (time_t) | |
30 | #endif | |
31 | #ifndef TIME_T_MAX | |
32 | # define TIME_T_MAX TYPE_MAXIMUM (time_t) | |
33 | #endif | |
e507cc56 RM |
34 | |
35 | /* Values we'll use to set the TZ environment variable. */ | |
36 | static const char *tz_strings[] = | |
37 | { | |
38 | (const char *) 0, "GMT0", "JST-9", | |
39 | "EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00" | |
40 | }; | |
f1034472 FW |
41 | |
42 | static void | |
43 | set_timezone (const char *tz) | |
44 | { | |
45 | printf ("info: setting TZ=%s\n", tz); | |
46 | if (setenv ("TZ", tz, 1) != 0) | |
47 | FAIL_EXIT1 ("setenv: %m"); | |
48 | } | |
e507cc56 RM |
49 | |
50 | /* Fail if mktime fails to convert a date in the spring-forward gap. | |
51 | Based on a problem report from Andreas Jaeger. */ | |
52 | static void | |
53 | spring_forward_gap (void) | |
54 | { | |
55 | /* glibc (up to about 1998-10-07) failed this test. */ | |
56 | struct tm tm; | |
57 | ||
58 | /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" | |
59 | instead of "TZ=America/Vancouver" in order to detect the bug even | |
60 | on systems that don't support the Olson extension, or don't have the | |
61 | full zoneinfo tables installed. */ | |
f1034472 | 62 | set_timezone ("PST8PDT,M4.1.0,M10.5.0"); |
e507cc56 RM |
63 | |
64 | tm.tm_year = 98; | |
65 | tm.tm_mon = 3; | |
66 | tm.tm_mday = 5; | |
67 | tm.tm_hour = 2; | |
68 | tm.tm_min = 0; | |
69 | tm.tm_sec = 0; | |
70 | tm.tm_isdst = -1; | |
71 | if (mktime (&tm) == (time_t)-1) | |
f1034472 | 72 | FAIL_EXIT1 ("mktime: %m"); |
e507cc56 RM |
73 | } |
74 | ||
75 | static void | |
76 | mktime_test1 (time_t now) | |
77 | { | |
78 | struct tm *lt = localtime (&now); | |
f1034472 FW |
79 | if (lt == NULL) |
80 | { | |
81 | /* For extreme input values, it is expected that localtime fails | |
82 | with EOVERFLOW. */ | |
83 | printf ("info: localtime (%lld) failed: %m\n", (long long int) now); | |
84 | TEST_COMPARE (errno, EOVERFLOW); | |
85 | return; | |
86 | } | |
87 | TEST_COMPARE (mktime (lt), now); | |
e507cc56 RM |
88 | } |
89 | ||
90 | static void | |
91 | mktime_test (time_t now) | |
92 | { | |
93 | mktime_test1 (now); | |
82c9a4f8 L |
94 | mktime_test1 ((time_t) (TIME_T_MAX - now)); |
95 | mktime_test1 ((time_t) (TIME_T_MIN + now)); | |
e507cc56 RM |
96 | } |
97 | ||
98 | static void | |
99 | irix_6_4_bug (void) | |
100 | { | |
101 | /* Based on code from Ariel Faigon. */ | |
102 | struct tm tm; | |
103 | tm.tm_year = 96; | |
104 | tm.tm_mon = 3; | |
105 | tm.tm_mday = 0; | |
106 | tm.tm_hour = 0; | |
107 | tm.tm_min = 0; | |
108 | tm.tm_sec = 0; | |
109 | tm.tm_isdst = -1; | |
110 | mktime (&tm); | |
f1034472 FW |
111 | TEST_COMPARE (tm.tm_mon, 2); |
112 | TEST_COMPARE (tm.tm_mday, 31); | |
e507cc56 RM |
113 | } |
114 | ||
115 | static void | |
116 | bigtime_test (int j) | |
117 | { | |
118 | struct tm tm; | |
119 | time_t now; | |
120 | tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j; | |
469dcb0d | 121 | tm.tm_isdst = -1; |
e507cc56 RM |
122 | now = mktime (&tm); |
123 | if (now != (time_t) -1) | |
124 | { | |
125 | struct tm *lt = localtime (&now); | |
f1034472 FW |
126 | TEST_COMPARE (lt->tm_year, tm.tm_year); |
127 | TEST_COMPARE (lt->tm_mon, tm.tm_mon); | |
128 | TEST_COMPARE (lt->tm_mday, tm.tm_mday); | |
129 | TEST_COMPARE (lt->tm_hour, tm.tm_hour); | |
130 | TEST_COMPARE (lt->tm_min, tm.tm_min); | |
131 | TEST_COMPARE (lt->tm_sec, tm.tm_sec); | |
132 | TEST_COMPARE (lt->tm_yday, tm.tm_yday); | |
133 | TEST_COMPARE (lt->tm_wday, tm.tm_wday); | |
134 | TEST_COMPARE (lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst, | |
135 | tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst); | |
e507cc56 RM |
136 | } |
137 | } | |
138 | ||
139 | static int | |
140 | do_test (void) | |
141 | { | |
142 | time_t t, delta; | |
965cba04 UD |
143 | int i; |
144 | unsigned int j; | |
e507cc56 | 145 | |
f1034472 | 146 | set_timezone ("America/Sao_Paulo"); |
e507cc56 | 147 | |
82c9a4f8 | 148 | delta = TIME_T_MAX / 997; /* a suitable prime number */ |
f1034472 | 149 | for (i = 0; i < array_length (tz_strings); i++) |
e507cc56 | 150 | { |
f1034472 FW |
151 | if (tz_strings[i] != NULL) |
152 | set_timezone (tz_strings[i]); | |
e507cc56 | 153 | |
82c9a4f8 | 154 | for (t = 0; t <= TIME_T_MAX - delta; t += delta) |
e507cc56 RM |
155 | mktime_test (t); |
156 | mktime_test ((time_t) 1); | |
157 | mktime_test ((time_t) (60 * 60)); | |
158 | mktime_test ((time_t) (60 * 60 * 24)); | |
159 | ||
965cba04 | 160 | for (j = 1; j <= INT_MAX; j *= 2) |
e507cc56 RM |
161 | bigtime_test (j); |
162 | bigtime_test (j - 1); | |
163 | } | |
164 | irix_6_4_bug (); | |
165 | spring_forward_gap (); | |
166 | return 0; | |
167 | } | |
168 | ||
f1034472 | 169 | #include <support/test-driver.c> |