mrflash818's C programming stuffI dabble in C-language programming now-and-then. Timediff2010-12-31 I created a program, which was designed to be a command line program to use in things like bash scripts, to calculate the differences between two dates. It uses the combination of a oldest date restriction and the Gregorian Calendar algorithm to provide accurate counts of days between two dates. 2011-01-02 right now the program does not take any other parameters other than two dates. In the future I will code it up to accept the output modifiers and spew the adjusted output. The program uses straight C language program constructs and headers. Here is the C header file, C source code file, and the make file to create it.
/*
* Copyright (c) 2011
* Robert Leyva
*
* timediff.h
*
* Simple, but useful way to quickly determine the difference
* between two A.D. dates as a command line program:
*
* timediff [options] date1 date2
*
* where
*
* dates are in ISO 8601 format ( http://en.wikipedia.org/wiki/ISO_8601 )
* (basically yyyy-mm-dd)
*
* Leap year calculated by constraining date to after 1600AD and
* the algorithm for the Gregorian Calendar from:
* http://en.wikipedia.org/wiki/Leap_year of
*
* if year modulo 400 is 0
* then is_leap_year
* else if year modulo 100 is 0
* then not_leap_year
* else if year modulo 4 is 0
* then is_leap_year
* else
* not_leap_year
*
*
*
* options
* -------------
* specify the units of time between system time and date1, or
* between date1 and date2:
*
* -ms milliseconds
* -s seconds
* -m minutes
* -h hours
* -d days **default**
*
*/
void usage();
typedef struct {
int year;
int month;
int dayOfMonth;
} date_struct;
date_struct ISO8601dateStringConv(char*,int);
void printErrorAndExit(char *);
static int days_in_month[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
date_struct min(date_struct,date_struct);
date_struct max(date_struct,date_struct);
int isLeftDateSmaller(date_struct,date_struct);
long daysBetween(date_struct, date_struct);
date_struct addOneDay(date_struct,int);
int isLeapYear(int year);
const char* PROGRAM_NAME = "timediff";
/*
* Copyright (c) 2011
* Robert Leyva
*
* timediff.c
*
* Simple, but useful way to quickly determine the difference
* between two A.D. dates as a command line program.
*
* Tracks leap year using Gregorian Calendar.
*
* timediff [options] date1 date2
*
* where
*
* dates are in ISO 8601 format ( http://en.wikipedia.org/wiki/ISO_8601 )
* (basically yyyy-mm-dd)
*
* options
* -------------
* specify the units of time between system time and date1, or
* between date1 and date2:
*
* -ms milliseconds
* -s seconds
* -m minutes
* -h hours
* -d days **default**
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "timediff.h"
int main(int argc, char* argv[]) {
// The program needs to be invoked as timediff yyyy-mm-dd yyyy-mm-dd
if(argc != 3) usage();
//1. fetch 1st date
//2. fetch 2nd date
//3. determine the difference, adjust for February when it is a leap year
//4. return the difference in value defaulted or
// specified by modifier
//Determine the lenth of a valid date string, including the required string termination character
const int VALID_DATE_STRING_LENGTH = strlen("yyyy-mm-dd ");
date_struct ds1, ds2;
ds1 = ISO8601dateStringConv(argv[1],VALID_DATE_STRING_LENGTH);
ds2 = ISO8601dateStringConv(argv[2],VALID_DATE_STRING_LENGTH);
long result;
result = daysBetween(ds1,ds2);
printf("%ld",result);
exit(0);
}
// *** end of main ***
void printErrorAndExit(char * message) {
fprintf(stderr, message);
exit(1);
}
date_struct min(date_struct date1, date_struct date2) {
if(date1.year < date2.year) return date1;
if(date2.year < date1.year) return date2;
if(date1.month < date2.month) return date1;
if(date2.month < date1.month) return date2;
if(date1.dayOfMonth < date2.dayOfMonth) return date1;
if(date2.dayOfMonth < date1.dayOfMonth) return date2;
return date2;
}
date_struct max(date_struct date1, date_struct date2) {
if(date1.year > date2.year) return date1;
if(date2.year > date1.year) return date2;
if(date1.month > date2.month) return date1;
if(date2.month > date1.month) return date2;
if(date1.dayOfMonth > date2.dayOfMonth) return date1;
if(date2.dayOfMonth > date1.dayOfMonth) return date2;
return date2;
}
int isLeftDateSmaller(date_struct date1, date_struct date2) {
if(date1.year < date2.year) return 1;
if(date2.year < date1.year) return 0;
if(date1.month < date2.month) return 1;
if(date2.month < date1.month) return 0;
if(date1.dayOfMonth < date2.dayOfMonth) return 1;
if(date2.dayOfMonth > date2.dayOfMonth) return 0;
return 0;
}
int isLeapYear(int year) {
int value;
value = year;
//if year modulo 400 is 0
// then is_leap_year
value = year % 400;
if(value == 0) return 1;
//else if year modulo 100 is 0
// then not_leap_year
value = year % 100;
if(value == 0) return 0;
//else if year modulo 4 is 0
// then is_leap_year
value = year % 4;
if(value == 0) return 1;
//else
// not_leap_year
return 0;
}
date_struct addOneDay(date_struct ds, int isLeapYear){
int daysInMonth;
ds.dayOfMonth++;
//If the month is February test for leap year and adjust daysInMonth
if(ds.month == 2) {
daysInMonth = days_in_month[isLeapYear][ds.month];
} else {
daysInMonth = days_in_month[0][ds.month];
}
if(ds.dayOfMonth > daysInMonth) {
ds.month++;
ds.dayOfMonth = 1;
if(ds.month > 12) {
ds.year += 1;
ds.month = 1;
}
}
return ds;
}
long daysBetween(date_struct date1, date_struct date2){
long result = 0l;
date_struct minDate = min(date1, date2);
date_struct maxDate = max(date1, date2);
date_struct countingDate;
countingDate.year = minDate.year;
countingDate.month = minDate.month;
countingDate.dayOfMonth = minDate.dayOfMonth;
int leapYear = isLeapYear(countingDate.year);
int countingYear = countingDate.year;
while(isLeftDateSmaller(countingDate,maxDate)) {
countingDate = addOneDay(countingDate,leapYear);
//if the year changes while counting, check to see if
//it is a new year
if(countingYear != countingDate.year) {
countingYear = countingDate.year;
leapYear = isLeapYear(countingDate.year);
}
result++;
}
return result;
}
date_struct ISO8601dateStringConv(char* dateString, int VALID_DATE_STRING_LENGTH) {
char STRING_DATE_DELIMITERS[] = {'-','/'};
date_struct result;
char ds[VALID_DATE_STRING_LENGTH];
char * pDs;
int i;
int MIN_YEAR = 1800;
char ERROR_MSG_MISSING_PART[] = "Value must be yyyy-m[m]-d[d]\n";
char ERROR_MSG_BAD_VALUE[] = "Invalid value for year, month, or date\n";
strncpy(ds, dateString,VALID_DATE_STRING_LENGTH);
if (VALID_DATE_STRING_LENGTH > 0)
ds[VALID_DATE_STRING_LENGTH - 1]= '\0';
// get the year
pDs = strtok(ds,STRING_DATE_DELIMITERS);
if(pDs == NULL) printErrorAndExit(ERROR_MSG_MISSING_PART);
i = atoi(pDs);
if(i == NULL || i < 1 || i < MIN_YEAR) printErrorAndExit(ERROR_MSG_BAD_VALUE);
result.year = i;
// get the month
pDs = strtok(NULL,STRING_DATE_DELIMITERS);
if(pDs == NULL) printErrorAndExit(ERROR_MSG_MISSING_PART);
i = atoi(pDs);
if(i == NULL || i < 1) printErrorAndExit(ERROR_MSG_BAD_VALUE);
result.month = i;
// get the day of month
pDs = strtok(NULL,STRING_DATE_DELIMITERS);
if(pDs == NULL) printErrorAndExit(ERROR_MSG_MISSING_PART);
i = atoi(pDs);
if(i == NULL || i < 1) printErrorAndExit(ERROR_MSG_BAD_VALUE);
result.dayOfMonth = i;
return result;
}
/*
* Tell the user how to invoke the program
*/
void usage() {
printf("%s [options] date1 date2 \n",PROGRAM_NAME);
printf("\n");
printf("where \n");
printf("\n");
printf("dates are in ISO 8601 format and are after 1800 A.D. \n");
printf("(http://en.wikipedia.org/wiki/ISO_8601) \n");
printf("(basically yyyy-mm-dd) \n");
printf("\n");
printf("options \n");
printf("------------- \n");
printf("The units of time between date1 and date2: \n");
printf(" -ms milliseconds \n");
printf(" -s seconds \n");
printf(" -m minutes \n");
printf(" -h hours \n");
printf(" -d days **default** \n");
printf("\n");
exit(1);
}
#
# timediff Makefile
#
PROGRAM_NAME=timediff
program: ${PROGRAM_NAME}
gcc -g -Wall timediff.h timediff.c -o ${PROGRAM_NAME}
clean:
rm -f *.o ${PROGRAM_NAME}
|