/******************************************************************************* * vdate.c * Compatible with Unix date(1), but handles 4-digit years better. * It is also compatible with System V.4 date(1) and ANSI-C * strftime(3C). * * Caveats * This does not deal with the locale (LC_LOCALE) at all. * * Bugs * The %U and %W format specifiers are not implemented. * The %Z format specifier is not implemented. * * History * 1.0, 1991-02-12, David R Tribble. * First cut. * * 2.1, 2002-12-07, David R Tribble. * Converted to ISO/ANSI C. * * Copyright ©1991,2002 by David R. Tribble, all rights reserved. * Permission is granted to use and distribute this source code provided that the * original copyright and authorship notices remain intact and unaltered. */ /* Identification */ static const char REV[] = "@(#)drt/src/cmd/vdate.c $Revision: 2.1 $ $Date: 2002-12-07 $\n"; static const char COPYRIGHT[] = "Copyright \xA9 1991,2002 by David R. Tribble, all rights reserved."; /* System includes */ #include #include #include #include #include #include #include /* Local constants */ #define ESC '%' #define DFL_FMT "%a %b %e %T %Y" /* eg: "Thu Jan 3 22:16:56 1991" */ /* Private variables */ static const char * pgm = "vdate"; static const char *const usage_m[] = { "'sec' is the number of seconds since 00:00:00 1 Jan 1970 GMT.", "", "'format' strings are composed of printable characters and special", "field descriptors:", "", "%% \"%\" character", "%a Abbreviated weekday name (Sun to Sat)", "%A Full weekday name (Sunday to Saturday)", "%b Abbreviated month name (Jan to Dec)", "%B Full month name (January to December)", "%c Default date and time format (\"%a %b %e %T %Y\")", "%C Same as \"%c\"", "%d Day of month (01 to 31)", "%D Date as \"%m/%d/%y\"", "%e Day of month ( 1 to 31)", "%h Same as \"%b\"", "%H Hour (00 to 23)", "%I Hour (01 to 12)", "%j Day of year (001 to 366)", "%m Month of year (01 to 12)", "%M Minute (00 to 59)", "%n Newline character", "%N Number of seconds since 1 Jan 1970 GMT", /* Extension */ "%p AM or PM", "%r Time as \"%I:%M:%S %p\"", "%R Time as \"%H:%M\"", "%s Millisecond (000 to 999)", /* Extension */ "%S Second (00 to 61, allows for leap seconds)", "%t Tab character", "%T Time as \"%H:%M:%S\"", "%U Week of year (00 to 52, Sunday is first day of year)", "%v Daylight Savings Time indicator (Y or N)", /* Extension */ "%V Week of year (01 to 53, Sunday is first day of year)", "%w Weekday number (0 to 6, Sunday is 0)", #ifdef is_not_supported_ "%W Week of year (00 to 53, Monday is first day of week)", #endif "%x Date as \"%a %b %Y\"", "%X Time as \"%T\"", "%y Year within century (00 to 99)", "%Y Year, 4 digits (1900 to 2099)", "%Z Zone name (or nothing if unknown)", NULL }; static const char *const wday[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", }; static const char *const month[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; /******************************************************************************* * print_date() */ void print_date(time_t t, int msec, const char *fmt) { struct tm ts; int hour12; int mon; int yday; int jan1_wday; int weekno_sun; int weekno_mon; int ch; /* Get local time */ ts = *localtime(&t); #ifdef TEST tzname[0] = "CST"; tzname[1] = "CDT"; daylight = 1; timezone = 6 * 60 * 60; #endif /* Compute other time values */ hour12 = ts.tm_hour; if (hour12 > 12) hour12 -= 12; if (hour12 == 0) hour12 = 12; mon = ts.tm_mon + 1; yday = ts.tm_yday + 1; jan1_wday = (ts.tm_wday - ts.tm_yday % 7 + 7) % 7; weekno_sun = (ts.tm_yday + jan1_wday) / 7; #ifdef is_not_supported_ /*** weekno fails for 1st_yday=Sun or 1st_yday=Mon ***/ wday_sun = (ts.tm_wday + 7) % 7; wday_mon = (wday_sun - 1 + 7) % 7; weekno_sun = (ts.tm_yday - wday_sun + 7) / 7; weekno_mon = (ts.tm_yday - wday_mon + 7) / 7; #endif /* Print the formatted date */ while (*fmt != '\0') { ch = *fmt++; if (ch == ESC) { ch = *fmt++; switch (ch) { case 'a': printf("%3.3s", wday[ts.tm_wday]); break; case 'A': printf("%s", wday[ts.tm_wday]); break; case 'b': case 'h': printf("%3.3s", month[ts.tm_mon]); break; case 'B': printf("%s", month[ts.tm_mon]); break; case 'c': case 'C': print_date(t, msec, "%a %b %e %T %Y"); break; case 'd': printf("%.2d", ts.tm_mday); break; case 'D': print_date(t, msec, "%m/%d/%y"); break; case 'e': printf("%2d", ts.tm_mday); break; case 'H': printf("%2.2d", ts.tm_hour); break; case 'I': printf("%2.2d", hour12); break; case 'j': printf("%3.3d", yday); break; case 'm': printf("%2.2d", mon); break; case 'M': printf("%2.2d", ts.tm_min); break; case 'n': printf("\n"); break; case 'N': printf("%10ld", (long)t); break; case 'p': printf("%s", (ts.tm_hour < 12 ? "AM" : "PM")); break; case 'r': print_date(t, msec, "%I:%M:%S %p"); break; case 'R': print_date(t, msec, "%H:%M"); break; case 's': printf("%3.3d", msec); break; case 'S': printf("%2.2d", ts.tm_sec); break; case 't': printf("\t"); break; case 'T': print_date(t, msec, "%H:%M:%S"); break; case 'U': printf("%2.2d", weekno_sun); break; case 'v': printf("%c", (ts.tm_isdst ? 'T' : 'F')); break; case 'V': printf("%2.2d", weekno_sun+1); break; case 'w': printf("%d", ts.tm_wday); break; case 'W': #ifdef is_not_supported_ printf("%2.2d", weekno_mon); #else fprintf(stderr, "%s: Unsupported format '%c'\n", pgm, ch); #endif break; case 'x': print_date(t, msec, "%e %b %Y"); break; case 'X': print_date(t, msec, "%H:%M:%S"); break; case 'y': printf("%2.2d", (ts.tm_year % 100)); break; case 'Y': printf("%4.4d", (ts.tm_year + 1900)); break; case 'Z': printf("%s", tzname[ts.tm_isdst > 0]); break; case ESC: case '\0': printf("%c", ESC); break; default: fprintf(stderr, "%s: Bad format character '%c'\n", pgm, ch); /* printf("%c", ch); */ } } else putchar(ch); } } /******************************************************************************/ #ifdef TEST static void test_case(time_t t, int msec, const char *fmt, const char *exp) { printf("\"%s\": \"", fmt+1); print_date(t, msec, fmt+1); printf("\"\n"); } /******************************************************************************* * main() * Test driver. */ int main(int argc, const char *const argv[]) { time_t t; /*pgm = argv[0];*/ t = 0; /* 1969-12-31 18:00:00.000 CST */ test_case(t, "+%%", "%"); test_case(t, "+%a", "Wed"); test_case(t, "+%A", "Wednesday"); test_case(t, "+%b", "Dec"); test_case(t, "+%B", "December"); test_case(t, "+%c", "Wed Dec 31 18:00:00 CST 1969"); test_case(t, "+%C", "Wed Dec 31 18:00:00 CST 1969"); test_case(t, "+%d", "31"); test_case(t, "+%D", "12/31/69"); test_case(t, "+%e", "31"); test_case(t, "+%h", "Dec"); test_case(t, "+%H", "18"); test_case(t, "+%I", "06"); test_case(t, "+%j", "364"); test_case(t, "+%m", "12"); test_case(t, "+%M", "00"); test_case(t, "+%n", "\n"); test_case(t, "+%N", " 0"); test_case(t, "+%p", "PM"); test_case(t, "+%r", "06:00:00 PM"); test_case(t, "+%R", "18:00"); test_case(t, "+%S", "00"); test_case(t, "+%t", "\t"); test_case(t, "+%T", "18:00:00"); test_case(t, "+%U", "51"); test_case(t, "+%v", "F"); test_case(t, "+%V", "52"); test_case(t, "+%w", "3"); test_case(t, "+%W", "51"); test_case(t, "+%x", "31 Dec 1969"); test_case(t, "+%X", "18:00:00"); test_case(t, "+%y", "69"); test_case(t, "+%Y", "1969"); /*test_case(t, "+%Z", "CST");*/ printf("============================\n"); t = 651669958; /* 1990-08-26 06:25:58.000 CDT */ test_case(t, "+%%", "%"); test_case(t, "+%a", "Sun"); test_case(t, "+%A", "Sunday"); test_case(t, "+%b", "Aug"); test_case(t, "+%B", "August"); test_case(t, "+%c", "Sun Aug 26 06:25:58 CDT 1990"); test_case(t, "+%C", "Sun Aug 26 06:25:58 CDT 1990"); test_case(t, "+%d", "26"); test_case(t, "+%D", "08/26/90"); test_case(t, "+%e", "26"); test_case(t, "+%h", "Aug"); test_case(t, "+%H", "06"); test_case(t, "+%I", "06"); test_case(t, "+%j", "237"); test_case(t, "+%m", "08"); test_case(t, "+%M", "25"); test_case(t, "+%n", "\n"); test_case(t, "+%N", " 651669958"); test_case(t, "+%p", "AM"); test_case(t, "+%r", "06:25:58 AM"); test_case(t, "+%R", "06:25"); test_case(t, "+%S", "58"); test_case(t, "+%t", "\t"); test_case(t, "+%T", "06:25:58"); test_case(t, "+%U", "33"); test_case(t, "+%v", "T"); test_case(t, "+%V", "34"); test_case(t, "+%w", "0"); test_case(t, "+%W", "34"); test_case(t, "+%x", "26 Aug 1990"); test_case(t, "+%X", "06:25:58"); test_case(t, "+%y", "90"); test_case(t, "+%Y", "1990"); /*test_case(t, "+%Z", "CDT");*/ printf("============================\n"); return (0); } #define main dummy_main #endif /* TEST */ /******************************************************************************/ /******************************************************************************* * main() * Main program driver. */ int main(int argc, char *argv[]) { int i; time_t t; int msec; /* Get the current time */ tzset(); time(&t); #if IS_INCOMPLETE #if unix ...use gettimeofday() #elif WIN32 ...use GetSystemTime()? #else time(&t); #endif #endif msec = 0; /* Check args */ /*pgm = argv[0];*/ if (argc > 1 and isdigit(argv[1][0])) { t = atol(argv[1]); argc--, argv++; } if (argc < 2) { argc = 2; argv[1] = DFL_FMT; argv[2] = NULL; } else if (argv[1][0] == '+') argv[1]++; else goto usage; /* Print a formatted time */ for (i = 1; i < argc; i++) { if (i > 1) print_date(t, msec, " "); print_date(t, msec, argv[i]); } print_date(t, msec, "\n"); fflush(stdout); return (0); usage: /* Improper usage, print a usage message and punt */ fprintf(stderr, "Print date and time.\n\n"); fprintf(stderr, "usage: %s [sec] [+format [format...]]\n\n", pgm); for (i = 0; usage_m[i] != NULL; i++) fprintf(stderr, "%s\n", usage_m[i]); return (1); } /* End vdate.c */