2 * misc - data and miscellaneous routines
14 long tv_sec
; /* seconds */
15 long tv_usec
; /* and microseconds */
19 int tz_minuteswest
; /* minutes west of Greenwich */
20 int tz_dsttime
; /* type of dst correction */
23 int _gettimeofday(struct timeval
*tp
, struct timezone
*tzp
);
25 #elif !defined(_POSIX_SOURCE) && !defined(__USG)
26 #if !defined(_MINIX) /* MINIX has no ftime() */
29 unsigned short millitm
;
33 void _ftime(struct timeb
*bp
);
42 /* Make sure that the strings do not end up in ROM.
43 * These strings probably contain the wrong value, and we cannot obtain the
44 * right value from the system. TZ is the only help.
46 static char ntstr
[TZ_LEN
+ 1] = "GMT"; /* string for normal time */
47 static char dststr
[TZ_LEN
+ 1] = "GDT"; /* string for daylight saving */
50 long _dst_off
= 60 * 60;
52 char *_tzname
[2] = {ntstr
, dststr
};
54 #if defined(__USG) || defined(_POSIX_SOURCE)
55 char *tzname
[2] = {ntstr
, dststr
};
63 static struct dsttype
{
64 char ds_type
; /* Unknown, Julian, Zero-based or M */
65 int ds_date
[3]; /* months, weeks, days */
66 long ds_sec
; /* usually 02:00:00 */
67 } dststart
= { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
68 , dstend
= { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
70 const char *_days
[] = {
71 "Sunday", "Monday", "Tuesday", "Wednesday",
72 "Thursday", "Friday", "Saturday"
75 const char *_months
[] = {
76 "January", "February", "March",
77 "April", "May", "June",
78 "July", "August", "September",
79 "October", "November", "December"
82 const int _ytab
[2][12] = {
83 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
84 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
88 parseZoneName(register char *buf
, register const char *p
)
92 if (*p
== ':') return NULL
;
93 while (*p
&& !isdigit(*p
) && *p
!= ',' && *p
!= '-' && *p
!= '+') {
99 if (n
< 3) return NULL
; /* error */
105 parseTime(register long *tm
, const char *p
, register struct dsttype
*dst
)
108 register const char *q
= p
;
109 char ds_type
= (dst
? dst
->ds_type
: '\0');
111 if (dst
) dst
->ds_type
= 'U';
114 while(*p
>= '0' && *p
<= '9') {
115 n
= 10 * n
+ (*p
++ - '0');
117 if (q
== p
) return NULL
; /* "The hour shall be required" */
118 if (n
< 0 || n
>= 24) return NULL
;
123 while(*p
>= '0' && *p
<= '9') {
124 n
= 10 * n
+ (*p
++ - '0');
126 if (q
== p
) return NULL
; /* format error */
127 if (n
< 0 || n
>= 60) return NULL
;
132 while(*p
>= '0' && *p
<= '9') {
133 n
= 10 * n
+ (*p
++ - '0');
135 if (q
== p
) return NULL
; /* format error */
136 if (n
< 0 || n
>= 60) return NULL
;
141 dst
->ds_type
= ds_type
;
148 parseDate(register char *buf
, register const char *p
, struct dsttype
*dstinfo
)
150 register const char *q
;
153 const int bnds
[3][2] = { { 1, 12 },
166 while(*p
>= '0' && *p
<= '9') {
167 n
= 10 * n
+ (*p
- '0');
170 if (q
== p
) return NULL
; /* format error */
171 if (n
< (ds_type
== 'J') || n
> 365) return NULL
;
172 dstinfo
->ds_type
= ds_type
;
173 dstinfo
->ds_date
[0] = n
;
181 while(*p
>= '0' && *p
<= '9') {
182 n
= 10 * n
+ (*p
- '0');
185 if (q
== p
) return NULL
; /* format error */
186 if (n
< bnds
[cnt
][0] || n
> bnds
[cnt
][1]) return NULL
;
187 dstinfo
->ds_date
[cnt
] = n
;
189 } while (cnt
< 3 && *p
== '.');
190 if (cnt
!= 3) return NULL
;
192 dstinfo
->ds_type
= ds_type
;
197 parseRule(register char *buf
, register const char *p
)
200 register const char *q
;
202 if (!(p
= parseDate(buf
, p
, &dststart
))) return NULL
;
206 if (!(p
= parseTime(&time
, p
, &dststart
))) return NULL
;
207 while( p
!= q
) *buf
++ = *q
++;
209 if (*p
!= ',') return NULL
;
211 if (!(p
= parseDate(buf
, p
, &dstend
))) return NULL
;
215 if (!(p
= parseTime(&time
, p
, &dstend
))) return NULL
;
216 while(*buf
++ = *q
++);
222 /* The following routine parses timezone information in POSIX-format. For
223 * the requirements, see IEEE Std 1003.1-1988 section 8.1.1.
224 * The function returns as soon as it spots an error.
227 parseTZ(const char *p
)
229 long tz
, dst
= 60 * 60, sign
= 1;
230 static char lastTZ
[2 * RULE_LEN
];
231 static char buffer
[RULE_LEN
];
237 * According to POSIX, this is implementation defined.
238 * Since it depends on the particular operating system, we
244 if (!strcmp(lastTZ
, p
)) return; /* nothing changed */
248 dststart
.ds_type
= 'U';
249 dststart
.ds_sec
= 2 * 60 * 60;
250 dstend
.ds_type
= 'U';
251 dstend
.ds_sec
= 2 * 60 * 60;
253 if (strlen(p
) > 2 * RULE_LEN
) return;
256 if (!(p
= parseZoneName(buffer
, p
))) return;
261 } else if (*p
== '+') p
++;
263 if (!(p
= parseTime(&tz
, p
, NULL
))) return;
266 strncpy(_tzname
[0], buffer
, TZ_LEN
);
268 if (!(_daylight
= (*p
!= '\0'))) return;
271 if (!(p
= parseZoneName(buffer
, p
))) return;
272 strncpy(_tzname
[1], buffer
, TZ_LEN
);
275 if (*p
&& (*p
!= ','))
276 if (!(p
= parseTime(&dst
, p
, NULL
))) return;
277 _dst_off
= dst
; /* dst was initialized to 1 hour */
279 if (*p
!= ',') return;
281 if (strlen(p
) > RULE_LEN
) return;
282 if (!(p
= parseRule(buffer
, p
))) return;
289 #if defined(__BSD4_2)
294 _gettimeofday(&tv
, &tz
);
295 _daylight
= tz
.tz_dsttime
;
296 _timezone
= tz
.tz_minuteswest
* 60L;
298 #elif !defined(_POSIX_SOURCE) && !defined(__USG)
300 #if !defined(_MINIX) /* MINIX has no ftime() */
304 _timezone
= time
.timezone
* 60L;
305 _daylight
= time
.dstflag
;
308 #endif /* !_POSIX_SOURCE && !__USG */
310 parseTZ(getenv("TZ")); /* should go inside #if */
312 #if defined(__USG) || defined(_POSIX_SOURCE)
313 tzname
[0] = _tzname
[0];
314 tzname
[1] = _tzname
[1];
316 timezone
= _timezone
;
317 daylight
= _daylight
;
319 #endif /* __USG || _POSIX_SOURCE */
323 last_sunday(register int day
, register struct tm
*timep
)
325 int first
= FIRSTSUNDAY(timep
);
327 if (day
>= 58 && LEAPYEAR(YEAR0
+ timep
->tm_year
)) day
++;
328 if (day
< first
) return first
;
329 return day
- (day
- first
) % 7;
333 date_of(register struct dsttype
*dst
, struct tm
*timep
)
335 int leap
= LEAPYEAR(YEAR0
+ timep
->tm_year
);
336 int firstday
, tmpday
;
337 register int day
, month
;
339 if (dst
->ds_type
!= 'M') {
340 return dst
->ds_date
[0] -
343 && dst
->ds_date
[0] < 58);
347 while (month
< dst
->ds_date
[0]) {
348 day
+= _ytab
[leap
][month
- 1];
351 firstday
= (day
+ FIRSTDAYOF(timep
)) % 7;
353 day
+= (dst
->ds_date
[2] - firstday
+ 7) % 7
354 + 7 * (dst
->ds_date
[1] - 1);
355 if (day
>= tmpday
+ _ytab
[leap
][month
-1]) day
-= 7;
360 * The default dst transitions are those for Western Europe (except Great
364 _dstget(register struct tm
*timep
)
366 int begindst
, enddst
;
367 register struct dsttype
*dsts
= &dststart
, *dste
= &dstend
;
373 timep
->tm_isdst
= _daylight
;
374 if (!_daylight
) return 0;
376 if (dsts
->ds_type
!= 'U')
377 begindst
= date_of(dsts
, timep
);
378 else begindst
= last_sunday(89, timep
); /* last Sun before Apr */
379 if (dste
->ds_type
!= 'U')
380 enddst
= date_of(dste
, timep
);
381 else enddst
= last_sunday(272, timep
); /* last Sun in Sep */
383 /* assume begindst != enddst (otherwise it would be no use) */
384 if (begindst
< enddst
) { /* northern hemisphere */
385 if (timep
->tm_yday
> begindst
&& timep
->tm_yday
< enddst
)
387 } else { /* southern hemisphere */
388 if (timep
->tm_yday
> begindst
|| timep
->tm_yday
< enddst
)
393 && (timep
->tm_yday
== begindst
|| timep
->tm_yday
== enddst
)) {
394 long dsttranssec
; /* transition when day is this old */
397 if (timep
->tm_yday
== begindst
)
398 dsttranssec
= dsts
->ds_sec
;
399 else dsttranssec
= dste
->ds_sec
;
400 cursec
= ((timep
->tm_hour
* 60) + timep
->tm_min
) * 60L
403 if ((timep
->tm_yday
== begindst
&& cursec
>= dsttranssec
)
404 || (timep
->tm_yday
== enddst
&& cursec
< dsttranssec
))
407 if (do_dst
) return _dst_off
;