49static int c_dpm_julian (
int year,
int month,
int *dpm );
52static int c_dpm_noleap (
int year,
int month,
int *dpm );
55#define CCS_ERROR_MESSAGE_LEN 8192
62static int dpm_idx1[] = {-99, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
63static int dpm_leap_idx1[] = {-99, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
66static int spm_idx1[] = {-99, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
69static int date_ge(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
70static int date_le(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
71static int date_lt(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
72static int date_gt(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
79#define CCS_VALID_SIG 89132412
84#define CCS_MAX_N_COUNTRY_CODES 5000
107 int use_specified_xition_date, spec_year_x, spec_month_x, spec_day_x;
111 if( strncasecmp( calname,
"standard", 8 ) == 0 ) {
117 use_specified_xition_date = 0;
118 if( (strlen(calname) >= 11) && (calname[8] ==
'_')) {
120 fprintf( stderr,
"Error, unknown calendar passed to ccs_init_calendar: \"%s\". Returning NULL\n",
124 use_specified_xition_date = 1;
128 if( retval == NULL ) {
129 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
133 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
135 if ( retval->
name == NULL ) {
137 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
141 strcpy( retval->
name, calname );
148 if( use_specified_xition_date == 1 ) {
149 retval->
year_x = spec_year_x;
150 retval->
month_x = spec_month_x;
151 retval->
day_x = spec_day_x;
162 fprintf( stderr,
"calcalcs_init_cal: Error trying to initialize calendar \"%s\": %s. Returning NULL\n",
172 else if( (strcasecmp( calname,
"gregorian" ) == 0) ||
173 (strcasecmp( calname,
"proleptic_gregorian" ) == 0)) {
179 if( retval == NULL ) {
180 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
184 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
186 if ( retval->
name == NULL ) {
188 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
192 strcpy( retval->
name, calname );
204 else if( (strcasecmp( calname,
"gregorian_y0" ) == 0) ||
205 (strcasecmp( calname,
"proleptic_gregorian_y0" ) == 0)) {
210 if( retval == NULL ) {
211 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
215 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
217 if ( retval->
name == NULL ) {
219 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
223 strcpy( retval->
name, calname );
235 else if( (strcasecmp( calname,
"julian" ) == 0 ) ||
236 (strcasecmp( calname,
"proleptic_julian" ) == 0 )) {
238 if( retval == NULL ) {
239 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
243 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
245 if ( retval->
name == NULL ) {
247 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
251 strcpy( retval->
name, calname );
263 else if( (strcasecmp(calname,
"noleap")==0) ||
264 (strcasecmp(calname,
"no_leap")==0) ||
265 (strcasecmp(calname,
"365_day")==0)) {
267 if( retval == NULL ) {
268 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
272 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(
"noleap")+1) );
274 if ( retval->
name == NULL ) {
276 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
280 strcpy( retval->
name,
"noleap" );
292 else if( strcasecmp(calname,
"360_day")==0) {
294 if( retval == NULL ) {
295 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
299 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
301 if ( retval->
name == NULL ) {
303 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
307 strcpy( retval->
name, calname );
344 if( calendar->
mixed ) {
345 if( year >= calendar->
year_x )
353 ierr = c2use->
c_isleap( year, leap );
365 int overlap_px_month, overlap_x_month;
368 if( calendar->
mixed ) {
374 overlap_px_month = ((year == calendar->
year_px) && (month == calendar->
month_px));
375 overlap_x_month = ((year == calendar->
year_x ) && (month == calendar->
month_x ));
376 if( overlap_px_month || overlap_x_month ) {
377 if( overlap_px_month && (!overlap_x_month)) {
382 else if( overlap_x_month && (!overlap_px_month)) {
383 if( (ierr =
ccs_dpm( calendar->
late_cal, year, month, &ndays_reg )) != 0 )
385 *dpm = ndays_reg - calendar->
day_x + 1;
391 if( (ierr =
ccs_dpm( calendar->
late_cal, year, month, &ndays_reg )) != 0 )
393 *dpm = calendar->
day_px + (ndays_reg - calendar->
day_x + 1);
405 return( c2use->
c_dpm( year, month, dpm ));
421 if( calendar->
mixed ) {
422 if( jday >= calendar->
jday_x )
430 return( c2use->
c_jday2date( jday, year, month, day ));
450 if( calendar->
mixed ) {
457 sprintf(
error_message,
"ccs_date2jday: date %04d-%02d-%02d is not a valid date in the %s calendar; it falls between the last date the %s calendar was used (%04d-%02d-%02d) and the first date the %s calendar was used (%04d-%02d-%02d)",
458 year, month, day, calendar->
name,
469 if( (ierr =
ccs_dpm( c2use, year, month, &dpm )) != 0 )
472 if( (month < 1) || (month > 12) || (day < 1) || (day > dpm)) {
473 sprintf(
error_message,
"date2jday passed an date that is invalid in the %s calendar: %04d-%02d-%02d",
474 c2use->
name, year, month, day );
478 return( c2use->
c_date2jday( year, month, day, jday ));
491 int ierr, jd0, jd1, doy_px, jd_args, xition_date_first_day_of_year,
498 if( calendar->
mixed ) {
505 sprintf(
error_message,
"ccs_date2doy: date %04d-%02d-%02d is not a valid date in the %s calendar; it falls between the last date the %s calendar was used (%04d-%02d-%02d) and the first date the %s calendar was used (%04d-%02d-%02d)",
506 year, month, day, calendar->
name,
514 xition_date_first_day_of_year = ((year == calendar->
year_x) && (calendar->
month_x == 1) && (calendar->
day_x == 1));
515 if( (year > calendar->
year_x) || xition_date_first_day_of_year )
541 ndays_elapsed = jd_args - calendar->
jday_x + 1;
547 *doy = doy_px + ndays_elapsed;
556 if( (ierr = c2use->
c_date2jday( year, 1, 1, &jd0 )) != 0 )
560 if( (ierr = c2use->
c_date2jday( year, month, day, &jd1 )) != 0 )
563 *doy = jd1 - jd0 + 1;
578 int ierr, leap, jd0, jd1, tyear, doy_px, jd_want,
579 xition_date_first_day_of_year, ndays_max;
585 if( calendar->
mixed ) {
586 xition_date_first_day_of_year = ((year == calendar->
year_x) && (calendar->
month_x == 1) && (calendar->
day_x == 1));
587 if( year < calendar->year_x )
589 else if( (year > calendar->
year_x) || xition_date_first_day_of_year )
606 jd_want = calendar->
jday_x + (doy - doy_px - 1);
615 if( tyear != year ) {
616 sprintf(
error_message,
"year %d in the %s calendar (with transition date %04d-%02d-%02d) has less than %d days, but that was the day-of-year number requested in a call to ccs_doy2date\n",
630 if( (ierr = c2use->
c_isleap( year, &leap )) != 0 )
637 if( (doy < 1) || (doy > ndays_max)) {
638 sprintf(
error_message,
"routine ccs_doy2date was passed a day-of-year=%d, but for year %d in the %s calendar, the value must be between 1 and %d",
639 doy, year, c2use->
name, ndays_max );
644 if( (ierr = c2use->
c_date2jday( year, 1, 1, &jd0 )) != 0 )
651 if( (ierr = c2use->
c_jday2date( jd1, &tyear, month, day )) != 0 )
667 int ndays_since,
calcalcs_cal *calendar_new,
int *year_new,
int *month_new,
int *day_new )
680 if( calendar_orig->
mixed ) {
681 if(
date_ge( year_orig, month_orig, day_orig,
683 c2use_orig = calendar_orig->
late_cal;
684 else if(
date_le( year_orig, month_orig, day_orig,
689 sprintf(
error_message,
"ccs_dayssince: date %04d-%02d-%02d is not a valid date in the %s calendar; it falls between the last date the %s calendar was used (%04d-%02d-%02d) and the first date the %s calendar was used (%04d-%02d-%02d)",
690 year_orig, month_orig, day_orig, calendar_orig->
name,
699 c2use_orig = calendar_orig;
702 if( (ierr = c2use_orig->
c_date2jday( year_orig, month_orig, day_orig, &jd0 )) != 0 )
706 jd1 = jd0 + ndays_since;
708 if( calendar_new->
mixed ) {
711 if( jd1 >= calendar_new->
jday_x )
717 c2use_new = calendar_new;
720 if( (ierr = c2use_new->
c_jday2date( jd1, year_new, month_new, day_new )) != 0 )
730 fprintf( stderr,
"Error, the calcalcs library is attempting to store more country codes than is possible; max is %d\n",
732 fprintf( stderr,
"To fix, recompile with a larger number for CCS_MAX_N_COUNTRY_CODES\n" );
738 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code %s\n",
745 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code named %s\n",
753 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code long name %s\n",
815 if( strcmp( country_code,
"??" ) == 0 ) {
843 sprintf(
error_message,
"ccs_get_xition_date: unknown calendar country/region code: \"%s\". Known codes: ", country_code );
861 printf(
"Calcalcs library known country codes:\n" );
863 printf(
"Code: %s Transition date: %04d-%02d-%02d Country/Region: %s\n",
882 if( calendar->
mixed == 0 )
892 if( (month < 1) || (month > 12) || (day < 1) || (day > dpm)) {
893 fprintf( stderr,
"Error in routine set_cal_xition_date: trying to set the calendar Julian/Gregorian transition date to an illegal date: %04d-%02d-%02d\n", year, month, day );
899 calendar->
day_x = day;
910 if( error_code == 0 )
914 sprintf(
error_message,
"a NULL calendar was passed to the calcalcs routine" );
917 sprintf(
error_message,
"an invalid, malformed, previously-freed, or uninitialized calendar was passed to the calcalcs routine" );
930 sprintf(
error_message,
"ccs_isleap: year %d is out of range for the Julian calendar; dates must not be before 4713 B.C.", year);
935 sprintf(
error_message,
"the Julian calendar has no year 0" );
947 *leap = ((tyear % 4) == 0);
960 sprintf(
error_message,
"ccs_isleap: year %d is out of range for the Gregorian calendar; dates must not be before 4713 B.C.", year);
965 sprintf(
error_message,
"the Gregorian calendar has no year 0. Use the \"Gregorian_y0\" calendar if you want to include year 0." );
977 *leap = (((tyear % 4) == 0) && ((tyear % 100) != 0)) || ((tyear % 400) == 0);
988 sprintf(
error_message,
"ccs_isleap: year %d is out of range for the Gregorian_y0 calendar; dates must not be before 4713 B.C.", year);
992 *leap = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
1010 int m, leap, *dpm2use, err;
1012 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1013 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Gregorian calendar",
1019 sprintf(
error_message,
"year 0 does not exist in the Gregorian calendar. Use the \"Gregorian_y0\" calendar if you want to include year 0" );
1024 if( year < -4714 ) {
1025 sprintf(
error_message,
"year %d is out of range of the Gregorian calendar routines; must have year >= -4714", year );
1046 for( m=month-1; m>0; m-- )
1047 *jday += dpm2use[m];
1049 *jday += 365*(year-1) + (year-1)/4 - (year-1)/100 + (year-1)/400;
1072 int m, leap, *dpm2use, err;
1074 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1075 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Gregorian calendar",
1081 if( year < -4714 ) {
1082 sprintf(
error_message,
"year %d is out of range of the Gregorian calendar routines; must have year >= -4714", year );
1097 for( m=month-1; m>0; m-- )
1098 *jday += dpm2use[m];
1100 *jday += 365*(year-1) + (year-1)/4 - (year-1)/100 + (year-1)/400;
1120 int tjday, leap, *dpm2use, ierr, yp1;
1126 *year = jday/366 - 4714;
1130 if( yp1 == 0 ) yp1 = 1;
1133 while( jday >= tjday ) {
1138 if( yp1 == 0 ) yp1 = 1;
1153 while( jday > tjday ) {
1161 *day = jday - tjday + 1;
1176 int tjday, leap, *dpm2use, ierr, yp1;
1182 *year = jday/366 - 4715;
1188 while( jday >= tjday ) {
1205 while( jday > tjday ) {
1213 *day = jday - tjday + 1;
1231 int m, leap, *dpm2use, err;
1233 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1234 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Julian calendar",
1240 sprintf(
error_message,
"year 0 does not exist in the Julian calendar" );
1245 if( year < -4713 ) {
1246 sprintf(
error_message,
"year %d is out of range of the Julian calendar routines; must have year >= -4713", year );
1267 for( m=month-1; m>0; m-- )
1268 *jday += dpm2use[m];
1270 *jday += 365*(year-1) + (year-1)/4;
1290 int tjday, leap, *dpm2use, ierr, yp1;
1295 *year = jday/366 - 4713;
1299 if( yp1 == 0 ) yp1 = 1;
1302 while( jday >= tjday ) {
1307 if( yp1 == 0 ) yp1 = 1;
1322 while( jday > tjday ) {
1330 *day = jday - tjday + 1;
1343 if( cc->
mixed == 1 ) {
1349 fprintf( stderr,
"Warning: invalid calendar passed to routine ccs_free_calendar!\n" );
1355 if( cc->
name != NULL )
1362static int date_gt(
int year,
int month,
int day,
int y2,
int m2,
int d2 )
1364 return( !
date_le( year, month, day, y2, m2, d2 ));
1362static int date_gt(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
…}
1368static int date_lt(
int year,
int month,
int day,
int y2,
int m2,
int d2 )
1370 return( !
date_ge( year, month, day, y2, m2, d2 ));
1368static int date_lt(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
…}
1374static int date_le(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
1374static int date_le(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
…}
1396static int date_ge(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
1396static int date_ge(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
…}
1430 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the 360_day calendar",
1437 *jday = year*360 + spm + (day-1);
1445 if( (month == 2) && (day == 29)) {
1446 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the noleap calendar",
1451 *jday = year*365 +
spm_idx1[month] + (day-1);
1459 int nextra, yr_offset, doy;
1463 yr_offset = (-jday)/360+1;
1464 jday += 360*yr_offset;
1469 nextra = jday - *year*360;
1471 *month = nextra/30 + 1;
1472 *day = doy - (*month-1)*30;
1482 int nextra, yr_offset, doy;
1486 yr_offset = (-jday)/365+1;
1487 jday += 365*yr_offset;
1492 nextra = jday - *year*365;
1495 while( doy >
spm_idx1[*month + 1] )
1510 if( (month<1) || (month>12)) {
1511 sprintf(
error_message,
"month %d does not exist in the Gregorian calendar", month );
1532 if( (month<1) || (month>12)) {
1533 sprintf(
error_message,
"month %d does not exist in the Gregorian calendar", month );
1553 if( (month<1) || (month>12)) {
1554 sprintf(
error_message,
"month %d does not exist in the Julian calendar", month );
1572 if( (month<1) || (month>12)) {
1573 sprintf(
error_message,
"month %d does not exist in the 360_day calendar", month );
1585 if( (month<1) || (month>12)) {
1586 sprintf(
error_message,
"month %d does not exist in the noleap calendar", month );
1603 sprintf(
error_message,
"Failed to turn the mixed calendar transition day %04d-%02d-%02d in the %s calendar into a Julian day!\n",
1613 sprintf(
error_message,
"Failed to turn the day before the mixed calendar transition day into a date! %s\n",
static int c_jday2date_gregorian(int jday, int *year, int *month, int *day)
static int c_dpm_360_day(int year, int month, int *dpm)
static int c_jday2date_julian(int jday, int *year, int *month, int *day)
static int date_ge(int year, int month, int day, int y2, int m2, int d2)
static void ccs_dump_xition_dates(void)
static int c_jday2date_360_day(int jday, int *year, int *month, int *day)
static int c_date2jday_gregorian_y0(int year, int month, int day, int *jday)
int ccs_dayssince(calcalcs_cal *calendar_orig, int year_orig, int month_orig, int day_orig, int ndays_since, calcalcs_cal *calendar_new, int *year_new, int *month_new, int *day_new)
char * ccs_err_str(int error_code)
static int set_xition_extra_info(calcalcs_cal *cal)
#define CCS_MAX_N_COUNTRY_CODES
int ccs_date2doy(calcalcs_cal *calendar, int year, int month, int day, int *doy)
static ccs_country_code * ccs_xition_dates[CCS_MAX_N_COUNTRY_CODES]
static int c_isleap_julian(int year, int *leap)
static int c_date2jday_noleap(int year, int month, int day, int *jday)
static int c_date2jday_360_day(int year, int month, int day, int *jday)
int ccs_jday2date(calcalcs_cal *calendar, int jday, int *year, int *month, int *day)
int ccs_isleap(calcalcs_cal *calendar, int year, int *leap)
static int date_le(int year, int month, int day, int y2, int m2, int d2)
static int c_jday2date_noleap(int jday, int *year, int *month, int *day)
static int have_initted_country_codes
static void ccs_init_country_database(void)
static int c_jday2date_gregorian_y0(int jday, int *year, int *month, int *day)
int ccs_doy2date(calcalcs_cal *calendar, int year, int doy, int *month, int *day)
void ccs_free_calendar(calcalcs_cal *cc)
static int c_dpm_noleap(int year, int month, int *dpm)
static int date_lt(int year, int month, int day, int y2, int m2, int d2)
int ccs_date2jday(calcalcs_cal *calendar, int year, int month, int day, int *jday)
int ccs_dpm(calcalcs_cal *calendar, int year, int month, int *dpm)
#define CCS_ERROR_MESSAGE_LEN
static int ccs_n_country_codes
static int c_dpm_gregorian_y0(int year, int month, int *dpm)
static void ccs_gxd_add_country(char *code, char *longname, int year, int month, int day)
static int c_date2jday_julian(int year, int month, int day, int *jday)
int ccs_set_xition_date(calcalcs_cal *calendar, int year, int month, int day)
static int c_date2jday_gregorian(int year, int month, int day, int *jday)
static int c_isleap_never(int year, int *leap)
static int c_isleap_gregorian(int year, int *leap)
static char error_message[CCS_ERROR_MESSAGE_LEN]
static int dpm_leap_idx1[]
static int c_isleap_gregorian_y0(int year, int *leap)
static int date_gt(int year, int month, int day, int y2, int m2, int d2)
calcalcs_cal * ccs_init_calendar(const char *calname)
static int c_dpm_julian(int year, int month, int *dpm)
static int c_dpm_gregorian(int year, int month, int *dpm)
int ccs_get_xition_date(const char *country_code, int *year, int *month, int *day)
#define CALCALCS_ERR_DATE_NOT_IN_CALENDAR
#define CALCALCS_VERSION_NUMBER
#define CALCALCS_ERR_INVALID_DAY_OF_YEAR
#define CALCALCS_ERR_UNKNOWN_COUNTRY_CODE
#define CALCALCS_ERR_NO_YEAR_ZERO
#define CALCALCS_ERR_INVALID_CALENDAR
#define CALCALCS_ERR_NULL_CALENDAR
#define CALCALCS_ERR_NOT_A_MIXED_CALENDAR
#define CALCALCS_ERR_OUT_OF_RANGE
int(* c_jday2date)(int, int *, int *, int *)
struct cccalendar * late_cal
struct cccalendar * early_cal
int(* c_date2jday)(int, int, int, int *)
int(* c_isleap)(int, int *)
int(* c_dpm)(int, int, int *)