The function tomorrow - Kurt Nørmark

Solution index                   Textual C program


/* Programmed by Kurt Normark, April 2003 */

#include <stdio.h>

/* Date related types */
enum weekday {sunday, monday, tuesday, wednesday, thursday, 
           friday, saturday};
typedef enum weekday weekday;

struct date {
  weekday day_of_week;
  int day;
  int month;
  int year;
};

typedef struct date date;

/* Funktion prototypes */

int leapYear(int);
int date_before(date, date);
weekday next_day_of(weekday);
void prnt_date(date);
char *name_of_weekday(date);
date tomorrow(date);

int main(void) {
  date calendar[1000];

  date first_date = {thursday, 14, 4, 2005},
       last_date  = {thursday, 13, 4, 2006},
       current_date;
  int i = 0, j = 0;

  current_date = first_date;
  while (date_before(current_date, last_date)){
    calendar[i] = current_date;
    current_date = tomorrow(current_date);
    i++;
  }

  for (j = 0; j < i; j++)
    prnt_date(calendar[j]);
}  

/* Return the date after d */
date tomorrow(date d){
  date result;
  
  result = d;

  switch(d.month){
    case 1: case 3: case 5: case 7: case 8: case 10: 
      if (d.day < 31)
	++(result.day);
      else {result.day = 1; ++(result.month);}
      break;
    case 4: case 6: case 9: case 11: 
      if (d.day < 30)
	++(result.day);
      else {result.day = 1; ++(result.month);}
      break;
    case 2:
      if (d.day < (leapYear(d.year)? 29 : 28))
        ++(result.day);
      else {result.day = 1; result.month = 3;}
      break;
    case 12:
      if (d.day < 31)
	++(result.day);
      else {result.day = 1; result.month = 1; (++result.year);}
      break;
    default: exit(-1);  break;
  }

  result.day_of_week = next_day_of(d.day_of_week);
  return result;
}

/* Is y a leapyear */
int leapYear(int y){
  int result;

  if (y % 400 == 0) result = 1;
  else if (y % 100 == 0) result = 0;
  else if (y % 4 == 0) result = 1;
  else result = 0;

  return result;
}

/* Is date d1 less than date d2 */
int date_before(date d1, date d2){
 return
  (d1.year < d2.year) ||
  (d1.year == d2.year && d1.month < d2.month) ||
  (d1.year == d2.year && d1.month == d2.month && d1.day < d2.day);
}  

weekday next_day_of(weekday d){
  return (weekday) (((int) d + 1) % 7);
}

/* Print date d */
void prnt_date(date d){
  printf("%9s %2i.%2i.%4i\n", name_of_weekday(d), d.day, d.month, d.year);
}

/* Return the name of the weekday of the date d */
char *name_of_weekday(date d){
  char *result;
  switch (d.day_of_week) {
    case sunday: result = "Sunday";
       break;
    case monday: result = "Monday";
       break;
    case tuesday: result = "Tuesday";
       break;
    case wednesday: result = "Wednesday";
       break;
    case thursday: result = "Thursday";
       break;
    case friday: result = "Friday";
       break;
    case saturday: result = "Saturday";
       break;
  }
  return result;
}   


struct date {
  weekday day_of_week;
  int day;
  int month;
  int year;
};

typedef struct date date;
First, we notice the type struct date. It is basically an aggregation of three integers: day, month, and year. As redundant information (which can be derived from the three integers) we also represent the day of the week, of type enum weekday. Also notice the way we introduce convenient type names via typedefs.
 

date tomorrow(date d){
  date result;
  
  result = d;

  switch(d.month){
    case 1: case 3: case 5: case 7: case 8: case 10: 
      if (d.day < 31)
	++(result.day);
      else {result.day = 1; ++(result.month);}
      break;
    case 4: case 6: case 9: case 11: 
      if (d.day < 30)
	++(result.day);
      else {result.day = 1; ++(result.month);}
      break;
    case 2:
      if (d.day < (leapYear(d.year)? 29 : 28))
        ++(result.day);
      else {result.day = 1; result.month = 3;}
      break;
    case 12:
      if (d.day < 31)
	++(result.day);
      else {result.day = 1; result.month = 1; (++result.year);}
      break;
    default: exit(-1);  break;
  }

  result.day_of_week = next_day_of(d.day_of_week);
  return result;
}
We concentrate on the function tomorrow in this dissection. Given a date as input, it returns the date of the following day. Overall we make a copy of the input date d and hold it in the variable result. Notice that the assignment result = d in fact involves structure copying. In the switch statement we make changes to result before we return it in the end of the function. The switch statement switches on the month of the date, because the month controls the way we compute the date of the following day. We will now look at the details of the computation.
 

case 1: case 3: case 5: case 7: case 8: case 10: 
  if (d.day < 31)
	++(result.day);
  else {result.day = 1; ++(result.month);}
  break;
In case of a month with 31 days, but not december, we increase result.day. In the case d.day is the last day of the month (31), we reset the day to 1 and increase the month.
 

case 4: case 6: case 9: case 11: 
  if (d.day < 30)
	++(result.day);
  else {result.day = 1; ++(result.month);}
  break;
A similar pattern is found for the months with 30 days.
 

case 2:
  if (d.day < (leapYear(d.year)? 29 : 28))
    ++(result.day);
  else {result.day = 1; result.month = 3;}
  break;
Febrary is special, because it may have 28 or 29 days depending on leap year. The predicate leapYear(year), which is part of the program, returns whether the year is a leap year.
 

case 12:
  if (d.day < 31)
	++(result.day);
  else {result.day = 1; result.month = 1; (++result.year);}
  break;
default: exit(-1);  break;
December is also special. If d.day is 31 we both have to reset the result.month and result.day in addtion to incrementing result.year.
 

result.day_of_week = next_day_of(d.day_of_week);
As the last action, we increase the weekday in a cyclic way, using the function next_day_of, which we have programmed in the lecture about types.
 


Generated: Wednesday, March 29, 2006, 12:33:13
This program dissection page is generated from an XML-in-LAML source file