Datareign

Date Arithmetic

I wrote this for a particular case where I needed to find out the number of seconds batch jobs had run for. The jobs produced logs which had the start and stop times in the format…

CCYYMMDDhhmmss

…so at least the conversions were straightforward, as can be seen from the code.

/* -----------------------------------------------------
      Name: datesub 
   Purpose: See ShowHelp() function for full description 
   -------------------------------------------------- */ 
 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
 
#define DATELENGTH 14 
 
/* ---------------------- 
   Function Prototypes... 
   ------------------- */ 
long ConvertToCalendarTime(char *SourceDate); 
int GetTwoDigits(char* SourceString, int StartFrom); 
void ShowHelp(); 
void FormatAsDayHourMinuteSecond(long NumberOfSeconds);
 
/* ================================================== 
   The main function controls the entire programme... 
   =============================================== */ 
int main (int argc, char **argv) 
{ 
  char Mode; 
  char FirstDate[DATELENGTH + 1]; 
  char SecondDate[DATELENGTH + 1]; 
  long FirstDateInSeconds; 
  long SecondDateInSeconds; 
  long ResultInSeconds; 
  char FormattedResult[14]; 
 
  /* ----------------------------- 
     Is the user looking for help? 
     -------------------------- */ 
  if ( (argc == 1 ) || (*argv[1] == '?')) 
  { 
    ShowHelp(); 
    return -1; 
  } 
 
  /* --------------------------------------------------- 
     If there are the wrong number of arguments, fail... 
     ------------------------------------------------ */ 
  if ( argc != 4 ) 
  { 
    printf("\nWRONG NUMBER OF PARAMETERS!\n"); 
    ShowHelp(); 
    return -1; 
  } 
 
  /* ---------------------------------------------- 
     Extract the arguments from the command line... 
     ------------------------------------------- */ 
  Mode = *argv[1]; 
  sprintf(FirstDate, "%s", argv[2]); 
  sprintf(SecondDate, "%s", argv[3]); 
 
  /* ------------------------------- 
     If the mode is invalid, fail... 
     ---------------------------- */ 
  if ((Mode != 's') && (Mode != 'f')) 
  { 
    printf("\nINVALID MODE SETTING!\n"); 
    ShowHelp(); 
    return -1; 
  } 
 
  /* ------------------------------------------------------------------- 
     Convert the first and second dates to seconds since Jan 1st 1970... 
     ---------------------------------------------------------------- */ 
  FirstDateInSeconds = ConvertToCalendarTime(FirstDate); 
  SecondDateInSeconds = ConvertToCalendarTime(SecondDate); 
 
  /* ------------------------------ 
     Do the required calculation... 
     --------------------------- */ 
  ResultInSeconds = FirstDateInSeconds - SecondDateInSeconds; 
 
  /* ---------------- 
     Are we finished? 
     ------------- */ 
  if (Mode == 's') 
  { 
    printf("%d\n", ResultInSeconds); 
    exit(0); 
  } 
 
  /* ----------------------------------- 
     Still here, so format the output... 
     -------------------------------- */ 
  FormatAsDayHourMinuteSecond(ResultInSeconds); 
  exit(0); 
} 
 
/* =========================================== 
   Function converts the date passed into
   the number of seconds since Jan 1st 1970... 
   ======================================== */ 
