The CalCalcs API


Table of Contents:

utCalendar2_cal: Turn a udunits-specified time value into a Y/M/D date
utInvCalendar2_cal: Turn a Y/M/D date into a udunits-specified value

ccs_init_calendar: initialize a calendar
ccs_free_calendar: Free storage for a calendar
ccs_isleap: Determine if a year is a leap year
ccs_dayssince: Compute the date N days since a given Y/M/D date
ccs_date2jday: Turn a Y/M/D date into a Julian Day number
ccs_jday2date: Turn a Julian Day into a Y/M/D date
ccs_date2doy: Turn a Y/M/D date into a day number of year
ccs_doy2date: Turn a day number of year into a Y/M/D date
ccs_get_xition_date: Get the Julian/Gregorian transition date for a country or region
ccs_set_xition_date: Set the Julian/Gregorian transition date for a calendar
ccs_err_str: Get an error string from the calcalcs library

Error codes

 

Details


calcalcs_cal *ccs_init_calendar( const char *calname );

This initializes a calendar for use, and returns a pointer to that calendar. You have to initialize a calendar before you can use it. The passed parameter is the name of the calendar you want to use. The allowed values are: "Standard", "proleptic_Gregorian", "proleptic_Julian", "noleap", and "360_day". Also, "365_day" and "no_leap" are aliases for "noleap". The calendars these values describe are shown here.

Optionally, you can specify "Standard" append an underscore and two-letter uppercase country/region code (as recognized by ccs_get_xition_date, see below), and the specified transition date between the Julian and Gregorian calendar will be used. For example, "Standard_US" specifies a calendar using the transition date observed in the British colonial United States. If no country/region is specified, a transition date of Oct 15, 1582 is used.

If the specified name is not recognized, NULL is returned and an error message is set (see ccs_err_str, below). You should free the calendar using ccs_free_calendar when you are done with it. This routine is in file calcalcs.c, and declared in header calcalcs.h.


void ccs_free_calendar( calcalcs_cal *calendar );

This frees the storage associated with a calendar that has been allocated by routine ccs_init_calendar. This routine is in file calcalcs.c, and declared in header calcalcs.h.


int utCalendar2_cal( double val, ut_unit *dataunits, int *year, int *month, int *day, int *hour, int *minute, double *second, char *calendar_name );

This is a replacement for the (missing in udunits version 2?) routine "utCalendar" that works with version 2 of the udunits library and a specified calendar. Given a double precision value, of some units described by dataunits, this converts the value into a date and time in the specified calendar. The passed parameter "dataunits" must be the return value from a call to the udunits-2 library routine "ut_parse", and must be a temporal unit with an origin (i.e., a temporal value since some origin time).

The allowed values for calendar_name include "Standard", "proleptic_Gregorian", "proleptic_Julian", "noleap", and "360_day". Also, "365_day" is an alias for "noleap". The calendars these describe are shown here.

NOTE that there are three differences between this routine and the original utCalendar routine: 1) the name is "utCalendar2", not "utCalendar"; 2) the last parameter is a double, not a float; 3) the passed unit is a ut_unit pointer (as produced by the udunits version 2 library), not a utUnit pointer (as produced by the udunits version 1 library).

For example, if val is 2.5 and dataunits is the return value of ut_parse given the string "days since 1901-01-01 00:00:00.0", then the retured value is the date 1901-01-03 12:00:00.0.

This routine is in file utCalendar2_cal.c, and declared in the header file utCalendar2_cal.h. If this routine is included, the resulting code must be linked with the udunits-2 library. If this routine is not needed, then the file utCalendar2_cal.c can be omitted, in which case no linking with the udunits-2 library is needed for the rest of calcalc's functionality.

This returns 0 on success, or a negative number on error. Errors can be generated by, for instance, uninitialized or NULL values given in the dataunits parameter. Note that the year 0 does not exist in the Standard calendar, so 1 day before 1 Jan, 1 A.D. is the date 31 Dec, 1 B.C. (year -1).


int utInvCalendar2_cal( int year, int month, int day, int hour, int minute, double second, ut_unit *user_unit, double *value, char *calendar_name );

Given a Y/M/D H:M:S date and time, a udunits-2 library description of some temporal units that have an origin, and a calendar name, this gives the double precision floating point value corresponding to that date, using the specified calendar.

The allowed values for calendar_name are: "Standard", "proleptic_Gregorian", "proleptic_Julian", "noleap", and "360_day". Also, "365_day" is an alias for "noleap". The calendars these describe are shown here.

For example, if the passed date is 1901-01-03 12:00, and the passed units are the result from the udunits-2 library ut_parse applied to the string "days since 1901-01-01 00:00", then the returned value is 2.5, since the passed date is 2.5 days after the origin date.

This routine is in file utCalendar2_cal.c, and declared in the header file utCalendar2_cal.h. If this routine is included, the resulting code must be linked with the udunits-2 library. If this routine is not needed, then the file utCalendar2_cal.c can be omitted, in which case no linking with the udunits-2 library is needed for the rest of calcalc's functionality.

This returns 0 on success, or a negative number on error. Errors can be generated by, for instance, uninitialized or NULL values given in the dataunits parameter, or passing illegal dates. Illegal dates include those before 4713 B.C., or dates that do not exist in the Standard calendar, such as April 31st. Note that that the year 0 does not exist in the Standard calendar, and so will return an error.


int ccs_isleap( calcalcs_cal *calendar, int year, int *leap );

Given an initialized calendar and a year, this sets pameter leap to 1 if the year is a leap year in that calendar, and sets it to 0 otherwise.

The function returns 0 on success, and a negative value on error. An error can include passing a null or uninitialized calendar, or an invalid year (only years after 4713 B.C. are supported, so 'year' must be greater than or equal to -4713).


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 );

Given a date in one calendar, and the number of days elapsed since that date (either positive or negative), this computes the resulting date in a (possibly different) calendar.

