|
|
1.1 ! root 1: /* ! 2: * libc/gen/ctime.c ! 3: * Convert time to ASCII representation. ! 4: * ! 5: * Pseudo system-5, employs TIMEZONE environment for gmt offset, ! 6: * timezone abbreviations, and daylight savings time information. ! 7: * TIMEZONE=SSS:mmm:DDD:n.d.m:n.d.m:h:m ! 8: * SSS - Standard timezone abbreviation up to 31 characters long ! 9: * mmm - minutes west of GMT ! 10: * DDD - Daylight timezone abbreviation also 31 characters ! 11: * n.d.m - n'th occurrence of d'th day of week in m'th month of ! 12: * start and end of daylight savings time. Negative n indicates ! 13: * counting backwards from end of month. Zero n indicates absolute date, ! 14: * d'th day of m'th month. Days and months from 1 to n. ! 15: * h - Hour of change from standard to daylight. ! 16: * m - Minutes of adjustment at change. ! 17: * Example - Central standard in current US conventions: ! 18: * TIMEZONE=CST:3600:CDT:-1.1.4:-1.1.10:2:60 ! 19: * Only the first two fields are required. ! 20: * If no daylight timezone is specified, then no daylight conversion is done. ! 21: * If no dates for daylight are given, they default to 83-05-10 US standard. ! 22: * If no hour of daylight time change is specified, it defaults to 2AM. ! 23: * If no minutes of adjustment is specified, it defaults to 60. ! 24: * These defaults can be changed by overwriting tzdstdef[]. ! 25: */ ! 26: ! 27: ! 28: #include <time.h> ! 29: #if 0 ! 30: /* Required for ftime(), now conditionalized out, cf. comments below. */ ! 31: #include <sys/timeb.h> ! 32: #endif ! 33: ! 34: #define FEB 1 ! 35: #define NWDAY 7 /* Number of weekdays */ ! 36: #define NMON 12 /* Number of months */ ! 37: #define todigit(c) ((c)+'0') ! 38: #define NTZNAME 31 /* max time zone name size */ ! 39: ! 40: /* Static data. */ ! 41: static char daynames[3*NWDAY+1] = "SunMonTueWedThuFriSat"; ! 42: static char dpm[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; ! 43: static int dstadjust = 60*60; /* In seconds */ ! 44: static char dsthour = 2; ! 45: static struct dsttimes { ! 46: char dst_occur, dst_day, dst_month; ! 47: } dsttimes[2] = { ! 48: { 1, 0, 3 }, /* First Sunday in April */ ! 49: { -1, 0, 9 } /* Last Sunday in October */ ! 50: }; ! 51: static char months[3*NMON+1] = "JanFebMarAprMayJunJulAugSepOctNovDec"; ! 52: static char timestr[] = "AAA AAA DD DD:DD:DD DDDD\n"; ! 53: static struct tm tm; ! 54: static char tz0[NTZNAME+1] = "GMT"; ! 55: static char tz1[NTZNAME+1] = ""; ! 56: ! 57: /* Global data. */ ! 58: long timezone = 0L; ! 59: char *tzname[2] = { tz0, tz1 }; ! 60: char tzdstdef[] = "1.1.4:-1.1.10:2:60......"; ! 61: ! 62: /* Set the timezone parameters, once is enough */ ! 63: void ! 64: settz() ! 65: { ! 66: extern char *getenv(); ! 67: register char *cp1, *cp2; ! 68: static int settz = 0; ! 69: ! 70: if (settz++ > 0) ! 71: return; ! 72: if ((cp1 = getenv("TIMEZONE")) == ((char *)0)) ! 73: return; ! 74: timezone = 0; ! 75: ! 76: /* Read primary timezone name and nul terminate */ ! 77: cp2 = tzname[0]; ! 78: while (*cp1 && *cp1 != ':' && cp2 < &tzname[0][NTZNAME]) ! 79: *cp2++ = *cp1++; ! 80: *cp2++ = '\0'; ! 81: while (*cp1 && *cp1++ != ':'); ! 82: ! 83: /* Read timezone offset and convert to seconds */ ! 84: timezone = (long)atoi(cp1) * 60L; ! 85: while (*cp1 && *cp1++ != ':'); ! 86: ! 87: /* Read daylight timezone name and nul terminate */ ! 88: cp2 = tzname[1]; ! 89: while (*cp1 && *cp1 != ':' && cp2 < &tzname[1][NTZNAME]) ! 90: *cp2++ = *cp1++; ! 91: *cp2++ = '\0'; ! 92: while (*cp1 && *cp1++ != ':'); ! 93: ! 94: /* Exit if no daylight time */ ! 95: if (tzname[1][0] == '\0') ! 96: return; ! 97: ! 98: /* Set default dst parameters */ ! 99: setdst(tzdstdef); ! 100: ! 101: /* Set supplied dst parameters */ ! 102: setdst(cp1); ! 103: } ! 104: ! 105: /* Parse and set dst parameters */ ! 106: static ! 107: setdst(cp1) register char *cp1; ! 108: { ! 109: /* Get optional start of daylight time */ ! 110: if (*cp1) { ! 111: dsttimes[0].dst_occur = atoi(cp1); ! 112: while (*cp1 && *cp1++ != '.'); ! 113: dsttimes[0].dst_day = atoi(cp1)-1; ! 114: while (*cp1 && *cp1++ != '.'); ! 115: dsttimes[0].dst_month = atoi(cp1)-1; ! 116: while (*cp1 && *cp1++ != ':'); ! 117: } ! 118: ! 119: /* Get optional end of daylight time */ ! 120: if (*cp1) { ! 121: dsttimes[1].dst_occur = atoi(cp1); ! 122: while (*cp1 && *cp1++ != '.'); ! 123: dsttimes[1].dst_day = atoi(cp1)-1; ! 124: while (*cp1 && *cp1++ != '.'); ! 125: dsttimes[1].dst_month = atoi(cp1)-1; ! 126: while (*cp1 && *cp1++ != ':'); ! 127: } ! 128: ! 129: /* Get optional hour of daylight time advance */ ! 130: if (*cp1) { ! 131: dsthour = atoi(cp1); ! 132: while (*cp1 && *cp1++ != ':'); ! 133: } ! 134: ! 135: /* Get optional minutes of adjustment */ ! 136: if (*cp1) ! 137: dstadjust = atoi(cp1) * 60; ! 138: } ! 139: ! 140: #if 0 ! 141: /* ! 142: * This ftime() is not required for COH 4.0.1r78 or later, ! 143: * it is now a system call using the stub generated by sys/i386/scall.s5. ! 144: */ ! 145: /* ! 146: * ftime() ! 147: */ ! 148: ftime (tb) struct timeb *tb; ! 149: { ! 150: time_t t; ! 151: ! 152: tb->time = time(&t); ! 153: settz(); ! 154: localtime(&t); ! 155: tb->millitm = 0; ! 156: tb->timezone = (short)(timezone / 60L); ! 157: tb->dstflag = isdaylight(); ! 158: } ! 159: #endif ! 160: ! 161: /* ! 162: * Most common interface, returns a static string ! 163: * which is a printable version of the time and date. ! 164: */ ! 165: char * ! 166: ctime(tp) ! 167: long *tp; ! 168: { ! 169: return asctime(localtime(tp)); ! 170: } ! 171: ! 172: /* ! 173: * Do what gmtime does for the local timezone. ! 174: * And correct for daylight time. ! 175: */ ! 176: struct tm * ! 177: localtime(tp) ! 178: long *tp; ! 179: { ! 180: long ltime; ! 181: ! 182: settz(); ! 183: ltime = *tp - timezone; ! 184: gmtime(<ime); ! 185: ! 186: /* ! 187: * If necessary, adjust for daylight saving time. ! 188: */ ! 189: if (isdaylight()) { ! 190: ltime = *tp - timezone + dstadjust; ! 191: gmtime(<ime); ! 192: tm.tm_isdst = 1; ! 193: } else ! 194: tm.tm_isdst = 0; ! 195: return &tm; ! 196: } ! 197: ! 198: /* ! 199: * Returns a printable version of the time ! 200: * which has been broken down as in the tm structure. ! 201: */ ! 202: char * ! 203: asctime(tmp) ! 204: struct tm *tmp; ! 205: { ! 206: register char *cp, *xp; ! 207: register unsigned i; ! 208: ! 209: cp = timestr; ! 210: /* ! 211: * Day of week ! 212: */ ! 213: if ((i = tmp->tm_wday) >= NWDAY) ! 214: i = 0; ! 215: xp = &daynames[i*3]; ! 216: *cp++ = *xp++; ! 217: *cp++ = *xp++; ! 218: *cp++ = *xp++; ! 219: *cp++ = ' '; ! 220: /* ! 221: * Month ! 222: */ ! 223: if ((i = tmp->tm_mon) >= NMON) ! 224: i = 0; ! 225: xp = &months[i*3]; ! 226: *cp++ = *xp++; ! 227: *cp++ = *xp++; ! 228: *cp++ = *xp++; ! 229: *cp++ = ' '; ! 230: /* ! 231: * Day of month ! 232: */ ! 233: if ((i = tmp->tm_mday) >= 10) ! 234: *cp++ = todigit(i/10); ! 235: else ! 236: *cp++ = ' '; ! 237: *cp++ = todigit(i%10); ! 238: *cp++ = ' '; ! 239: /* ! 240: * Hours:mins:seconds ! 241: */ ! 242: *cp++ = todigit((i = tmp->tm_hour)/10); ! 243: *cp++ = todigit(i%10); ! 244: *cp++ = ':'; ! 245: *cp++ = todigit((i = tmp->tm_min)/10); ! 246: *cp++ = todigit(i%10); ! 247: *cp++ = ':'; ! 248: *cp++ = todigit((i = tmp->tm_sec)/10); ! 249: *cp++ = todigit(i%10); ! 250: *cp++ = ' '; ! 251: /* ! 252: * Year ! 253: */ ! 254: i = tmp->tm_year + 1900; ! 255: *cp++ = todigit(i/1000); ! 256: i = i%1000; ! 257: *cp++ = todigit(i/100); ! 258: i = i%100; ! 259: *cp++ = todigit(i/10); ! 260: *cp++ = todigit(i%10); ! 261: *cp++ = '\n'; ! 262: *cp++ = '\0'; ! 263: return timestr; ! 264: } ! 265: ! 266: /* ! 267: * Do conversions for Greenwich Mean Time to ! 268: * the tm structure. ! 269: */ ! 270: struct tm * ! 271: gmtime(tp) ! 272: long *tp; ! 273: { ! 274: long xtime; ! 275: unsigned days; ! 276: long secs; ! 277: int year; ! 278: int ydays; ! 279: int wday; ! 280: register char *mp; ! 281: ! 282: if ((xtime = *tp) < 0) ! 283: xtime = 0; ! 284: days = xtime/(60L*60L*24L); ! 285: secs = xtime%(60L*60L*24L); ! 286: tm.tm_hour = secs/(60L*60L); ! 287: secs = secs%(60L*60L); ! 288: tm.tm_min = secs/60; ! 289: tm.tm_sec = secs%60; ! 290: /* ! 291: * Start at Thursday (wday=4) Jan 1, 1970 (the Epoch) ! 292: * and calculate from there. ! 293: */ ! 294: wday = (4+days)%NWDAY; ! 295: year = 1970; ! 296: for (;;) { ! 297: ydays = isleap(year) ? 366 : 365; ! 298: if (days < ydays) ! 299: break; ! 300: year++; ! 301: days -= ydays; ! 302: } ! 303: tm.tm_year = year-1900; ! 304: tm.tm_yday = days; ! 305: tm.tm_wday = wday; ! 306: /* ! 307: * Setup february's #days now. ! 308: */ ! 309: if (isleap(year)) ! 310: dpm[FEB] = 29; ! 311: else ! 312: dpm[FEB] = 28; ! 313: for (mp = &dpm[0]; mp < &dpm[NMON] && days >= *mp; mp++) ! 314: days -= *mp; ! 315: tm.tm_mon = mp-dpm; ! 316: tm.tm_mday = days+1; ! 317: return &tm; ! 318: } ! 319: ! 320: /* ! 321: * Return 1 on leap years; 0 otherwise. ! 322: */ ! 323: static ! 324: isleap(yr) ! 325: register yr; ! 326: { ! 327: if (yr%4000 == 0) ! 328: return 0; ! 329: return (yr%400==0 || (yr%100!=0 && yr%4==0)); ! 330: } ! 331: ! 332: /* ! 333: * Check for daylight savings time. ! 334: * Watch out for the Southern Hemisphere, where start month > end month. ! 335: * This does not do the case where start == end correctly for all cases. ! 336: */ ! 337: static ! 338: isdaylight() ! 339: { ! 340: register int month, start, end, xday; ! 341: ! 342: if (tzname[1][0] == 0) ! 343: return 0; /* No name, no daylight time */ ! 344: month = tm.tm_mon; ! 345: start = dsttimes[0].dst_month; ! 346: end = dsttimes[1].dst_month; ! 347: if ((start <= end && (month < start || month > end)) ! 348: || (start > end && (month < start && month > end))) ! 349: return 0; /* current month is never DST */ ! 350: else if (month == start) { /* DST starts this month */ ! 351: xday = nthday(&dsttimes[0]); /* DST starts on xday */ ! 352: if (tm.tm_mday != xday) ! 353: return (tm.tm_mday > xday); ! 354: return (tm.tm_hour >= dsthour); ! 355: } else if (month == end) { /* DST ends this month */ ! 356: xday = nthday(&dsttimes[1]); /* DST ends on xday */ ! 357: if (tm.tm_mday != xday) ! 358: return (tm.tm_mday < xday); ! 359: return (tm.tm_hour < dsthour-1); ! 360: } else ! 361: return 1; /* current month is always DST */ ! 362: } ! 363: ! 364: static ! 365: nthday(dp) ! 366: register struct dsttimes *dp; ! 367: { ! 368: register int nthday; ! 369: register int nth; ! 370: ! 371: if ((nth = dp->dst_occur) == 0) ! 372: return dp->dst_day; ! 373: nthday = tm.tm_mday - tm.tm_wday + dp->dst_day; ! 374: if (nth > 0) { ! 375: while (nthday > 0) ! 376: nthday -= 7; ! 377: do ! 378: nthday += 7; ! 379: while (--nth > 0); ! 380: } else { ! 381: while (nthday < dpm[tm.tm_mon]) ! 382: nthday += 7; ! 383: do ! 384: nthday -= 7; ! 385: while (++nth < 0); ! 386: } ! 387: return nthday; ! 388: } ! 389: ! 390: /* end of ctime.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.