00001
00002
00003
00004
00005
00006 #include <ctype.h>
00007 #include <time.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010
00011 #if defined(__BSD4_2)
00012
00013 struct timeval {
00014 long tv_sec;
00015 long tv_usec;
00016 };
00017
00018 struct timezone {
00019 int tz_minuteswest;
00020 int tz_dsttime;
00021 };
00022
00023 int _gettimeofday(struct timeval *tp, struct timezone *tzp);
00024
00025 #elif !defined(_POSIX_SOURCE) && !defined(__USG)
00026 #if !defined(_MINIX)
00027 struct timeb {
00028 long time;
00029 unsigned short millitm;
00030 short timezone;
00031 short dstflag;
00032 };
00033 void _ftime(struct timeb *bp);
00034 #endif
00035 #endif
00036
00037 #include "loc_time.h"
00038
00039 #define RULE_LEN 120
00040 #define TZ_LEN 10
00041
00042
00043
00044
00045
00046 static char ntstr[TZ_LEN + 1] = "GMT";
00047 static char dststr[TZ_LEN + 1] = "GDT";
00048
00049 long _timezone = 0;
00050 long _dst_off = 60 * 60;
00051 int _daylight = 0;
00052 char *_tzname[2] = {ntstr, dststr};
00053
00054 #if defined(__USG) || defined(_POSIX_SOURCE)
00055 char *tzname[2] = {ntstr, dststr};
00056
00057 #if defined(__USG)
00058 long timezone = 0;
00059 int daylight = 0;
00060 #endif
00061 #endif
00062
00063 static struct dsttype {
00064 char ds_type;
00065 int ds_date[3];
00066 long ds_sec;
00067 } dststart = { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
00068 , dstend = { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
00069
00070 const char *_days[] = {
00071 "Sunday", "Monday", "Tuesday", "Wednesday",
00072 "Thursday", "Friday", "Saturday"
00073 };
00074
00075 const char *_months[] = {
00076 "January", "February", "March",
00077 "April", "May", "June",
00078 "July", "August", "September",
00079 "October", "November", "December"
00080 };
00081
00082 const int _ytab[2][12] = {
00083 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00084 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00085 };
00086
00087 static const char *
00088 parseZoneName(register char *buf, register const char *p)
00089 {
00090 register int n = 0;
00091
00092 if (*p == ':') return NULL;
00093 while (*p && !isdigit(*p) && *p != ',' && *p != '-' && *p != '+') {
00094 if (n < TZ_LEN)
00095 *buf++ = *p;
00096 p++;
00097 n++;
00098 }
00099 if (n < 3) return NULL;
00100 *buf = '\0';
00101 return p;
00102 }
00103
00104 static const char *
00105 parseTime(register long *tm, const char *p, register struct dsttype *dst)
00106 {
00107 register int n = 0;
00108 register const char *q = p;
00109 char ds_type = (dst ? dst->ds_type : '\0');
00110
00111 if (dst) dst->ds_type = 'U';
00112
00113 *tm = 0;
00114 while(*p >= '0' && *p <= '9') {
00115 n = 10 * n + (*p++ - '0');
00116 }
00117 if (q == p) return NULL;
00118 if (n < 0 || n >= 24) return NULL;
00119 *tm = n * 60 * 60;
00120 if (*p == ':') {
00121 p++;
00122 n = 0;
00123 while(*p >= '0' && *p <= '9') {
00124 n = 10 * n + (*p++ - '0');
00125 }
00126 if (q == p) return NULL;
00127 if (n < 0 || n >= 60) return NULL;
00128 *tm += n * 60;
00129 if (*p == ':') {
00130 p++;
00131 n = 0;
00132 while(*p >= '0' && *p <= '9') {
00133 n = 10 * n + (*p++ - '0');
00134 }
00135 if (q == p) return NULL;
00136 if (n < 0 || n >= 60) return NULL;
00137 *tm += n;
00138 }
00139 }
00140 if (dst) {
00141 dst->ds_type = ds_type;
00142 dst->ds_sec = *tm;
00143 }
00144 return p;
00145 }
00146
00147 static const char *
00148 parseDate(register char *buf, register const char *p, struct dsttype *dstinfo)
00149 {
00150 register const char *q;
00151 register int n = 0;
00152 int cnt = 0;
00153 const int bnds[3][2] = { { 1, 12 },
00154 { 1, 5 },
00155 { 0, 6}
00156 };
00157 char ds_type;
00158
00159 if (*p != 'M') {
00160 if (*p == 'J') {
00161 *buf++ = *p++;
00162 ds_type = 'J';
00163 }
00164 else ds_type = 'Z';
00165 q = p;
00166 while(*p >= '0' && *p <= '9') {
00167 n = 10 * n + (*p - '0');
00168 *buf++ = *p++;
00169 }
00170 if (q == p) return NULL;
00171 if (n < (ds_type == 'J') || n > 365) return NULL;
00172 dstinfo->ds_type = ds_type;
00173 dstinfo->ds_date[0] = n;
00174 return p;
00175 }
00176 ds_type = 'M';
00177 do {
00178 *buf++ = *p++;
00179 q = p;
00180 n = 0;
00181 while(*p >= '0' && *p <= '9') {
00182 n = 10 * n + (*p - '0');
00183 *buf++ = *p++;
00184 }
00185 if (q == p) return NULL;
00186 if (n < bnds[cnt][0] || n > bnds[cnt][1]) return NULL;
00187 dstinfo->ds_date[cnt] = n;
00188 cnt++;
00189 } while (cnt < 3 && *p == '.');
00190 if (cnt != 3) return NULL;
00191 *buf = '\0';
00192 dstinfo->ds_type = ds_type;
00193 return p;
00194 }
00195
00196 static const char *
00197 parseRule(register char *buf, register const char *p)
00198 {
00199 long time;
00200 register const char *q;
00201
00202 if (!(p = parseDate(buf, p, &dststart))) return NULL;
00203 buf += strlen(buf);
00204 if (*p == '/') {
00205 q = ++p;
00206 if (!(p = parseTime(&time, p, &dststart))) return NULL;
00207 while( p != q) *buf++ = *q++;
00208 }
00209 if (*p != ',') return NULL;
00210 p++;
00211 if (!(p = parseDate(buf, p, &dstend))) return NULL;
00212 buf += strlen(buf);
00213 if (*p == '/') {
00214 q = ++p;
00215 if (!(p = parseTime(&time, p, &dstend))) return NULL;
00216 while(*buf++ = *q++);
00217 }
00218 if (*p) return NULL;
00219 return p;
00220 }
00221
00222
00223
00224
00225
00226 static void
00227 parseTZ(const char *p)
00228 {
00229 long tz, dst = 60 * 60, sign = 1;
00230 static char lastTZ[2 * RULE_LEN];
00231 static char buffer[RULE_LEN];
00232
00233 if (!p) return;
00234
00235 if (*p == ':') {
00236
00237
00238
00239
00240
00241 return;
00242 }
00243
00244 if (!strcmp(lastTZ, p)) return;
00245
00246 *_tzname[0] = '\0';
00247 *_tzname[1] = '\0';
00248 dststart.ds_type = 'U';
00249 dststart.ds_sec = 2 * 60 * 60;
00250 dstend.ds_type = 'U';
00251 dstend.ds_sec = 2 * 60 * 60;
00252
00253 if (strlen(p) > 2 * RULE_LEN) return;
00254 strcpy(lastTZ, p);
00255
00256 if (!(p = parseZoneName(buffer, p))) return;
00257
00258 if (*p == '-') {
00259 sign = -1;
00260 p++;
00261 } else if (*p == '+') p++;
00262
00263 if (!(p = parseTime(&tz, p, NULL))) return;
00264 tz *= sign;
00265 _timezone = tz;
00266 strncpy(_tzname[0], buffer, TZ_LEN);
00267
00268 if (!(_daylight = (*p != '\0'))) return;
00269
00270 buffer[0] = '\0';
00271 if (!(p = parseZoneName(buffer, p))) return;
00272 strncpy(_tzname[1], buffer, TZ_LEN);
00273
00274 buffer[0] = '\0';
00275 if (*p && (*p != ','))
00276 if (!(p = parseTime(&dst, p, NULL))) return;
00277 _dst_off = dst;
00278 if (*p) {
00279 if (*p != ',') return;
00280 p++;
00281 if (strlen(p) > RULE_LEN) return;
00282 if (!(p = parseRule(buffer, p))) return;
00283 }
00284 }
00285
00286 void
00287 _tzset(void)
00288 {
00289 #if defined(__BSD4_2)
00290
00291 struct timeval tv;
00292 struct timezone tz;
00293
00294 _gettimeofday(&tv, &tz);
00295 _daylight = tz.tz_dsttime;
00296 _timezone = tz.tz_minuteswest * 60L;
00297
00298 #elif !defined(_POSIX_SOURCE) && !defined(__USG)
00299
00300 #if !defined(_MINIX)
00301 struct timeb time;
00302
00303 _ftime(&time);
00304 _timezone = time.timezone * 60L;
00305 _daylight = time.dstflag;
00306 #endif
00307
00308 #endif
00309
00310 parseTZ(getenv("TZ"));
00311
00312 #if defined(__USG) || defined(_POSIX_SOURCE)
00313 tzname[0] = _tzname[0];
00314 tzname[1] = _tzname[1];
00315 #if defined(__USG)
00316 timezone = _timezone;
00317 daylight = _daylight;
00318 #endif
00319 #endif
00320 }
00321
00322 static int
00323 last_sunday(register int day, register struct tm *timep)
00324 {
00325 int first = FIRSTSUNDAY(timep);
00326
00327 if (day >= 58 && LEAPYEAR(YEAR0 + timep->tm_year)) day++;
00328 if (day < first) return first;
00329 return day - (day - first) % 7;
00330 }
00331
00332 static int
00333 date_of(register struct dsttype *dst, struct tm *timep)
00334 {
00335 int leap = LEAPYEAR(YEAR0 + timep->tm_year);
00336 int firstday, tmpday;
00337 register int day, month;
00338
00339 if (dst->ds_type != 'M') {
00340 return dst->ds_date[0] -
00341 (dst->ds_type == 'J'
00342 && leap
00343 && dst->ds_date[0] < 58);
00344 }
00345 day = 0;
00346 month = 1;
00347 while (month < dst->ds_date[0]) {
00348 day += _ytab[leap][month - 1];
00349 month++;
00350 }
00351 firstday = (day + FIRSTDAYOF(timep)) % 7;
00352 tmpday = day;
00353 day += (dst->ds_date[2] - firstday + 7) % 7
00354 + 7 * (dst->ds_date[1] - 1);
00355 if (day >= tmpday + _ytab[leap][month-1]) day -= 7;
00356 return day;
00357 }
00358
00359
00360
00361
00362
00363 unsigned
00364 _dstget(register struct tm *timep)
00365 {
00366 int begindst, enddst;
00367 register struct dsttype *dsts = &dststart, *dste = &dstend;
00368 int do_dst = 0;
00369
00370 if (_daylight == -1)
00371 _tzset();
00372
00373 timep->tm_isdst = _daylight;
00374 if (!_daylight) return 0;
00375
00376 if (dsts->ds_type != 'U')
00377 begindst = date_of(dsts, timep);
00378 else begindst = last_sunday(89, timep);
00379 if (dste->ds_type != 'U')
00380 enddst = date_of(dste, timep);
00381 else enddst = last_sunday(272, timep);
00382
00383
00384 if (begindst < enddst) {
00385 if (timep->tm_yday > begindst && timep->tm_yday < enddst)
00386 do_dst = 1;
00387 } else {
00388 if (timep->tm_yday > begindst || timep->tm_yday < enddst)
00389 do_dst = 1;
00390 }
00391
00392 if (!do_dst
00393 && (timep->tm_yday == begindst || timep->tm_yday == enddst)) {
00394 long dsttranssec;
00395 long cursec;
00396
00397 if (timep->tm_yday == begindst)
00398 dsttranssec = dsts->ds_sec;
00399 else dsttranssec = dste->ds_sec;
00400 cursec = ((timep->tm_hour * 60) + timep->tm_min) * 60L
00401 + timep->tm_sec;
00402
00403 if ((timep->tm_yday == begindst && cursec >= dsttranssec)
00404 || (timep->tm_yday == enddst && cursec < dsttranssec))
00405 do_dst = 1;
00406 }
00407 if (do_dst) return _dst_off;
00408 timep->tm_isdst = 0;
00409 return 0;
00410 }