Counting starts at 0, so "0 days since" some date will return the original date, if the new calendar is the same as the original calendar. If the new calendar is different than the original calendar, using a count of ndays_since=0 will essentially translate dates between the original and new calendars. (If you don't want to translate dates between calendars, simply pass the same calendar as both the calendar_orig and calendar_new parameters.) Note that translating dates between calendars only works for the Julian and Gregorian calendars, since there is no agreed-upon convention for how to overlap the noleap and 360_day calendars with our actual historical calendars.

The function returns 0 on success, and a negative value on error. An error can include passing a null or uninitialized calendar, or an invalid year (only years after 4713 B.C. are supported, so 'year' must be greater than or equal to -4713).


int ccs_date2jday( calcalcs_cal *calendar, int year, int month, int day, int *jday );

Given an initialized calendar, and a Y/M/D date, this sets parameter "jday" to the Julian day of that date in the specified calendar. The Julian day is not the day number of the year, but rather the integer day number with counting starting at 1 Jan 4713 B.C. in the proleptic Julian calendar. For example, currently we are at Julian days numbering around 2,500,000.

Years B.C. are indicated by using negative year values. For example, -12 indicates year 12 B.C.

This routine returns 0 on success, and a negative number on error. Error values are defined below. Routine calcalcs_err_str, also described below, returns a pointer to a character string containing an error message. Errors can be generated by, for example, passing year 0 to a Gregorian or Julian calendar (which do not contain year 0); by passing the date of Feb 29th in a year that is not a leap year; or by being out of range (only dates after 4713 B.C. are supported).

This routine is in file calcalcs.c, and declared in header calcalcs.h.


int ccs_jday2date( calcalcs_cal *calendar, int jday, int *year, int *month, int *day );

Given an initialized calendar, and a Julian day number, this returns the Y/M/D date. The Julian day is not the day number of the year, but rather the integer day number with counting starting at 1 Jan 4713 B.C. in the proleptic Julian calendar. For example, currently we are at Julian days numbering around 2,500,000.

This routine returns 0 on success, and a negative number on error. Error values are defined below. Routine calcalcs_err_str, also described below, returns a pointer to a character string containing an error message. This routine is in file calcalcs.c, and declared in header calcalcs.h.


int ccs_date2doy( calcalcs_cal *calendar, int year, int month, int day, int *doy );

Given a Y/M/D date in some calendar, this returns the corresponding day number of the year. Numbering starts at 1 for January 1st.

This routine returns 0 on success, and a negative number on error. Error values are defined below. This routine is in file calcalcs.c, and declared in header calcalcs.h.


int ccs_doy2date( calcalcs_cal *calendar, int year, int doy, int *month, int *day );

Given a year and day number of the year (starting with January 1st = 1) in some calendar, this returns the corresponding date.

This routine returns 0 on success, and a negative number on error. Error values are defined below. This routine is in file calcalcs.c, and declared in header calcalcs.h.


int ccs_get_xition_date( char *country_code, int *year, int *month, int *day );

Most people know that our "Standard" (or "civil") calendar changed from the Julian calendar to the Gregorian calendar at some time in the past. However, different countries changed over on different dates. For example, the first day Italy used the Gregorian calendar was 15 Oct 1583, while the first day the United States colonies used the Gregorian calendar was 14 Sep 1752.

This routine returns the approximate Y/M/D date that the Gregorian calendar was first used for the country (or region) specified by the passed two-letter country code. You can then pass the transition date to routine set_cal_xition_date, described below, to produce a calendar appropriate to a specific country or region. Generally speaking, the country code is the same as the two-letter internet code for the country, with the exceptions described below.

Note that in many cases, different provinces or states in different countries changed at different times, and national borders have shifted over the centuries. So the values given by this call should only be considered general guidelines, not hard and fast dates for a particular location. Also, I have not consulted any original sources for these transition dates, but rather just collected them from the internet.

This routine returns 0 on success, and a negative number on an error, which typically means that the country/region code is not recognized. This routine is in file calcalcs.c, and declared in header calcalcs.h.

Recognized country/region codes and the transition date returned by this routine are described here.


int ccs_set_xition_date( calcalcs_cal *calendar, int year, int month, int day );

The passed calendar must be a "Standard" calendar. Then, this routine sets the transition date to be used for that calendar (i.e., the first day that the Gregorian calendar is used, with the Julian calendar being used prior to that) to the specified Y/M/D. You can obtain the transition date for the location you are interested in by doing research on your region, or get an approximate date by calling get_cal_xition_date(), described above.

This routine returns 0 on success, and a negative value on error. Errors include the specified date being out of range (only years after 4713 B.C. are supported) or a date that does not exist in the Standard calendar, such as March 35th, or February 29th in a year that is not a leap year. This routine is in file calcalcs.c, and declared in header calcalcs.h.


char *ccs_err_str( int errno );

This routine returns a pointer to a static memory location with a descriptive error message, if one of the calcalcs routines returns an error (value less than zero). This routine is in file calcalcs.c, and declared in header calcalcs.h.

If passed error number "0" (i.e., no error) the error message will include the current version of the CalCalcs routines.

 

Error Codes


These symbolic error codes are defined in the header file calcalcs.h.


CALCALCS_ERR_NO_YEAR_ZERO

Several important calendars have no year zero. For exaple, the Gregorian, Julian, and Standard calendars all transition from December 31st, 1 B.C. to January 1st, 1 A.D. with no "year 0" intervening. This error is returned if a date with year equal to 0 is given to a calendar that lacks a year 0.


CALCALCS_ERR_DATE_NOT_IN_CALENDAR

This error is returned if a date is given for a calendar that lacks that date. For example, March 35th does not occur in any calendar, and so passing that day to the calcalcs routine will always trigger this error.

You can also get this error if you pass February 29th in a year that is not a leap year in the given calendar. For example, the date February 29th, 2001 is not a valid date in the Gregorian calendar and will return this error.


CALCALCS_ERR_INVALID_DAY_OF_YEAR

This will be returned if the passed day of the year is invalid. For example, a day of year of 367 is always invalid. Note that transistion years in the Standard calendar (i.e., the year during which the switch from the Julian to Gregorian calendar was made) can have an unusual number of days of the year. So, for example, day-of-year number 364 can be invalid if using the Standard calendar and a year of 1582.


CALCALCS_ERR_NOT_A_MIXED_CALENDAR

Routine ccs_set_xition_date can only be called with a mixed calendar, i.e., one that transitioned from one calendar to another on a particular date. At the moment, only the Standard calendar is a mixed calendar. If ccs_set_xition_date is called with a calendar that is not a mixed calendar, this error is returned.


CALCALCS_ERR_UNKNOWN_COUNTRY_CODE

This error is returned if ccs_get_xition_date is called with an unknown country code. Note that if routine ccs_init_calendar is called with a calendar name that specifies a country code by an undersocre and appeneded two-letter code (for example, "Standard_UK") and the two-letter code is not recognized, then NULL is returned instead of this error code. However, the error string returned by ccs_err_str will note this problem.


CALCALCS_ERR_OUT_OF_RANGE

The calcalcs routines only support positive Julian Days, which means dates after 4713 B.C. If an earlier date is given, or a negative Julian Day, this error is returned. (Note that Julian Days are the integer day number counting since 4713 B.C., and not the day-of-year number, which is between 1 and 366).


CALCALCS_ERR_NULL_CALENDAR

This error is returned if a calcalcs routine is called with a NULL pointer for the calendar.


CALCALCS_ERR_INVALID_CALENDAR

This error is returned if the calcalcs routines recognize that an invalid, previously-freed, or corrupted calendar is passed.




(C) 2010 David W. Pierce