48 static int c_dpm_julian (
int year,
int month,
int *dpm );
51 static int c_dpm_noleap (
int year,
int month,
int *dpm );
54 #define CCS_ERROR_MESSAGE_LEN 8192
61 static int dpm_idx1[] = {-99, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
62 static int dpm_leap_idx1[] = {-99, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
65 static int spm_idx1[] = {-99, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
68 static int date_ge(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
69 static int date_le(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
70 static int date_lt(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
71 static int date_gt(
int year,
int month,
int day,
int y2,
int m2,
int d2 );
74 static void ccs_gxd_add_country(
char *code,
char *longname,
int year,
int month,
int day );
78 #define CCS_VALID_SIG 89132412
83 #define CCS_MAX_N_COUNTRY_CODES 5000
106 int use_specified_xition_date, spec_year_x, spec_month_x, spec_day_x;
110 if( strncasecmp( calname,
"standard", 8 ) == 0 ) {
116 use_specified_xition_date = 0;
117 if( (strlen(calname) >= 11) && (calname[8] ==
'_')) {
119 fprintf( stderr,
"Error, unknown calendar passed to ccs_init_calendar: \"%s\". Returning NULL\n",
123 use_specified_xition_date = 1;
127 if( retval == NULL ) {
128 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
132 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
134 if ( retval->
name == NULL ) {
136 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
140 strcpy( retval->
name, calname );
147 if( use_specified_xition_date == 1 ) {
148 retval->
year_x = spec_year_x;
149 retval->
month_x = spec_month_x;
150 retval->
day_x = spec_day_x;
161 fprintf( stderr,
"calcalcs_init_cal: Error trying to initialize calendar \"%s\": %s. Returning NULL\n",
171 else if( (strcasecmp( calname,
"gregorian" ) == 0) ||
172 (strcasecmp( calname,
"proleptic_gregorian" ) == 0)) {
178 if( retval == NULL ) {
179 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
183 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
185 if ( retval->
name == NULL ) {
187 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
191 strcpy( retval->
name, calname );
203 else if( (strcasecmp( calname,
"gregorian_y0" ) == 0) ||
204 (strcasecmp( calname,
"proleptic_gregorian_y0" ) == 0)) {
209 if( retval == NULL ) {
210 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
214 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
216 if ( retval->
name == NULL ) {
218 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
222 strcpy( retval->
name, calname );
234 else if( (strcasecmp( calname,
"julian" ) == 0 ) ||
235 (strcasecmp( calname,
"proleptic_julian" ) == 0 )) {
237 if( retval == NULL ) {
238 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
242 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
244 if ( retval->
name == NULL ) {
246 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
250 strcpy( retval->
name, calname );
262 else if( (strcasecmp(calname,
"noleap")==0) ||
263 (strcasecmp(calname,
"no_leap")==0) ||
264 (strcasecmp(calname,
"365_day")==0)) {
266 if( retval == NULL ) {
267 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
271 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(
"noleap")+1) );
273 if ( retval->
name == NULL ) {
275 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
279 strcpy( retval->
name,
"noleap" );
291 else if( strcasecmp(calname,
"360_day")==0) {
293 if( retval == NULL ) {
294 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar\n" );
298 retval->
name = (
char *)malloc(
sizeof(
char) * (strlen(calname)+1) );
300 if ( retval->
name == NULL ) {
302 fprintf( stderr,
"Error, cannot allocate space for the calcalcs calendar. Returning NULL\n" );
306 strcpy( retval->
name, calname );
352 ierr = c2use->
c_isleap( year, leap );
364 int overlap_px_month, overlap_x_month;
373 overlap_px_month = ((year ==
calendar->year_px) && (month ==
calendar->month_px));
374 overlap_x_month = ((year ==
calendar->year_x ) && (month ==
calendar->month_x ));
375 if( overlap_px_month || overlap_x_month ) {
376 if( overlap_px_month && (!overlap_x_month)) {
381 else if( overlap_x_month && (!overlap_px_month)) {
382 if( (ierr =
ccs_dpm(
calendar->late_cal, year, month, &ndays_reg )) != 0 )
384 *dpm = ndays_reg -
calendar->day_x + 1;
390 if( (ierr =
ccs_dpm(
calendar->late_cal, year, month, &ndays_reg )) != 0 )
404 return( c2use->
c_dpm( year, month, dpm ));
429 return( c2use->
c_jday2date( jday, year, month, day ));
456 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)",
468 if( (ierr =
ccs_dpm( c2use, year, month, &dpm )) != 0 )
471 if( (month < 1) || (month > 12) || (day < 1) || (day > dpm)) {
472 sprintf(
error_message,
"date2jday passed an date that is invalid in the %s calendar: %04d-%02d-%02d",
473 c2use->
name, year, month, day );
477 return( c2use->
c_date2jday( year, month, day, jday ));
490 int ierr, jd0, jd1, doy_px, jd_args, xition_date_first_day_of_year,
504 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)",
514 if( (year >
calendar->year_x) || xition_date_first_day_of_year )
540 ndays_elapsed = jd_args -
calendar->jday_x + 1;
546 *doy = doy_px + ndays_elapsed;
555 if( (ierr = c2use->c_date2jday( year, 1, 1, &jd0 )) != 0 )
559 if( (ierr = c2use->c_date2jday( year, month, day, &jd1 )) != 0 )
562 *doy = jd1 - jd0 + 1;
577 int ierr, leap, jd0, jd1, tyear, doy_px, jd_want,
578 xition_date_first_day_of_year, ndays_max;
586 if( year < calendar->year_x )
588 else if( (year >
calendar->year_x) || xition_date_first_day_of_year )
605 jd_want =
calendar->jday_x + (doy - doy_px - 1);
614 if( tyear != year ) {
615 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",
629 if( (ierr = c2use->c_isleap( year, &leap )) != 0 )
632 ndays_max = c2use->ndays_leap;
634 ndays_max = c2use->ndays_reg;
636 if( (doy < 1) || (doy > ndays_max)) {
637 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",
638 doy, year, c2use->name, ndays_max );
643 if( (ierr = c2use->c_date2jday( year, 1, 1, &jd0 )) != 0 )
650 if( (ierr = c2use->c_jday2date( jd1, &tyear, month, day )) != 0 )
666 int ndays_since,
calcalcs_cal *calendar_new,
int *year_new,
int *month_new,
int *day_new )
679 if( calendar_orig->
mixed ) {
680 if(
date_ge( year_orig, month_orig, day_orig,
682 c2use_orig = calendar_orig->
late_cal;
683 else if(
date_le( year_orig, month_orig, day_orig,
688 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)",
689 year_orig, month_orig, day_orig, calendar_orig->
name,
698 c2use_orig = calendar_orig;
701 if( (ierr = c2use_orig->
c_date2jday( year_orig, month_orig, day_orig, &jd0 )) != 0 )
705 jd1 = jd0 + ndays_since;
707 if( calendar_new->
mixed ) {
710 if( jd1 >= calendar_new->
jday_x )
716 c2use_new = calendar_new;
719 if( (ierr = c2use_new->
c_jday2date( jd1, year_new, month_new, day_new )) != 0 )
729 fprintf( stderr,
"Error, the calcalcs library is attempting to store more country codes than is possible; max is %d\n",
731 fprintf( stderr,
"To fix, recompile with a larger number for CCS_MAX_N_COUNTRY_CODES\n" );
737 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code %s\n",
744 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code named %s\n",
752 fprintf( stderr,
"calcalcs routine ccs_gxd_add_country: Error trying to allocate space for country code long name %s\n",
814 if( strcmp( country_code,
"??" ) == 0 ) {
842 sprintf(
error_message,
"ccs_get_xition_date: unknown calendar country/region code: \"%s\". Known codes: ", country_code );
860 printf(
"Calcalcs library known country codes:\n" );
862 printf(
"Code: %s Transition date: %04d-%02d-%02d Country/Region: %s\n",
891 if( (month < 1) || (month > 12) || (day < 1) || (day > dpm)) {
892 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 );
909 if( error_code == 0 )
913 sprintf(
error_message,
"a NULL calendar was passed to the calcalcs routine" );
916 sprintf(
error_message,
"an invalid, malformed, previously-freed, or uninitialized calendar was passed to the calcalcs routine" );
929 sprintf(
error_message,
"ccs_isleap: year %d is out of range for the Julian calendar; dates must not be before 4713 B.C.", year);
934 sprintf(
error_message,
"the Julian calendar has no year 0" );
946 *leap = ((tyear % 4) == 0);
959 sprintf(
error_message,
"ccs_isleap: year %d is out of range for the Gregorian calendar; dates must not be before 4713 B.C.", year);
964 sprintf(
error_message,
"the Gregorian calendar has no year 0. Use the \"Gregorian_y0\" calendar if you want to include year 0." );
976 *leap = (((tyear % 4) == 0) && ((tyear % 100) != 0)) || ((tyear % 400) == 0);
987 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);
991 *leap = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
1009 int m, leap, *dpm2use, err;
1011 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1012 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Gregorian calendar",
1018 sprintf(
error_message,
"year 0 does not exist in the Gregorian calendar. Use the \"Gregorian_y0\" calendar if you want to include year 0" );
1023 if( year < -4714 ) {
1024 sprintf(
error_message,
"year %d is out of range of the Gregorian calendar routines; must have year >= -4714", year );
1045 for( m=month-1; m>0; m-- )
1046 *jday += dpm2use[m];
1048 *jday += 365*(year-1) + (year-1)/4 - (year-1)/100 + (year-1)/400;
1071 int m, leap, *dpm2use, err;
1073 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1074 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Gregorian calendar",
1080 if( year < -4714 ) {
1081 sprintf(
error_message,
"year %d is out of range of the Gregorian calendar routines; must have year >= -4714", year );
1096 for( m=month-1; m>0; m-- )
1097 *jday += dpm2use[m];
1099 *jday += 365*(year-1) + (year-1)/4 - (year-1)/100 + (year-1)/400;
1119 int tjday, leap, *dpm2use, ierr, yp1;
1125 *year = jday/366 - 4714;
1129 if( yp1 == 0 ) yp1 = 1;
1132 while( jday >= tjday ) {
1137 if( yp1 == 0 ) yp1 = 1;
1152 while( jday > tjday ) {
1160 *day = jday - tjday + 1;
1175 int tjday, leap, *dpm2use, ierr, yp1;
1181 *year = jday/366 - 4715;
1187 while( jday >= tjday ) {
1204 while( jday > tjday ) {
1212 *day = jday - tjday + 1;
1230 int m, leap, *dpm2use, err;
1232 if( (month < 1) || (month > 12) || (day < 1) || (day > 31)) {
1233 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the Julian calendar",
1239 sprintf(
error_message,
"year 0 does not exist in the Julian calendar" );
1244 if( year < -4713 ) {
1245 sprintf(
error_message,
"year %d is out of range of the Julian calendar routines; must have year >= -4713", year );
1266 for( m=month-1; m>0; m-- )
1267 *jday += dpm2use[m];
1269 *jday += 365*(year-1) + (year-1)/4;
1289 int tjday, leap, *dpm2use, ierr, yp1;
1294 *year = jday/366 - 4713;
1298 if( yp1 == 0 ) yp1 = 1;
1301 while( jday >= tjday ) {
1306 if( yp1 == 0 ) yp1 = 1;
1321 while( jday > tjday ) {
1329 *day = jday - tjday + 1;
1342 if( cc->
mixed == 1 ) {
1348 fprintf( stderr,
"Warning: invalid calendar passed to routine ccs_free_calendar!\n" );
1354 if( cc->
name != NULL )
1361 static int date_gt(
int year,
int month,
int day,
int y2,
int m2,
int d2 )
1363 return( !
date_le( year, month, day, y2, m2,
d2 ));
1367 static int date_lt(
int year,
int month,
int day,
int y2,
int m2,
int d2 )
1369 return( !
date_ge( year, month, day, y2, m2,
d2 ));
1373 static int date_le(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
1395 static int date_ge(
int year,
int month,
int day,
int y2,
int m2,
int d2 ) {
1429 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the 360_day calendar",
1436 *jday = year*360 + spm + (day-1);
1444 if( (month == 2) && (day == 29)) {
1445 sprintf(
error_message,
"date %04d-%02d-%02d does not exist in the noleap calendar",
1450 *jday = year*365 +
spm_idx1[month] + (day-1);
1458 int nextra, yr_offset, doy;
1462 yr_offset = (-jday)/360+1;
1463 jday += 360*yr_offset;
1468 nextra = jday - *year*360;
1470 *month = nextra/30 + 1;
1471 *day = doy - (*month-1)*30;
1481 int nextra, yr_offset, doy;
1485 yr_offset = (-jday)/365+1;
1486 jday += 365*yr_offset;
1491 nextra = jday - *year*365;
1494 while( doy >
spm_idx1[*month + 1] )
1509 if( (month<1) || (month>12)) {
1510 sprintf(
error_message,
"month %d does not exist in the Gregorian calendar", month );
1531 if( (month<1) || (month>12)) {
1532 sprintf(
error_message,
"month %d does not exist in the Gregorian calendar", month );
1552 if( (month<1) || (month>12)) {
1553 sprintf(
error_message,
"month %d does not exist in the Julian calendar", month );
1571 if( (month<1) || (month>12)) {
1572 sprintf(
error_message,
"month %d does not exist in the 360_day calendar", month );
1584 if( (month<1) || (month>12)) {
1585 sprintf(
error_message,
"month %d does not exist in the noleap calendar", month );
1602 sprintf(
error_message,
"Failed to turn the mixed calendar transition day %04d-%02d-%02d in the %s calendar into a Julian day!\n",
1612 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)
calcalcs_cal * ccs_init_calendar(const char *calname)
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)
char * ccs_err_str(int error_code)
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)
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)
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
std::string printf(const char *format,...)
static std::string calendar(const File *input_file, const Config &config, const Logger &log)
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 *)