home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2616 < prev    next >
Encoding:
Internet Message Format  |  1991-01-26  |  7.2 KB

  1. From: arnold@audiofax.com (Arnold Robbins)
  2. Newsgroups: alt.sources
  3. Subject: beta release, pd ANSI strftime routine
  4. Message-ID: <325@audfax.audiofax.com>
  5. Date: 25 Jan 91 20:54:28 GMT
  6.  
  7. The other day I wanted to use the ANSI C routine strftime.  It's not
  8. in my C library, unfortunately.  So I cobbled one up.  Here it is. Please
  9. try it out, and let me know if you find any bugs.  If there are none
  10. reported in the next week or so, I'll ship it out over one of the moderated
  11. source groups.
  12.  
  13. As this is alt.sources, there is no man page or makefile.  This compiles
  14. fine with both gcc and cc on my ESIX V.3.2 rev D system.
  15.  
  16. It does assume System V for the timezone information.
  17. ---------------- cut here ---------------------
  18. /*
  19.  * strftime.c
  20.  *
  21.  * Public-domain relatively quick-and-dirty implemenation of
  22.  * ANSI library routine for System V Unix systems.
  23.  *
  24.  * It's written in old-style C for maximal portability.
  25.  *
  26.  * The code for %c, %x, and %X is my best guess as to what's "appropriate".
  27.  * This version ignores LOCALE information.
  28.  * It also doesn't worry about multi-byte characters.
  29.  * So there.
  30.  *
  31.  * Arnold Robbins
  32.  * January, 1991
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <time.h>
  38. #include <sys/types.h>
  39.  
  40. #ifndef NULL
  41. #define NULL    0    /* the real programmer's definition */
  42. #endif
  43.  
  44. #ifndef __STDC__
  45. #define const    /**/
  46. #endif
  47.  
  48. #ifndef __STDC__
  49. extern void tzset();
  50. extern int abs();
  51. static int weeknumber();
  52. #else
  53. extern void tzset(void);
  54. extern int abs(int val);
  55. static int weeknumber(const struct tm *timeptr, int firstweekday);
  56. #endif
  57.  
  58. extern char *tzname[2];
  59. extern int daylight;
  60.  
  61. #define L_DAYA    3    /* length of an abbreviated day name */
  62. #define L_MONA    3    /* length of an abbreviated month name */
  63.  
  64.  
  65. /* strftime --- produce formatted time */
  66.  
  67. #ifndef __STDC__
  68. size_t
  69. strftime(s, maxsize, format, timeptr)
  70. char *s;
  71. size_t maxsize;
  72. const char *format;
  73. const struct tm *timeptr;
  74. #else
  75. size_t
  76. strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
  77. #endif
  78. {
  79.     char *endp = s + maxsize;
  80.     char *start = s;
  81.     char tbuf[100];
  82.     int i;
  83.     static short first = 1;
  84.  
  85.     /* various tables, useful in North America */
  86.     static char *days_a[] = {
  87.         "Sun", "Mon", "Tue", "Wed",
  88.         "Thu", "Fri", "Sat",
  89.     };
  90.     static char *days_l[] = {
  91.         "Sunday", "Monday", "Tuesday", "Wednesday",
  92.         "Thursday", "Friday", "Saturday",
  93.     };
  94.     static char *months_a[] = {
  95.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  96.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  97.     };
  98.     static char *months_l[] = {
  99.         "January", "February", "March", "April",
  100.         "May", "June", "July", "August", "September",
  101.         "October", "November", "December",
  102.     };
  103.  
  104.     if (s == NULL || format == NULL || timeptr == NULL || maxsize <= 0)
  105.         return 0;
  106.  
  107.     if (first) {
  108.         first = 0;
  109.         tzset();
  110.     }
  111.  
  112.     for (; *format && s < endp - 1; format++) {
  113.         tbuf[0] = '\0';
  114.         if (*format != '%') {
  115.             *s++ = *format;
  116.             continue;
  117.         }
  118.         switch (*++format) {
  119.         case '\0':
  120.             break;
  121.  
  122.         case '%':
  123.             *s++ = '%';
  124.             continue;
  125.  
  126.         case 'a':    /* abbreviated weekday name */
  127.             if (s + L_DAYA < endp - 1) {
  128.                 *s++ = days_a[timeptr->tm_wday][0];
  129.                 *s++ = days_a[timeptr->tm_wday][1];
  130.                 *s++ = days_a[timeptr->tm_wday][2];
  131.             } else
  132.                 goto out;
  133.             break;
  134.  
  135.         case 'A':    /* full weekday name */
  136.             i = strlen(days_l[timeptr->tm_wday]);
  137.             if (s + i < endp - 1) {
  138.                 strcpy(s, days_l[timeptr->tm_wday]);
  139.                 s += i;
  140.             } else
  141.                 goto out;
  142.             break;
  143.  
  144.         case 'b':    /* abbreviated month name */
  145.             if (s + L_MONA < endp - 1) {
  146.                 *s++ = months_a[timeptr->tm_mon][0];
  147.                 *s++ = months_a[timeptr->tm_mon][1];
  148.                 *s++ = months_a[timeptr->tm_mon][2];
  149.             } else
  150.                 goto out;
  151.             break;
  152.  
  153.         case 'B':    /* full month name */
  154.             i = strlen(months_l[timeptr->tm_mon]);
  155.             if (s + i < endp - 1) {
  156.                 strcpy(s, months_l[timeptr->tm_mon]);
  157.                 s += i;
  158.             } else
  159.                 goto out;
  160.             break;
  161.  
  162.         case 'c':    /* appropriate date and time representation */
  163.             sprintf(tbuf, "%s %s %2d %02d:%02d:%02d %d",
  164.                 days_a[timeptr->tm_wday],
  165.                 months_a[timeptr->tm_mon],
  166.                 timeptr->tm_mday,
  167.                 timeptr->tm_hour,
  168.                 timeptr->tm_min,
  169.                 timeptr->tm_sec,
  170.                 timeptr->tm_year + 1900);
  171.             break;
  172.  
  173.         case 'd':    /* day of the month, 01 - 31 */
  174.             sprintf(tbuf, "%02d", timeptr->tm_mday);
  175.             break;
  176.  
  177.         case 'H':    /* hour, 24-hour clock, 00 - 23 */
  178.             sprintf(tbuf, "%02d", timeptr->tm_hour);
  179.             break;
  180.  
  181.         case 'I':    /* hour, 12-hour clock, 01 - 12 */
  182.             i = timeptr->tm_hour;
  183.             if (i == 0)
  184.                 i = 12;
  185.             else if (i > 12)
  186.                 i -= 12;
  187.             sprintf(tbuf, "%02d", i);
  188.             break;
  189.  
  190.         case 'j':    /* day of the year, 001 - 366 */
  191.             sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
  192.             break;
  193.  
  194.         case 'm':    /* month, 01 - 12 */
  195.             sprintf(tbuf, "%02d", timeptr->tm_mon + 1);
  196.             break;
  197.  
  198.         case 'M':    /* minute, 00 - 59 */
  199.             sprintf(tbuf, "%02d", timeptr->tm_min);
  200.             break;
  201.  
  202.         case 'p':    /* am or pm based on 12-hour clock */
  203.             if (timeptr->tm_hour < 12)
  204.                 strcpy(tbuf, "a.m.");
  205.             else
  206.                 strcpy(tbuf, "p.m.");
  207.             break;
  208.  
  209.         case 'S':    /* second, 00 - 61 */
  210.             sprintf(tbuf, "%02d", timeptr->tm_sec);
  211.             break;
  212.  
  213.         case 'U':    /* week of year, Sunday is first day of week */
  214.             sprintf(tbuf, "%d", weeknumber(timeptr, 0));
  215.             break;
  216.  
  217.         case 'w':    /* weekday, Sunday == 0, 0 - 6 */
  218.             sprintf(tbuf, "%d", timeptr->tm_wday);
  219.             break;
  220.  
  221.         case 'W':    /* week of year, Monday is first day of week */
  222.             sprintf(tbuf, "%d", weeknumber(timeptr, 1));
  223.             break;
  224.  
  225.         case 'x':    /* appropriate date representation */
  226.             sprintf(tbuf, "%s %s %2d %d",
  227.                 days_a[timeptr->tm_wday],
  228.                 months_a[timeptr->tm_mon],
  229.                 timeptr->tm_mday,
  230.                 timeptr->tm_year + 1900);
  231.             break;
  232.  
  233.         case 'X':    /* appropriate time representation */
  234.             sprintf(tbuf, "%02d:%02d:%02d",
  235.                 timeptr->tm_hour,
  236.                 timeptr->tm_min,
  237.                 timeptr->tm_sec);
  238.             break;
  239.  
  240.         case 'y':    /* year without a century, 00 - 99 */
  241.             i = timeptr->tm_year % 100;
  242.             sprintf(tbuf, "%d", i);
  243.             break;
  244.  
  245.         case 'Y':    /* year with century */
  246.             sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
  247.             break;
  248.  
  249.         case 'Z':    /* time zone name or abbrevation */
  250.             i = 0;
  251.             if (daylight && timeptr->tm_isdst)
  252.                 i = 1;
  253.             strcpy(tbuf, tzname[i]);
  254.             break;
  255.  
  256.         default:
  257.             /* do something reasonable */
  258.             if (s + 2 < endp - 1) {
  259.                 *s++ = '%';
  260.                 *s++ = *format;
  261.             } else
  262.                 goto out;
  263.             continue;
  264.         }
  265.         i = strlen(tbuf);
  266.         if (i)
  267.             if (s + i < endp - 1) {
  268.                 strcpy(s, tbuf);
  269.                 s += i;
  270.             } else
  271.                 break;    /* the for loop */
  272.     }
  273. out:
  274.     if (s < endp) {
  275.         *s = '\0';
  276.         return (s - start - 1);
  277.     } else
  278.         return 0;
  279. }
  280.  
  281. /* weeknumber --- figure how many weeks into the year */
  282.  
  283. #ifndef __STDC__
  284. static int
  285. weeknumber(timeptr, firstweekday)
  286. const struct tm *timeptr;
  287. int firstweekday;
  288. #else
  289. static int
  290. weeknumber(const struct tm *timeptr, int firstweekday)
  291. #endif
  292. {
  293.     int m, drift, r;
  294.  
  295.     /* days into the current 7-day period */
  296.     m = timeptr->tm_yday % 7;
  297.  
  298.     /* special case the first week */
  299.     if (m == timeptr->tm_yday)
  300.         if (timeptr->tm_wday >= firstweekday)
  301.             return 1;
  302.         else
  303.             return 0;
  304.  
  305.     /* how many days away from Sunday or Monday the year started */
  306.     drift = timeptr->tm_wday - m + firstweekday;
  307.     drift = abs(drift);
  308.  
  309.     r = (timeptr->tm_yday - drift) / 7;
  310.  
  311.     return r;
  312. }
  313. -- 
  314. Arnold Robbins                AudioFAX, Inc. | Laundry increases
  315. 2000 Powers Ferry Road, #200 / Marietta, GA. 30067     | exponentially in the
  316. INTERNET: arnold@audiofax.com Phone:   +1 404 933 7612 | number of children.
  317. UUCP:      emory!audfax!arnold Fax-box: +1 404 618 4581 |   -- Miriam Robbins
  318.