long ConvertToCalendarTime(char *SourceDate) 
{ 
  int Century, Year, Month, Day, Hour, Minute, Second; 
  int TotalYears; 
  int ThisYear; 
  long CalenderTime = 0; 
 
  Century = GetTwoDigits(SourceDate, 0); 
  Year = GetTwoDigits(SourceDate, 2); 
  Month = GetTwoDigits(SourceDate, 4); 
  Day = GetTwoDigits(SourceDate, 6); 
  Hour = GetTwoDigits(SourceDate, 8); 
  Minute = GetTwoDigits(SourceDate, 10); 
  Second = GetTwoDigits(SourceDate, 12); 
 
  /* ---------------------------------------------------------- 
     Calculate the number of seconds in the years since 1970... 
     ------------------------------------------------------- */ 
  TotalYears = ((Century * 100) + Year); 
  for( ThisYear = 1970; ThisYear < TotalYears; ThisYear++ )
    if( (ThisYear % 4) == 0) 
      CalenderTime = CalenderTime + 31622400; 
    else 
      CalenderTime = CalenderTime + 31536000; 
 
  /* ------------------------------------------------------ 
     Add in the number of seconds for the months this year.
     There are lots of 'clever' ways of doing this but why
     not make it crystal clear what's going on?
 
     To this end, I've used a case statement, which hard
     codes the number of seconds by month, with alternative
     values for leap years and non-leap years... 
     --------------------------------------------------- */ 
  switch (Month) 
  { 
    case 1: break; 
    case 2: CalenderTime = CalenderTime + 2678400; 
            break; 
    case 3: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 5184000; 
            else 
              CalenderTime = CalenderTime + 5097600; 
            break; 
    case 4: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 7862400; 
            else 
              CalenderTime = CalenderTime + 7776000; 
            break; 
    case 5: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 10454400; 
            else 
              CalenderTime = CalenderTime + 10368000; 
            break; 
    case 6: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 13132800; 
            else 
              CalenderTime = CalenderTime + 13046400; 
            break; 
    case 7: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 15724800; 
            else 
              CalenderTime = CalenderTime + 15638400; 
            break; 
    case 8: if((TotalYears %4) == 0) 
              CalenderTime = CalenderTime + 18403200; 
            else 
              CalenderTime = CalenderTime + 18316800; 
            break; 
    case 9: if((TotalYears %4) == 0) 
               CalenderTime = CalenderTime + 21081600; 
            else 
              CalenderTime = CalenderTime + 20995200; 
            break; 
    case 10: if((TotalYears %4) == 0) 
               CalenderTime = CalenderTime + 23673600; 
             else 
               CalenderTime = CalenderTime + 23587200; 
             break; 
    case 11: if((TotalYears %4) == 0) 
               CalenderTime = CalenderTime + 26352000; 
             else 
               CalenderTime = CalenderTime + 26265600; 
             break;
    case 12: if((TotalYears %4) == 0) 
               CalenderTime = CalenderTime + 28944000; 
             else 
               CalenderTime = CalenderTime + 28857600; 
             break; 
    default: printf("\nINVALID MONTH VALUE!\n"); 
             ShowHelp();
             exit (-1); 
  } 
 
  /* ------------------------------------------------------ 
     Add in the number of seconds in the days this month... 
     --------------------------------------------------- */ 
  CalenderTime = CalenderTime + (Day - 1) * 86400; 
 
  /* ----------------------------------------- 
     Add in the seconds for the hours today... 
     -------------------------------------- */ 
  CalenderTime = CalenderTime + (Hour - 1) * 3600; 
 
  /* -------------------------------------------------- 
     Add in the seconds for the minutes in this hour... 
     ----------------------------------------------- */ 
  CalenderTime = CalenderTime + (Minute - 1) * 60; 
 
  /* -------------------------- 
     And finally the seconds... 
     ----------------------- */ 
  CalenderTime = CalenderTime + Second; 
  return (CalenderTime); 
} 
 
/* ============================================================ 
   Function extracts two digits from the supplied source string
   and returns them as an integer... 
    ========================================================= */ 
int GetTwoDigits(char* SourceString, int StartFrom) 
{ 
  char TargetString[3]; 
 
  TargetString[0] = SourceString[StartFrom]; 
  TargetString[1] = SourceString[StartFrom + 1]; 
  TargetString[2] = '\0'; 
 
  return(atoi(TargetString)); 
} 
 
/* =================================================================== 
   Function provides an explanation of what this filter does (help)... 
   ================================================================ */ 
void ShowHelp() 
{ 
  printf("\nThis filter subtracts one date from another and returns the result\n")
  printf("either as seconds or as a formatted string.\n"); 
  printf("\n"); 
  printf("The first parameter is the operation which may be..."); 
  printf("\n"); 
  printf(" <s> result is to be in seconds\n"); 
  printf(" <f> format result as days, hours, minutes and seconds (DD:HH:MM:SS)\n"); 
  printf("\n"); 
  printf("The second and third parameters are the dates to be processed\n"); 
  printf("in the format CCYYMMDDHHMMSS\n"); 
  printf("\n"); 
  printf("example usage: datesub s 20010817105823 20010816113402 \n"); 
} 
 
/* ======================================================================= 
   Function accepts a number of seconds and formats them as dd:hh:mm:ss... 
   ==================================================================== */ 
void FormatAsDayHourMinuteSecond(long NumberOfSeconds) 
{ 
  int Days, Hours, Minutes, Seconds; 
  long Remainder; 
  char ResultString[14]; 
 
  Days = NumberOfSeconds / 86400; 
  Remainder = NumberOfSeconds % 86400; 
  Hours = Remainder / 3600; 
  Remainder = Remainder % 3600; 
  Minutes = Remainder / 60; 
  Seconds = Remainder % 60; 
 
  printf("%02d:%02d:%02d:%02d\n", Days, Hours, Minutes, Seconds); 
} 
 
/* ======================================================================= 
   END END END END END END END END END END END END END END END END END END 
   ==================================================================== */
Last modified: 2009/04/05 09:38