]> pd.if.org Git - pdclib/blob - functions/time.c
7da9c4b3281ae358e95d1e8ad322ccaa3b6831ee
[pdclib] / functions / time.c
1 // ----------------------------------------------------------------------------
2 // $Id$
3 // ----------------------------------------------------------------------------
4 // Public Domain C Library - http://pdclib.sourceforge.net
5 // This code is Public Domain. Use, modify, and redistribute at will.
6 // ----------------------------------------------------------------------------
7
8 char * asctime( const struct tm * tptr ) { /* TODO */ };
9 clock_t clock( void ) { /* TODO */ };
10 char * ctime( const time_t * tod ) { /* TODO */ };
11 double difftime( time_t t1, time_t t0 ) { /* TODO */ };
12 struct tm * gmtime( const time_t * tod ) { /* TODO */ };
13 struct tm * localtime( const time_t * tod ) { /* TODO */ };
14 time_t mktime( struct tm * tptr ) { /* TODO */ };
15 size_t strftime( char * restrict s, size_t n, const char * restrict format,
16  const struct tm * restrict tptr ) { /* TODO */ };
17 time_t time( time_t * tod ) { /* TODO */ };
18
19 /* PDPC code - unreviewed, verbatim
20 /* scalar date routines    --    public domain by Ray Gardner
21 ** These will work over the range 1-01-01 thru 14699-12-31
22 ** The functions written by Ray are isleap, months_to_days, 
23 ** years_to_days, ymd_to_scalar, scalar_to_ymd.
24 ** modified slightly by Paul Edwards
25 */
26
27 static int isleap(unsigned yr)
28 {
29    return yr % 400 == 0 || (yr % 4 == 0 && yr % 100 != 0);
30 }
31
32 static unsigned months_to_days(unsigned month)
33 {
34    return (month * 3057 - 3007) / 100;
35 }
36
37 static long years_to_days (unsigned yr)
38 {
39    return yr * 365L + yr / 4 - yr / 100 + yr / 400;
40 }
41
42 static long ymd_to_scalar(unsigned yr, unsigned mo, unsigned day)
43 {
44    long scalar;
45    
46    scalar = day + months_to_days(mo);
47    if ( mo > 2 )                         /* adjust if past February */
48       scalar -= isleap(yr) ? 1 : 2;
49    yr--;
50    scalar += years_to_days(yr);
51    return (scalar);
52 }
53
54 static void scalar_to_ymd(long scalar, 
55                           unsigned *pyr, 
56                           unsigned *pmo, 
57                           unsigned *pday)
58 {
59    unsigned n;                /* compute inverse of years_to_days() */
60
61    n = (unsigned)((scalar * 400L) / 146097L); 
62    while (years_to_days(n) < scalar)
63    {
64       n++;                         
65    }
66    for ( n = (unsigned)((scalar * 400L) / 146097L); years_to_days(n) < scalar; )
67       n++;                          /* 146097 == years_to_days(400) */
68    *pyr = n;
69    n = (unsigned)(scalar - years_to_days(n-1));
70    if ( n > 59 ) {                       /* adjust if past February */
71       n += 2;
72       if ( isleap(*pyr) )
73          n -= n > 62 ? 1 : 2;
74    }
75    *pmo = (n * 100 + 3007) / 3057;  /* inverse of months_to_days() */
76    *pday = n - months_to_days(*pmo);
77    return;
78 }
79
80 time_t time(time_t *timer)
81 {
82     time_t tt;
83 #ifdef __OS2__    
84     DATETIME dt;
85     APIRET rc;
86 #endif    
87 #if (defined(__MSDOS__) || defined(__MVS__))
88     struct {
89         int year;
90         int month;
91         int day;
92         int hours;
93         int minutes;
94         int seconds;
95         int hundredths;
96     } dt;
97 #endif
98 #ifdef __MVS__
99     unsigned int clk[2];
100 #endif    
101
102 #ifdef __OS2__
103     rc = DosGetDateTime(&dt);
104     if (rc != 0)
105     {
106         tt = (time_t)-1;
107     }
108     else
109 #endif    
110 #ifdef __MSDOS__
111     __datetime(&dt);
112 #endif
113 #ifdef __MVS__
114     tt = __getclk(clk);
115 #else
116
117     {
118         tt = ymd_to_scalar(dt.year, dt.month, dt.day) 
119              - ymd_to_scalar(1970, 1, 1);
120         tt = tt * 24 + dt.hours;
121         tt = tt * 60 + dt.minutes;
122         tt = tt * 60 + dt.seconds;
123     }
124 #endif    
125     if (timer != NULL)
126     {
127         *timer = tt;
128     }
129     return (tt);
130 }
131
132 clock_t clock(void)
133 {
134     return ((clock_t)-1);
135 }
136
137 double difftime(time_t time1, time_t time0)
138 {
139     return ((double)(time1 - time0));
140 }
141
142 time_t mktime(struct tm *timeptr)
143 {
144     time_t tt;
145     
146     if ((timeptr->tm_year < 70) || (timeptr->tm_year > 120))
147     {
148         tt = (time_t)-1;
149     }
150     else
151     {
152         tt = ymd_to_scalar(timeptr->tm_year + 1900, 
153                            timeptr->tm_mon, 
154                            timeptr->tm_mday)
155              - ymd_to_scalar(1970, 1, 1);
156         tt = tt * 24 + timeptr->tm_hour;
157         tt = tt * 60 + timeptr->tm_min;
158         tt = tt * 60 + timeptr->tm_sec;
159     }
160     return (tt);
161 }
162
163 char *asctime(const struct tm *timeptr)
164 {
165     static const char wday_name[7][3] = {
166           "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
167     };
168     static const char mon_name[12][3] = {
169           "Jan", "Feb", "Mar", "Apr", "May", "Jun",
170           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
171     };
172     static char result[26];
173
174     sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
175           wday_name[timeptr->tm_wday],
176           mon_name[timeptr->tm_mon],
177           timeptr->tm_mday, timeptr->tm_hour,
178           timeptr->tm_min, timeptr->tm_sec,
179           1900 + timeptr->tm_year);
180     return result;
181 }
182
183 char *ctime(const time_t *timer)
184 {
185     return (asctime(localtime(timer)));
186 }
187
188 struct tm *gmtime(const time_t *timer)
189 {
190     return (localtime(timer));
191 }
192
193 /* dow - written by Paul Edwards, 1993-01-31 */
194 /* Released to the Public Domain */
195 /* This routine will work over the range 1-01-01 to 32767-12-31.
196    It assumes the current calendar system has always been in
197    place in that time.  If you pass 0 or negative years, then
198    it produces results on the assumption that there is a year
199    0.  It should always produce a value in the range of 0..6
200    if a valid month and day have been passed, no matter what
201    the year is.  However, it has not been tested for negative
202    years, because the results are meaningless anyway.  It is
203    mainly to stop people playing silly buggers and causing
204    the macro to crash on negative years. */
205  
206 /* Modified 1994-08-26 by Paul Edwards to make it return
207    0..6 for Sunday..Saturday instead of Monday..Sunday */
208 /* change the "(d) + 1" to "(d) + 0" to get it back to Monday
209    to Sunday if you want */   
210
211 #define dow(y,m,d) \
212   ((((((m)+9)%12+1)<<4)%27 + (d) + 1 + \
213   ((y)%400+400) + ((y)%400+400)/4 - ((y)%400+400)/100 + \
214   (((m)<=2) ? ( \
215   (((((y)%4)==0) && (((y)%100)!=0)) || (((y)%400)==0)) \
216   ? 5 : 6) : 0)) % 7)
217
218 static struct tm tms;
219
220 struct tm *localtime(const time_t *timer)
221 {
222     unsigned yr, mo, da;
223     unsigned long secs;
224     unsigned long days;
225
226     days = *timer / (60L*60*24);
227     secs = *timer % (60L*60*24);
228     scalar_to_ymd(days + ymd_to_scalar(1970, 1, 1), &yr, &mo, &da);
229     tms.tm_year = yr - 1900;
230     tms.tm_mon = mo - 1;
231     tms.tm_mday = da;
232     tms.tm_yday = (int)(ymd_to_scalar(tms.tm_year + 1900, 1, 1)
233                   - ymd_to_scalar(tms.tm_year + 1900, mo, da));
234     tms.tm_wday = dow(tms.tm_year + 1900, mo, da);
235     tms.tm_isdst = -1;
236     tms.tm_sec = (int)(secs % 60);
237     secs /= 60;
238     tms.tm_min = (int)(secs % 60);
239     secs /= 60;
240     tms.tm_hour = (int)secs;
241     return (&tms);
242 }
243
244 /*
245  * strftime.c
246  *
247  * implements the iso c function strftime()
248  *
249  * written 1989-09-06 by jim nutt
250  * released into the public domain by jim nutt
251  *
252  * modified 1989-10-21 by Rob Duff
253  *
254  * modified 1994-08-26 by Paul Edwards
255  */
256
257 static char *aday[] = {
258     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
259 };
260
261 static char *day[] = {
262     "Sunday", "Monday", "Tuesday", "Wednesday",
263     "Thursday", "Friday", "Saturday"
264 };
265
266 static char *amonth[] = {
267     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
268     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
269 };
270
271 static char *month[] = {
272     "January", "February", "March", "April", "May", "June",
273     "July", "August", "September", "October", "November", "December"
274 };
275
276 static char *__tzname[2] = { "" "" };
277 static char buf[26];
278
279 static void strfmt(char *str, const char *fmt, ...);
280
281 /**
282  *
283  * size_t strftime(char *str,
284  *                 size_t maxs,
285  *                 const char *fmt,
286  *                 const struct tm *t)
287  *
288  *      this functions acts much like a sprintf for time/date output.
289  *      given a pointer to an output buffer, a format string and a
290  *      time, it copies the time to the output buffer formatted in
291  *      accordance with the format string.  the parameters are used
292  *      as follows:
293  *
294  *          str is a pointer to the output buffer, there should
295  *          be at least maxs characters available at the address
296  *          pointed to by str.
297  *
298  *          maxs is the maximum number of characters to be copied
299  *          into the output buffer, included the '\0' terminator
300  *
301  *          fmt is the format string.  a percent sign (%) is used
302  *          to indicate that the following character is a special
303  *          format character.  the following are valid format
304  *          characters:
305  *
306  *              %A      full weekday name (Monday)
307  *              %a      abbreviated weekday name (Mon)
308  *              %B      full month name (January)
309  *              %b      abbreviated month name (Jan)
310  *              %c      standard date and time representation
311  *              %d      day-of-month (01-31)
312  *              %H      hour (24 hour clock) (00-23)
313  *              %I      hour (12 hour clock) (01-12)
314  *              %j      day-of-year (001-366)
315  *              %M      minute (00-59)
316  *              %m      month (01-12)
317  *              %p      local equivalent of AM or PM
318  *              %S      second (00-59)
319  *              %U      week-of-year, first day sunday (00-53)
320  *              %W      week-of-year, first day monday (00-53)
321  *              %w      weekday (0-6, sunday is 0)
322  *              %X      standard time representation
323  *              %x      standard date representation
324  *              %Y      year with century
325  *              %y      year without century (00-99)
326  *              %Z      timezone name
327  *              %%      percent sign
328  *
329  *      the standard date string is equivalent to:
330  *
331  *          %a %b %d %Y
332  *
333  *      the standard time string is equivalent to:
334  *
335  *          %H:%M:%S
336  *
337  *      the standard date and time string is equivalent to:
338  *
339  *          %a %b %d %H:%M:%S %Y
340  *
341  *      strftime returns the number of characters placed in the
342  *      buffer, not including the terminating \0, or zero if more
343  *      than maxs characters were produced.
344  *
345 **/
346
347 size_t strftime(char *s, size_t maxs, const char *f, const struct tm *t)
348 {
349       int w;
350       char *p, *q, *r;
351
352       p = s;
353       q = s + maxs - 1;
354       while ((*f != '\0'))
355       {
356             if (*f++ == '%')
357             {
358                   r = buf;
359                   switch (*f++)
360                   {
361                   case '%' :
362                         r = "%";
363                         break;
364
365                   case 'a' :
366                         r = aday[t->tm_wday];
367                         break;
368
369                   case 'A' :
370                         r = day[t->tm_wday];
371                         break;
372
373                   case 'b' :
374                         r = amonth[t->tm_mon];
375                         break;
376
377                   case 'B' :
378                         r = month[t->tm_mon];
379                         break;
380
381                   case 'c' :
382                         strfmt(r, "%0 %0 %2 %2:%2:%2 %4",
383                               aday[t->tm_wday], amonth[t->tm_mon],
384                               t->tm_mday,t->tm_hour, t->tm_min,
385                               t->tm_sec, t->tm_year+1900);
386                         break;
387
388                   case 'd' :
389                         strfmt(r,"%2",t->tm_mday);
390                         break;
391
392                   case 'H' :
393                         strfmt(r,"%2",t->tm_hour);
394                         break;
395
396                   case 'I' :
397                         strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12);
398                         break;
399
400                   case 'j' :
401                         strfmt(r,"%3",t->tm_yday+1);
402                         break;
403
404                   case 'm' :
405                         strfmt(r,"%2",t->tm_mon+1);
406                         break;
407
408                   case 'M' :
409                         strfmt(r,"%2",t->tm_min);
410                         break;
411
412                   case 'p' :
413                         r = (t->tm_hour>11)?"PM":"AM";
414                         break;
415
416                   case 'S' :
417                         strfmt(r,"%2",t->tm_sec);
418                         break;
419
420                   case 'U' :
421                         w = t->tm_yday/7;
422                         if (t->tm_yday%7 > t->tm_wday)
423                               w++;
424                         strfmt(r, "%2", w);
425                         break;
426
427                   case 'W' :
428                         w = t->tm_yday/7;
429                         if (t->tm_yday%7 > (t->tm_wday+6)%7)
430                               w++;
431                         strfmt(r, "%2", w);
432                         break;
433
434                   case 'w' :
435                         strfmt(r,"%1",t->tm_wday);
436                         break;
437
438                   case 'x' :
439                         strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday],
440                               amonth[t->tm_mon], t->tm_mday, t->tm_year+1900);
441                         break;
442
443                   case 'X' :
444                         strfmt(r, "%2:%2:%2", t->tm_hour,
445                               t->tm_min, t->tm_sec);
446                         break;
447
448                   case 'y' :
449                         strfmt(r,"%2",t->tm_year%100);
450                         break;
451
452                   case 'Y' :
453                         strfmt(r,"%4",t->tm_year+1900);
454                         break;
455
456                   case 'Z' :
457                         r = (t->tm_isdst) ? __tzname[1] : __tzname[0];
458                         break;
459
460                   default:
461                         buf[0] = '%';     /* reconstruct the format */
462                         buf[1] = f[-1];
463                         buf[2] = '\0';
464                         if (buf[1] == 0)
465                               f--;        /* back up if at end of string */
466                   }
467                   while (*r)
468                   {
469                         if (p == q)
470                         {
471                               *q = '\0';
472                               return 0;
473                         }
474                         *p++ = *r++;
475                   }
476             }
477             else
478             {
479                   if (p == q)
480                   {
481                         *q = '\0';
482                         return 0;
483                   }
484                   *p++ = f[-1];
485             }
486       }
487       *p = '\0';
488       return (size_t)(p - s);
489 }
490
491 static int pow[5] = { 1, 10, 100, 1000, 10000 };
492
493 /**
494  * static void strfmt(char *str, char *fmt);
495  *
496  * simple sprintf for strftime
497  *
498  * each format descriptor is of the form %n
499  * where n goes from zero to four
500  *
501  * 0    -- string %s
502  * 1..4 -- int %?.?d
503  *
504 **/
505
506 static void strfmt(char *str, const char *fmt, ...)
507 {
508       int ival, ilen;
509       char *sval;
510       va_list vp;
511
512       va_start(vp, fmt);
513       while (*fmt)
514       {
515             if (*fmt++ == '%')
516             {
517                   ilen = *fmt++ - '0';
518                   if (ilen == 0)                /* zero means string arg */
519                   {
520                         sval = va_arg(vp, char*);
521                         while (*sval)
522                               *str++ = *sval++;
523                   }
524                   else                          /* always leading zeros */
525                   {
526                         ival = va_arg(vp, int);
527                         while (ilen)
528                         {
529                               ival %= pow[ilen--];
530                               *str++ = (char)('0' + ival / pow[ilen]);
531                         }
532                   }
533             }
534             else  *str++ = fmt[-1];
535       }
536       *str = '\0';
537       va_end(vp);
538 }
539 */