fork download
  1. // -------------------------------------------------------------------------------
  2. // DATES ver 3.0 <mig_f1@hotmail.com>
  3. // a sample program in ANSI C performing calculations between two Gregorian dates:
  4. // difference in days and in (d,m,y) form, weekday & leap years indicators
  5. // jdn conversions, +/- days arithmetic, monthly calendars display
  6. // -------------------------------------------------------------------------------
  7. // migf1, Athens 2011 * use at your own risk * free for whatever use * give credit
  8. // -------------------------------------------------------------------------------
  9. // external alogorithms:
  10. // http://w...content-available-to-author-only...t.com/KB/datetime/DateDurationCalculation1.aspx
  11. // http://w...content-available-to-author-only...c.ch/cal_stud/jdn.htm#comp
  12.  
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #include <ctype.h>
  18. #include <stdlib.h>
  19.  
  20. #define MAX_INBUF 255+1 // for our input buffer
  21. #define INVALID -1 // just a flag for invalid d,m,y
  22.  
  23. #define validday(d) ( (d) > 0 && (d) < 32 ) // 1st validity check for days
  24. #define validmonth(m) ( (m) > 0 && (m) < 13 ) // 1st validity check for months
  25. #define validyear(y) ( (y) > 1751 && (y) < 10000 ) // 1st validity check for years
  26.  
  27. #define isleap(y) ( !((y) % 4) && ( (y) % 100 || !((y) % 400) ) )
  28.  
  29. #define myabs(x) ( (x) < 0 ? -(x) : (x) ) // absolute value
  30.  
  31. typedef enum bool { FALSE=0, TRUE } bool; // our custom boolean type
  32. enum { JAN=1, FEB }; // just two month constants
  33. enum { ID1=1, ID2 }; // to identify 1st and 2nd dates
  34.  
  35. typedef struct Date { // our date structure
  36. long d; // 1-31
  37. long m; // 1-12
  38. long y; // 1752-9999
  39. } Date;
  40.  
  41. // ------------------------------------------------------------------------------------
  42. // Read s from stdin until either len chars have been typed or ENTER has been hit,
  43. // and null-terminate s (if ENTER was there, it is replaced).
  44. // Return the null-terminated s
  45. //
  46. char *s_get(char *s, size_t len)
  47. {
  48. char *cp;
  49. for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
  50. ; // for-loop with empty body
  51. *cp = '\0'; // null-terminate last character
  52.  
  53. return s;
  54. }
  55.  
  56. // ------------------------------------------------------------------------------------
  57. // Trim leading & trailing blanks from string s, pad it with '\0's and return it
  58. // (or NULL on error)
  59. //
  60. char *s_trim(char *s)
  61. {
  62. if ( !s || !*s ) // error, early exit
  63. return NULL;
  64.  
  65. char *cp1; // for parsing the whole s
  66. char *cp2; // for shifting & padding
  67.  
  68. // trim leading & shift left remaining
  69. for (cp1=s; isblank((int)*cp1); cp1++ ) // skip leading blanks, via cp1
  70. ;
  71. for (cp2=s; *cp1; cp1++, cp2++) // shift-left remaining chars, via cp2
  72. *cp2 = *cp1;
  73. *cp2-- = '\0'; // mark end of left trimmed s
  74.  
  75. // replace trailing blanks with '\0's
  76. while ( cp2 > s && isblank((int)*cp2) )
  77. *cp2-- = '\0'; // pad with '\0'
  78.  
  79. return s;
  80. }
  81.  
  82. // ------------------------------------------------------------------------------------
  83. // remove from string s any char contained in string del (return the modified string s)
  84. char *s_strip(char *s, const char *del)
  85. {
  86. if ( !s || !*s)
  87. return NULL;
  88.  
  89. char *cp1; // for parsing the whole s
  90. char *cp2; // for keeping desired *cp1's
  91.  
  92. for (cp1=s, cp2=s; *cp1; cp1++ )
  93. if ( !strchr(del, *cp1) ) // *cp1 is NOT contained in del
  94. *cp2++ = *cp1; // copy it to start of s, via cp2
  95. *cp2 = 0; // null terminate the trimmed s
  96.  
  97. return s;
  98. }
  99.  
  100. // ------------------------------------------------------------------------------------
  101. char *s_ncopy( char *dst, const char *src, int n )
  102. {
  103. char *ret = dst;
  104.  
  105. while ( (dst-ret) < n-1 && (*dst=*src) != '\0' )
  106. dst++, src++;
  107.  
  108. if ( *dst )
  109. *dst = 0;
  110.  
  111. return ret;
  112. }
  113.  
  114. // ------------------------------------------------------------------------------------
  115. // Convert s to lowercase and return it (or NULL on error)
  116. //
  117. char *s_tolower( char *s )
  118. {
  119. if ( !s ) // error, early exit
  120. return NULL;
  121.  
  122. char *ret;
  123. for ( ret=s; (*s=tolower(*s)); s++ )
  124. ;
  125. return ret;
  126. }
  127.  
  128. // ------------------------------------------------------------------------------------
  129. // break a string up to maxtokens tokens and store them in *tokens[]
  130. // (uses " " as the delimeter string)
  131. // returns the number of tokens, or 0 on failure
  132. // ------------------------------------------------------------------------------------
  133.  
  134. int s_tokenize(char *s, char *tokens[], int maxtokens, char *delimiters)
  135. {
  136. if ( !s || !*s || !tokens || !maxtokens || !delimiters || !*delimiters )
  137. return 0;
  138.  
  139. register int i=0;
  140.  
  141. tokens[0] = strtok(s, delimiters);
  142. if (tokens[0] == NULL)
  143. return 0;
  144. for (i=1; i < maxtokens && (tokens[i]=strtok(NULL, delimiters)) != NULL; i++);
  145.  
  146. return i;
  147. }
  148.  
  149. // ------------------------------------------------------------------------------------
  150. // Convert a Gregorian date to a Julian Day count
  151. // IMPORTANT: accurate ONLY for dates after Oct 15, 1582 (Gregorian Calendar)
  152. // Algorithm by Henry F. Fliegel & Thomas C. Van Flandern:
  153. // http://w...content-available-to-author-only...c.ch/cal_stud/jdn.htm#comp
  154. //
  155. long date_2jdn( Date date )
  156. {
  157. return
  158. ( 1461 * ( date.y + 4800 + ( date.m - 14 ) / 12 ) ) / 4 +
  159. ( 367 * ( date.m - 2 - 12 * ( ( date.m - 14 ) / 12 ) ) ) / 12 -
  160. ( 3 * ( ( date.y + 4900 + ( date.m - 14 ) / 12 ) / 100 ) ) / 4 +
  161. date.d - 32075;
  162.  
  163. }
  164.  
  165. // ----------------------------------------------------------------------------------
  166. // Convert a Julian Day count to a Gregorian date (d,m,y)
  167. // IMPORTANT: accurate ONLY for dates after Oct 15, 1582 (Gregorian Calendar)
  168. // Algorithm by Henry F. Fliegel & Thomas C. Van Flandern:
  169. // http://w...content-available-to-author-only...c.ch/cal_stud/jdn.htm#comp
  170. //
  171. Date *jdn_2date( Date *date, long jd )
  172. {
  173. long l = jd + 68569;
  174. long n = ( 4 * l ) / 146097;
  175. l = l - ( 146097 * n + 3 ) / 4;
  176. long i = ( 4000 * ( l + 1 ) ) / 1461001;
  177. l = l - ( 1461 * i ) / 4 + 31;
  178. long j = ( 80 * l ) / 2447;
  179. date->d = l - ( 2447 * j ) / 80;
  180. l = j / 11;
  181. date->m = j + 2 - ( 12 * l );
  182. date->y = 100 * ( n - 49 ) + i + l;
  183.  
  184. return date;
  185. }
  186.  
  187. // ------------------------------------------------------------------------------------
  188. // Convert Gregorian date to weekday (valid from Sep 14, 1752 to Dec 31, 9999)
  189. // Return 0 to 6 (Mon to Sun)
  190. //
  191. int date_2weekday( Date date )
  192. {
  193. return date_2jdn(date) % 7; // return jdn % 7
  194. }
  195.  
  196. // ------------------------------------------------------------------------------------
  197. // Calc the difference between date1 and date2 and RETURN it expressed as # of days.
  198. // IMPORTANT:,
  199. // the difference is also calc'ed as days, months, years and passed into datediff
  200. // Algorithm by Mohammed Ali Babu
  201. // http://w...content-available-to-author-only...t.com/KB/datetime/DateDurationCalculation1.aspx
  202. //
  203. long date_diff( Date *datediff, Date date1, Date date2, int mdays[] )
  204. {
  205. if ( !datediff )
  206. return -1;
  207.  
  208. long int jdn1 = date_2jdn( date1 ); // calc jd of date1
  209. long int jdn2 = date_2jdn( date2 ); // calc jd of date2
  210. Date *dp2 = (jdn2 > jdn1) ? &date2 : &date1; // dp2 points to latest date
  211. Date *dp1 = (dp2 == &date1) ? &date2 : &date1; // dp1 points to earliest date
  212.  
  213. /*
  214. * the following alogorithm is published by Mohammed Ali Babu at:
  215. * http://w...content-available-to-author-only...t.com/KB/datetime/DateDurationCalculation1.aspx
  216. */
  217.  
  218. // first calc the difference of the day part
  219. int increment = 0;
  220. if ( dp1->d > dp2->d )
  221. increment = mdays[ dp1->m - 1 ];
  222.  
  223. if (increment == -1)
  224. {
  225. if ( isleap( dp1->y ) )
  226. increment = 29;
  227. else
  228. increment = 28;
  229. }
  230.  
  231. if (increment != 0)
  232. {
  233. datediff->d = (dp2->d + increment) - dp1->d;
  234. increment = 1;
  235. }
  236. else
  237. datediff->d = dp2->d - dp1->d;
  238.  
  239. // then calc the difference of the month part
  240. if ( (dp1->m + increment) > dp2->m )
  241. {
  242. datediff->m = (dp2->m + 12) - (dp1->m + increment);
  243. increment = 1;
  244. }
  245. else {
  246. datediff->m = dp2->m - (dp1->m + increment);
  247. increment = 0;
  248. }
  249.  
  250. // and last calculate the difference of the year part
  251. datediff->y = dp2->y - (dp1->y + increment);
  252.  
  253.  
  254. return myabs( jdn2-jdn1 );
  255. }
  256.  
  257. // ------------------------------------------------------------------------------------
  258. // Add ndays to basedate and Return the result into date (ndays can be negative)
  259. // (calstart and calend are used for boundary checking)
  260. //
  261. Date *date_plusdays( Date *date, Date basedate, long ndays, Date calstart, Date calend )
  262. {
  263. long jstart = date_2jdn( calstart ); // julian day of our calendar start date
  264. long jend = date_2jdn( calend ); // julian day of our calendar end date
  265. long jd = date_2jdn( basedate ); // julian day of basedate
  266.  
  267. if ( jd+ndays > jend ) // fix overflow (calend)
  268. return jdn_2date( date, jend );
  269.  
  270. if ( jd+ndays < jstart ) // fix underflow (calstart)
  271. return jdn_2date( date, jstart );
  272.  
  273. return jdn_2date( date, jd+ndays );
  274. }
  275.  
  276. // ------------------------------------------------------------------------------------
  277. // Convert string inbuf into a valid signed long int, store it in date->d
  278. // Return FALSE on failure
  279. //
  280. bool date_getoperation( Date *date, char *inbuf )
  281. {
  282. if ( !inbuf || !*inbuf || (*inbuf != '+' && *inbuf != '-') )
  283. return FALSE;
  284.  
  285. char *tail; // in strtol() for err checking
  286.  
  287. errno = 0;
  288. date->m = date->y = INVALID;
  289.  
  290. s_strip(inbuf, " \t\v"); // strip off blanks from inbuf
  291.  
  292. date->d = strtol(inbuf, &tail, 10); // convert inbuf to long
  293. if ( *tail != '\0' || errno == ERANGE )
  294. {
  295. puts("\t*** error: invalid operation");
  296. date->d = INVALID;
  297. return FALSE;
  298. }
  299.  
  300. return TRUE;
  301. }
  302.  
  303. // ------------------------------------------------------------------------------------
  304. // If string inbuf contains any of our recognized mnemonics, date is set accordingly
  305. // and the function returns TRUE (otherwise it returns FALSE).
  306. //
  307. bool date_getmnemonic( Date *date, char *inbuf, const Date calstart, const Date calend )
  308. {
  309. if ( !inbuf || !*inbuf ) // inbuf is either non-existant or empty
  310. return FALSE; // early exit
  311.  
  312. time_t today = time( NULL ); // get system time
  313. struct tm *tmtoday = localtime( &today );// convert it to a tm structure
  314. long jstart = date_2jdn( calstart ); // julian day of our calendar start date
  315. long jend = date_2jdn( calend ); // julian day of our calendar end date
  316. long jtoday;
  317. Date caltoday;
  318.  
  319. caltoday.d = (long) tmtoday->tm_mday;
  320. caltoday.m = (long) tmtoday->tm_mon + 1;
  321. caltoday.y = (long) tmtoday->tm_year + 1900;
  322. jtoday = date_2jdn( caltoday );
  323.  
  324. if ( !strcmp( inbuf, "start") ) {
  325. jdn_2date( date, jstart );
  326. return TRUE;
  327. }
  328. if ( !strcmp( inbuf, "yesterday") ) {
  329. // jdn_2date( date, jtoday-1 ); // faster but no boundary checking
  330. date_plusdays( date, caltoday, -1, calstart, calend);
  331. return TRUE;
  332. }
  333. if ( !strcmp( inbuf, "today") ) {
  334. jdn_2date( date, jtoday );
  335. return TRUE;
  336. }
  337. if ( !strcmp( inbuf, "tomorrow") ) {
  338. // jdn_2date( date, jtoday+1 ); // faster but no boundary checking
  339. date_plusdays( date, caltoday, +1, calstart, calend);
  340. return TRUE;
  341. }
  342. if ( !strcmp( inbuf, "end") ) {
  343. jdn_2date( date, jend );
  344. return TRUE;
  345. }
  346.  
  347. return FALSE;
  348. }
  349.  
  350. // ------------------------------------------------------------------------------------
  351. // Read a Gregorian date as a string form stdin, validate it & return it inside *date
  352. // IMPORTANT:
  353. //
  354. // The function returns TRUE if the input string is a valid operation (i.e "-200" )
  355. // instead of a valid date string (i.e. "1/1/2000" ). In that case, date->d
  356. // is assigned the numeric value of the operation ( -200 for the above example )
  357. // while date->m and date->y are assined the value -1 ( INVALID ).
  358. //
  359. // Only the second date is allowed to accept an operation string, so we use
  360. // the parameter 'id' in order to know whether we're dealing with date1 or
  361. // date2 in here.
  362. //
  363. // Since in case of a valid operation in the input, the returned date does NOT
  364. // hold a valid date, further processing needs to be done in the main() function,
  365. // to ensure that date2 is properly converted to a valid date, equalling to:
  366. // date1 + date2.d, before attempting to do anything else with it (e.g. printing
  367. // it)
  368. //
  369. //
  370. bool date_askuser( int id, char *prompt, Date *date,
  371. int max_inbuf, int mdays[], Date calstart, Date calend )
  372. {
  373. if ( !prompt || !date) // inbuf does not exist or it is empty
  374. return FALSE;
  375.  
  376. char inbuf[ max_inbuf ]; // for reading the user input
  377. char *stokens[3]; // to read d, m, y as strings
  378. char *tail; // in strtol() for err checking
  379. long jdn; // for converting date to jdn
  380. bool stop = TRUE; // for controlling the main loop
  381. bool operated = FALSE; // got a date or an operation?
  382.  
  383. do
  384. {
  385. stop = TRUE; // reset boolean flag to TRUE
  386. operated = FALSE; // reset boolean flag to FALSE
  387.  
  388. // prompt and get user input
  389. printf( prompt ); // ask for input
  390. fflush(stdin); // clear input buffer (stdin)
  391. s_get(inbuf, max_inbuf); // read input as string in inbuf
  392. s_trim( s_tolower(inbuf) ); // trim leading & trailng blanks
  393.  
  394. // check if user typed just an ENTER
  395. if ( !*inbuf )
  396. continue; // stop = TRUE
  397.  
  398. // check if user typed an operation (+/-) followed by a number
  399. if ( id == ID1 && (*inbuf =='+' || *inbuf == '-') ) {
  400. puts("\t*** error: operations only allowed in the 2nd date");
  401. stop = FALSE;
  402. continue;
  403. }
  404. if ( date_getoperation(date, inbuf) ) {
  405. operated = TRUE;
  406. continue; // stop = TRUE
  407. }
  408.  
  409. // check if user typed any of our mnemonic strings
  410. if ( date_getmnemonic( date, inbuf, calstart, calend ) ) {
  411. stop = TRUE;
  412. continue;
  413. }
  414.  
  415. // split inbuf in up to 3 strings (tokens) assuming d, m, y
  416. if ( s_tokenize( inbuf, stokens, 3, " /,.;:\t") != 3 ) {
  417. puts("\t*** error: invalid date");
  418. stop = FALSE;
  419. continue;
  420. }
  421.  
  422. // demand from user to type a day between 1-31
  423. errno = 0; // reset golbal var errno
  424. date->d = strtol(stokens[0], &tail, 10);// convert str day to long
  425. if ( !validday(date->d) || *tail != '\0' || errno == ERANGE )
  426. {
  427. puts("\t*** error: valid days are 1-31");
  428. date->d = INVALID;
  429. stop = FALSE;
  430. continue;
  431. }
  432.  
  433. // demand from user to type a month between 1-12
  434. errno = 0; // reset golbal var errno
  435. date->m = strtol(stokens[1], &tail, 10);// convert str month to long
  436. if ( *tail != '\0' || errno == ERANGE || !validmonth(date->m) )
  437. {
  438. puts("\t*** error: valid months are 1-12");
  439. date->m = INVALID;
  440. stop = FALSE;
  441. continue;
  442. }
  443.  
  444. // demand from user to type a year between 1752-9999
  445. errno = 0; // reset golbal errno
  446. date->y = strtol(stokens[2], &tail, 10);// convert str year to long
  447. if ( *tail != '\0' || errno == ERANGE || !validyear(date->y) )
  448. {
  449. puts("\t*** error: valid years are 1752-9999");
  450. date->y = INVALID;
  451. stop = FALSE;
  452. continue;
  453. }
  454.  
  455. /* now we have a complete date (d,m,y) but this
  456. * does not gurantee us that it is a valid one
  457. * (e.g. 29/2/2000 is valid, but 29/2/2001 is not)
  458. * (also, e.g. 31/4 is invalid, an so on)
  459. */
  460.  
  461. // ensure day lyes inside the month boundary of the typed date
  462. if ( date->d > mdays[ date->m - 1 ] )
  463. {
  464. if ( date->d == 29 && date->m == FEB && isleap( date->y ) )
  465. continue; // stop = TRUE
  466.  
  467. date->d = date->m = date->y = INVALID;
  468. puts("\t*** error: invalid day");
  469. stop = FALSE;
  470. continue;
  471. }
  472.  
  473. // ensure date is between 14/9/1752 and 31/12/9999
  474. jdn = date_2jdn( *date ); // convert date to day
  475. if ( date_2jdn(calstart) > jdn || jdn > date_2jdn(calend) )
  476. {
  477. date->d = date->m = date->y = INVALID;
  478. puts("\t*** error: valid dates are 14/9/1752 - 31/12/9999");
  479. stop = FALSE;
  480. continue;
  481. }
  482.  
  483. } while( !stop || !*inbuf );
  484.  
  485. return operated;
  486. }
  487.  
  488. // ------------------------------------------------------------------------------------
  489. void print_help( void )
  490. {
  491. printf("\n\n%70s\n", "<mig_f1@hotmail.com>\n");
  492. puts("A sample program performing various calculations between two dates in \nthe time interval: 14/9/1752 to 31/12/9999 (results never exceed it).\n\nEach date input is checked in real time against both syntax & logical\nerrors. It can be in one of the following formats...\n-\td/m/y\t\t: other separators: :,.; and tab\n-\ta signed number\t: e.g. -200 (subtract 200 days from 1st Date)\n-\tstart\t\t: equals to 14/9/1752\n-\tyesterday\t: equals to yesterday's date\n-\ttoday\t\t: equals to today's date\n-\ttomorrow\t: equals to tomorrow's date\n-\tend\t\t: equals to 31/12/9999\n\nThe calculated results include...\n-\tdifference expressed in days\n-\tdifference expressed in days, months, years\n-\tweekday indication\n-\tJulian Day Number indication\n-\tleap year indication\n-\tmonthly calendar of both dates (or 1st only, if same with 2nd)");
  493.  
  494. return;
  495. }
  496.  
  497. // ------------------------------------------------------------------------------------
  498. // Print date in the form: MONTH DAY YEAR, Weekday (jdn) (is leap year ?)
  499. //
  500. void print_date(Date date, int id, char *mnames[], char *dnames[] )
  501. {
  502. if ( !validday( date.d ) || !validmonth( date.m ) || !validyear( date.y ) )
  503. return;
  504.  
  505. printf( "\t%d. %s %02ld %04ld, %-09s (jdn: %ld) %s\n",
  506. id,
  507. mnames[ (int)(date.m)-1 ],
  508. date.d, date.y, dnames[ date_2weekday(date) ],
  509. date_2jdn( date ),
  510. isleap( date.y ) ? "\t(leap year)" : ""
  511. );
  512.  
  513. return;
  514. }
  515.  
  516. // ------------------------------------------------------------------------------------
  517. // Print the difference between date1 and date 2 expressed both in number of days
  518. // and in the form: days, months, years
  519. //
  520. void print_diffs(long int ndays, Date date, char *mnames[], char *dnames[] )
  521. {
  522. printf("\tDiff:\t%ld day(s)\n", ndays);
  523. printf( "\t\t%ld years(s), %02ld months(s) and %02ld days(s)\n",
  524. date.y, date.m, date.d );
  525.  
  526. return;
  527. }
  528.  
  529. // ------------------------------------------------------------------------------------
  530. // Print the monthly calendar of date
  531. //
  532. void print_calmonth(Date date, int mdays[], char *mnames[], char *dnames[] )
  533. {
  534. register int i=0, j=0;
  535. Date mon1date = { // temp date for 1/date.m/date.y
  536. .d = 1, .m = date.m, .y = date.y
  537. };
  538. int monthdays = mdays[date.m - 1]; // calc # days of date.m
  539. if ( isleap(date.y) && date.m == FEB ) // +1 if leap February
  540. monthdays++;
  541.  
  542. // print month & year
  543. printf("\n%s %ld\t", mnames[date.m - 1], date.y );
  544.  
  545. // print header (day names)
  546. for (i=0; i<7; i++) {
  547. printf("%3s ", dnames[i]);
  548. }
  549. putchar('\n');
  550.  
  551. // now print the day numbers
  552.  
  553. // start with blanks, when needed
  554. printf("\t\t");
  555. for (i=0; i < date_2weekday( mon1date ); i++)
  556. printf("%3s ", "");
  557.  
  558. // start printing the day numbers (i is carried from previous loop)
  559. for ( j=0; j < monthdays; j++, i++ )
  560. {
  561. if ( i % 7 == 0)
  562. printf("\n\t\t");
  563. printf("%3d ", j+1);
  564. }
  565. putchar('\n');
  566.  
  567. return;
  568. }
  569.  
  570. // ------------------------------------------------------------------------------------
  571. int main( void )
  572. {
  573. char *dnames[7] = { // day names
  574. "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
  575. };
  576. char *mnames[12] = { // month names
  577. "JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"
  578. };
  579. // month lengths in days
  580. int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  581.  
  582. Date calstart = { .d=14, .m=9, .y=1752 }; // our calendar starting date
  583. Date calend = { .d=31, .m=12, .y=9999 }; // our calendar ending date
  584.  
  585. Date date1, date2; // dates to be read from user
  586. Date diffdate; // for holding diff as (d,m,y)
  587. long ndays; // difference in days
  588. bool operated = FALSE; // input was date or operation?
  589. char inbuf[MAX_INBUF] = ""; // our own input buffer
  590.  
  591. do
  592. {
  593. print_help();
  594.  
  595. // read date1 and date2
  596. date_askuser( ID1, "\nFirst date (d/m/y): ", &date1,
  597. MAX_INBUF, mdays, calstart, calend );
  598. operated = date_askuser(
  599. ID2, "Second date (d/m/y): ", &date2,
  600. MAX_INBUF, mdays, calstart, calend );
  601.  
  602. // if date2 was an operation, store the resulting date into date2
  603. if ( operated )
  604. date_plusdays( &date2, date1, date2.d, calstart, calend);
  605.  
  606. // calc difference between date1 and date2
  607. ndays = date_diff( &diffdate, date1, date2, mdays );
  608.  
  609. // print dates and results
  610. putchar('\n');
  611. puts("\t--------------------------------------------------");
  612. print_date( date1, ID1, mnames, dnames );
  613. print_date( date2, ID2, mnames, dnames );
  614. puts("\t--------------------------------------------------");
  615. print_diffs( ndays, diffdate, mnames, dnames );
  616. puts("\t--------------------------------------------------");
  617.  
  618. // display the month calendars of the 2 dates
  619. print_calmonth( date1, mdays, mnames, dnames );
  620. if ( date1.y != date2.y || (date1.y == date2.y && date1.m != date2.m) )
  621. print_calmonth(date2, mdays, mnames, dnames);
  622.  
  623. printf("\ntry again (/n): ");
  624. fflush(stdin);
  625. } while ( *s_tolower( s_get(inbuf, MAX_INBUF) ) != 'n' );
  626.  
  627. exit(0);
  628. }
  629.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty