/* ------------------------------------------------------------------------ History ------------------------------------------------------------------------ */ /* dcalc - date calculator */ /* ------------------------------------------------------------------------ Include Files ------------------------------------------------------------------------ */ #include #include #include #include /* ------------------------------------------------------------------------ Defines ------------------------------------------------------------------------ */ #define VERSION_STR "dcalc 0.9" #define TIME_LEN 64 /* ------------------------------------------------------------------------ DEBUGGING MACROS ------------------------------------------------------------------------ */ #define WRITEMSG \ printf ("File %s line %d: ", __FILE__, __LINE__); \ printf ("errmsg <%s>\n", strerror(errno)); fflush(stdout); #define WRITEVAR(VAL,FMT) \ printf ("File %s line %d: ", __FILE__, __LINE__); \ printf ("%s=",#VAL); printf (#FMT, VAL); printf ("\n"); \ fflush(stdout); /* ------------------------------------------------------------------------ Macros ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ Typedefs ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ Global Variables ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ Module Wide Variables ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ Local Function Prototypes ------------------------------------------------------------------------ */ void Usage(void); long tomin (char *); long date2nmin (int year, int month, int day, int hour, int min); void nmin2date (int *, int *, int *, int *, int *, long); /* ------------------------------------------------------------------------ Main ------------------------------------------------------------------------ */ int main (int argc, char *argv[]) { char optchar; int nopt=0; int nscan=0; char *time_increment = NULL; char *rounding_time = NULL; char *initial_time = NULL; int year, month, day, hour, min; long current_time = 0; while (-1 != (optchar=getopt(argc,argv,"d:hi:r:t:v"))) { nopt++; switch (optchar) { case '?': return 1; case 'h': Usage(); return 0; case 'v': printf ("%s (compiled %s)\n", VERSION_STR, __DATE__); return 0; case 'i': time_increment = strdup(optarg); break; case 'r': rounding_time = strdup(optarg); break; default: return 1; } } /* Check for required args */ if (optind>=argc) { Usage(); return 1; } initial_time = strdup(argv[optind]); /* Read input time */ if (initial_time) { nscan = sscanf (initial_time, "%d-%d-%d-%d:%d", &year, &month, &day, &hour, &min); if (nscan<3) { perror ("Initial time is in unrecognized format\n"); exit (1); } else if (nscan<5) { nscan = sscanf (initial_time, "%d-%d-%d", &year, &month, &day); hour = min = 0; } current_time = date2nmin (year, month, day, hour, min); } /* Round time */ if (rounding_time) current_time -= current_time % tomin(rounding_time); /* Increment time */ if (time_increment) current_time += tomin(time_increment); /* Print time */ nmin2date (&year, &month, &day, &hour, &min, current_time); printf ("%4d-%02d-%02d-%02d:%02d\n", year, month, day, hour, min); /* All done */ return 0; } /* ------------------------------------------------------------------------ Functions ------------------------------------------------------------------------ */ /* Convert strings of form 10s, 21m, 102h, 7d to seconds where letters smhd denote seconds, minutes, hours, days */ long tomin (char *timestr) { int length = strlen(timestr); int unitchar = tolower (timestr[length-1]); long unit; long time; switch (unitchar) { case 'd': unit = 60*24; break; case 'h': unit = 60; break; case 'm': unit = 1; break; default: perror ("Invalid time unit\n"); exit(1); } return unit * atol(timestr); } void Usage (void) { printf("\n"); printf(" dcalc [-hfiv] \n"); printf("\n"); printf(" Increment and round date/times\n"); printf("\n"); printf(" -h Print help.\n"); printf(" -i Adds (negative) increment to time.\n"); printf(" Append letter s,m,h,d for to use units of\n"); printf(" seconds, minutes, hours or days.\n"); printf(" -r Round time to previous interval using same\n"); printf(" units as above. This is done before\n"); printf(" increment is added. For example, if\n"); printf(" time is 12:41, the '-r 30min' option would\n"); printf(" round the time to 12:30\n"); printf(" -v Print version.\n"); printf("\n"); printf(" is in format yyyy-mm-dd or yyyy-mm-dd-hh:mm\n"); printf("\n"); exit(0); } /* Need this because Linux time routines give screwed up time when DST changes to Standard time. GNU date does it right but it is not ported to all systems. ..sigh... :( */ int dayofyear_for_month[12] = {0,31,59,90,120,151,181,212,243,273,304,334}; /* Calculate days since Jan 1, 1900 (day 0) */ long date2nmin (int year, int month, int day, int hour, int min) { long nday; int nyear, lyear, dayofyear; if (month<0 || month>12) { fprintf (stderr, "nday: month (%d) out of range (1-12)\n", month); exit(1); } nyear = year - 1900; /* Previous leep years */ lyear = (year - 1904)/4; if (lyear<0) lyear=0; dayofyear = dayofyear_for_month[month-1]; /* This leap year */ if (year%4==0 && dayofyear > 59) lyear++; nday = nyear*365 + lyear + dayofyear + day-1; return 24*60*nday + 60*hour + min; } /* Given days since Jan 1, 1900, calculate date */ void nmin2date (int *year, int *month, int *day, int *hour, int *min, long nmin) { int test_year, test_month, test_day; int year1_nmin, year2_nmin, month1_nmin, month2_nmin; long nday; nday = nmin / 60 / 24; /* First guess at year */ test_year = 1900+nmin/60/24/365; /* Find component of nmin for previous years */ do { year1_nmin = date2nmin (test_year, 1, 1, 0, 0); year2_nmin = date2nmin (test_year+1, 1, 1, 0, 0); if (year1_nmin>nmin) test_year--; else if (nmin>=year2_nmin) test_year++; } while (year1_nmin > nmin || nmin>=year2_nmin); /* Find component of nmin for previous months in year */ test_month = (nmin-year1_nmin)/60/24/30 + 1; if (test_month<12) { do { month1_nmin = date2nmin (test_year, test_month, 1, 0, 0); month2_nmin = date2nmin (test_year, test_month+1, 1, 0, 0); if (month1_nmin > nmin) test_month--; else if (nmin >= month2_nmin) test_month++; } while ( (month1_nmin > nmin || nmin >= month2_nmin) && test_month>0 && test_month<12); test_day = (nmin-month1_nmin)/24/60+1; } *year = test_year; *month = test_month; *day = test_day; *hour = nmin/60 - nday*24; *min = nmin % 60; }