#!mkcmd # $Id: datecalc.m,v 1.16 2009/03/12 19:05:14 ksb Exp $ # $Mkcmd: mkcmd %f # from '' from '' from '' from '' from '' from '' from '' from '"machine.h"' basename "datecalc" "" require "std_help.m" "std_version.m" require "util_time.m" # for better conversion (in local time zone) require "time_tz.m" %i static char rcsid[] = "$Id: datecalc.m,v 1.16 2009/03/12 19:05:14 ksb Exp $"; #define ISNOT 0 #define ISTIME 1 #define ISDATE 2 #define ISSCALAR 3 extern int TimeToSeconds(char *, time_t *); extern char *SecondsToTime(time_t); extern char *EatWhite(char *); extern char *EatNumber(char *); static char acAtSpec[] = "%H%M %h %d"; static char acAtYears[] = "-t %G%m%d%H%M"; %% # Operations exclude "asmdc" boolean 'a' { named "fAdd" init "0" update "%ran = !%i;" help "Add a time string to a date" } boolean 's' { named "fSubtract" init "0" update "%rsn = !%i;" help "Subtract a time string from a date" } boolean 'm' { named "fMultipy" init "0" update "%rmn = !%i;" exclude "asdoefnpty" help "Multiply a time string by a scalar" } boolean 'd' { named "fDivide" init "0" update "%rdn = !%i;" help "Divide a time string by a scalar" } # remainder/modulus? #boolean 'r' { # named "fRemainder" # init "0" # help "Modulus a time by a scaler" #} boolean 'c' { named "fCompare" init "0" update "%rcn = !%i;" help "Compare two dates or times" } # Ouptut formats exclude "petfny" boolean 'e' { named "fUnEpoch" init "0" update "%ren = !%i;" help "Convert seconds since the epoch to a date" } boolean 'f' { named "fFixedFormat" init "0" update "%rfn = !%i;" help "Convert a free format date to fixed format" } boolean 'p' { named "fEpoch" init "0" update "%rpn = !%i;" help "Convert a date to seconds since the epoch" } action 't' { init "0" update "%rfn = !%rfi;" user 'pcFormat = acAtSpec;' exclude "o" help "Convert a free format date to at's format" } boolean 'n' { named "fSeconds" exclude "o" init "0" help "Convert a time string to seconds" } boolean 'y' { named "fYears" exclude "o" init "0" help "Convert a time string to Years Days Hours Minutes Seconds" } char* 'o' { named "pcFormat" init '(char *)0' param "format" help "Specify a strftime(3) output format" } boolean 'v' { named "fVerbose" init "0" help "Verbose" } list { named "Process" param "dates" help "reference date/time for computation" aborts "exit(EX_TEMPFAIL);" } %c /* (mm) * When we are doing -t and the target is not in the current year * we need to change the output format to at's -t format (to get years), * some at commands won't take years w/o -t. */ void Output(time_t ttParam) { auto time_t tNow; auto struct tm *tm_date; auto char acLine[4096]; auto int iYear; (void)time(&tNow); tm_date = localtime(&tNow); iYear = tm_date->tm_year; tm_date = localtime(&ttParam); if ((char *)0 == pcFormat) { pcFormat = "%a %h %d %T %Z %Y"; } else if (acAtSpec != pcFormat) { /* we don't mess with a user format */ } else if (iYear != tm_date->tm_year) { pcFormat = acAtYears; } strftime(acLine, sizeof(acLine)-1, pcFormat, tm_date); printf("%s\n", acLine); } /* (mm) * ksb added strftime's %D (%m/%d/%y) format as a date. */ int TimeOrDate(char *pcStr, time_t *piTime, time_t *pttParam, int *piScalar) { register int iTmp; register char *pcNum; if (NULL == pcStr || '\000' == *pcStr) { return ISNOT; } if ((time_t *)0 != piTime && TimeToSeconds(pcStr, piTime)) { return ISTIME; } /* Ouch! We hard coded the timezone here, let's let mkcmd find it. */ if (pttParam) { if (0 == strcmp("yesterday", pcStr)) { time(pttParam); *pttParam -= (24*60*60); return ISDATE; } if (0 == strcmp("tomorrow", pcStr)) { time(pttParam); *pttParam += (24*60*60); return ISDATE; } if (0 == strcmp("now", pcStr) || 0 == strcmp("today", pcStr)) { time(pttParam); return ISDATE; } iTmp = atotm(pcStr, Atz_West); if (iTmp >= 0) { *pttParam = iTmp; return ISDATE; } } pcNum = EatWhite(pcStr); pcStr = EatNumber(pcNum); if ('\000' != *pcStr && (!isascii(*pcStr) || !isspace(*pcStr))){ return ISNOT; } pcStr = EatWhite(pcStr); if ('\000' != *pcStr) { return ISNOT; } *piScalar = atoi(pcNum); return ISSCALAR; } /* (mm) */ void Process(int argc, char **argv) { register int iArg1Type, iArg2Type; auto time_t ttTime, ttDummy; auto time_t ttDate1, ttDate2, ttTotal; auto int iScalar, iDummy; if (0 == argc) { fprintf(stderr, "%s: missing parameters\n", progname); exit(EX_USAGE); } iArg1Type = ISNOT; iArg2Type = ISNOT; switch (iArg1Type = TimeOrDate(argv[0], &ttTime, &ttDate1, &iScalar)) { case ISNOT: /* 1st Arg */ break; case ISTIME: /* 1st Arg */ switch (iArg2Type = TimeOrDate(argv[1], &ttDummy, &ttDate1, &iScalar)) { case ISNOT: /* 2nd Arg */ break; case ISTIME: /* 2nd Arg */ if (!fCompare) { fprintf(stderr,"%s: Second time (\"%s\") not valid.\n", progname, argv[1]); exit(EX_DATAERR); } break; case ISDATE: /* 2nd Arg */ break; case ISSCALAR: /* 2nd Arg */ break; default: /* 2nd Arg */ fprintf(stderr,"%s: Something went horribly wrong in TimeOrDate().\n", progname); exit(EX_SOFTWARE); } break; case ISDATE: /* 1st Arg */ switch (iArg2Type = TimeOrDate(argv[1], &ttTime, &ttDate2, &iScalar)) { case ISNOT: /* 2nd Arg */ break; case ISTIME: /* 2nd Arg */ break; case ISDATE: /* 2nd Arg */ break; case ISSCALAR: /* 2nd Arg */ if (fAdd || fSubtract || fCompare || fFixedFormat || fSeconds || fYears) { fprintf(stderr,"%s: A scalar is not valid for this operation\n", progname); exit(EX_DATAERR); } break; default: /* 2nd Arg */ fprintf(stderr,"%s: Something went horribly wrong in TimeOrDate().\n", progname); exit(EX_SOFTWARE); } break; case ISSCALAR: /* 1st Arg */ switch (iArg2Type = TimeOrDate(argv[1], &ttTime, &ttDate2, &iDummy)) { case ISNOT: /* 2nd Arg */ break; case ISTIME: /* 2nd Arg */ break; case ISDATE: /* 2nd Arg */ break; case ISSCALAR: /* 2nd Arg */ if (fAdd || fSubtract || fCompare || fFixedFormat || fSeconds || fYears) { fprintf(stderr,"%s: A scalar is not valid for this operation\n", progname); exit(EX_DATAERR); } break; default: /* 2nd Arg */ fprintf(stderr,"%s: Something went horribly wrong in TimeOrDate().\n", progname); exit(EX_SOFTWARE); } break; default: /* 1st Arg */ fprintf(stderr,"%s: Something went horribly wrong in TimeOrDate().\n", progname); exit(EX_SOFTWARE); } if (fUnEpoch || fEpoch || fFixedFormat || fSeconds || fYears) { if (ISNOT != iArg2Type) { fprintf(stderr,"%s: Extra argument (\"%s\") ignored\n", progname, argv[1]); } } else if (fAdd || fSubtract || fMultipy || fDivide || fCompare) { /* Null */; } else if (ISNOT == iArg2Type) { /* default to add 0 seconds (or a date like tomorrow) */ fAdd = 1; iArg2Type = ISTIME; ttTime = 0; } else { fprintf(stderr,"%s: Unknown operation\n", progname); exit(EX_UNAVAILABLE); } if (fAdd) { /* -a */ if ( !(ISDATE == iArg1Type && ISTIME == iArg2Type) && !(ISTIME == iArg1Type && ISDATE == iArg2Type)) { fprintf(stderr,"%s: A date and a time are required for Addition\n", progname); exit(EX_DATAERR); } if (fVerbose) { printf("Adding %ld to %ld\n", (long)ttTime, (long)ttDate1); } ttTotal = ttDate1 + ttTime; Output(ttTotal); exit(EX_OK); } if (fSubtract) { /* -s */ if ( (ISDATE == iArg1Type && ISTIME == iArg2Type) || (ISTIME == iArg1Type && ISDATE == iArg2Type)) { if (fVerbose) printf("Subtracting %ld from %ld\n", (long)ttTime, (long)ttDate1); ttTotal = ttDate1 - ttTime; Output(ttTotal); } else if ((ISDATE == iArg1Type && ISDATE == iArg2Type)) { if (fVerbose) printf("Subtracting %d from %d\n", (int)ttDate2, (int)ttDate1); ttTotal = ttDate1 - ttDate2; printf("%s\n", SecondsToTime(ttTotal)); } else { fprintf(stderr,"%s: A date and a time, or two dates are required for Subtraction\n", progname); exit(EX_DATAERR); } exit(EX_OK); } if (fMultipy) { /* -m */ if ( !(ISTIME == iArg1Type && ISSCALAR == iArg2Type) && !(ISSCALAR == iArg1Type && ISTIME == iArg2Type)) { fprintf(stderr,"%s: Arguments must be a time and a scalar\n", progname); exit(EX_DATAERR); } if (fVerbose) { printf("Multiplying %ld and %ld\n", (long)ttTime, (long)iScalar); } ttTotal = ttTime * iScalar; printf("%s\n", SecondsToTime(ttTotal)); exit(EX_OK); } if (fDivide) { if ( !(ISTIME == iArg1Type && ISSCALAR == iArg2Type) && !(ISSCALAR == iArg1Type && ISTIME == iArg2Type)) { fprintf(stderr,"%s: Arguments must be a time and a scalar\n", progname); exit(EX_DATAERR); } if (fVerbose) { printf("Dividing %ld and %ld\n", (long)ttTime, (long)iScalar); } ttTotal = ttTime / iScalar; printf("%s\n", SecondsToTime(ttTotal)); exit(EX_OK); } if (fCompare) { if (ISDATE != iArg1Type || ISDATE != iArg2Type) { fprintf(stderr,"%s: Two dates are required for comparison\n", progname); exit(EX_DATAERR); } if (fVerbose) { printf("Comparing %d and %d\n", (int)ttDate1, (int)ttDate2); } if (ttDate1 == ttDate2) { printf("0\n"); } else if (ttDate1 < ttDate2) { printf("-1\n"); } else /* ttDate1 > ttDate2 */ { printf("1\n"); } exit(EX_OK); } if (fUnEpoch) { /* -e */ if (ISSCALAR == iArg1Type) { Output((time_t)iScalar); } else if (ISDATE == iArg1Type) { Output((time_t)ttDate1); } else if (ISTIME == iArg1Type) { Output((time_t)ttTime); } else { fprintf(stderr,"%s: Operation requires a scalar or a time\n", progname); exit(EX_DATAERR); } exit(EX_OK); } if (fEpoch) { /* -p */ if (ISDATE != iArg1Type) { fprintf(stderr,"%s: Operation requires a date\n", progname); exit(EX_DATAERR); } printf("%d\n", (int)ttDate1); exit(EX_OK); } if (fFixedFormat) { /* -f */ if (ISDATE != iArg1Type) { fprintf(stderr, "%s: Operation requires a date\n", progname); exit(EX_DATAERR); } Output(ttDate1); exit(EX_OK); } if (fSeconds) { /* -n */ if (ISTIME != iArg1Type) { fprintf(stderr,"%s: Operation requires a time\n", progname); exit(EX_DATAERR); } printf("%d seconds\n", (int)ttTime); exit(EX_OK); } if (fYears) { /* -y */ if (ISTIME != iArg1Type) { fprintf(stderr,"%s: Operation requires a time\n", progname); exit(EX_DATAERR); } printf("%s\n", SecondsToTime(ttTime)); exit(EX_OK); } /* no output -- let the called decide (exit failure) */ }