/* * dayslib.c * * Small library to handle dates. The algorithms are mostly from Pascal's SWAG. * * History: * 1/11/03 Creation from the old sources of ohdatabank. * 8/01/04 Fix the yday2wday() function. Also generalize the formula * for a wider range of years (that is, pass the 2099 barrier). * 15/09/06 Fix some comments, protect the macro GetYearDays. * * Author: Dario Rodriguez dario@softhome.net * This code is dual licensed under the terms of the GNU LGPL/3-clause BSD. */ /* Constants */ const int __NAcDaysNoLeap[13]= {0,31,59,90,120,151,181,212,243,273,304,334,365}; const int __NAcDaysLeap[13]= {0,31,60,91,121,152,182,213,244,274,305,335,366}; int * GetYearDays(int year) { return(((((year)%4)==0 && !(((year)%100)==0)) \ || ((year)%400)==0)?__NAcDaysLeap:__NAcDaysNoLeap); } /* Function prototypes */ int yday2mday(int year, int yday, int *month, int *day); int mday2yday(int year, int month, int day, int *yday); int yday2wday(int year, int yday, int *wday); /* Function bodies */ /* yday2mday(): returns the day-in-month of the specified day-in-year */ int yday2mday(int year, int yday, int *month, int *day) { const int *NAcDays; NAcDays=GetYearDays(year); for(*month=1;yday>NAcDays[*month];(*month)++) ; *day=yday-NAcDays[(*month)-1]; return(year); } /* yday2mday(): returns the day-in-year of the specified day-in-month */ int mday2yday(int year, int month, int day, int *yday) { const int *NAcDays; NAcDays=GetYearDays(year); *yday=NAcDays[month-1]+day; return(year); } /* yday2mday(): returns the weekday (0:sunday) of the specified day-in-year */ /* Warning: formula only valid for 1900- */ int yday2wday(int year, int yday, int *wday) { #if 0 /* Simplified formula, valid only 1901-2099 */ *wday=(((year+3)/4)+year+4+yday)%7; #else /* Full-blown formula, valid from 1900 onwards */ /* (ok, it works for years earlier to 1900, but I'm not sure when */ /* Also, it varies from country to country when they adopted the */ /* current calendary... see your encyclopaedia for more info on this).*/ *wday=(((year+3)/4)+year+4+yday-((year-1)/100-19)+((year-1)/400-4))%7; #endif return(year); } #ifdef UNIT_TESTING #include <stdio.h> int main(void) { struct { int day; int month; int year; int wday; } Tests[]={{1,1,2003,3},{31,12,2003,3},{1,1,2004,4},{1,2,2004,0},{1,3,2004,1}, {1,1,2000,6},{1,1,2001,1},{1,1,2002,2},{1,1,2003,3},{1,1,2004,4},{1,1,2005,6}, {1,1,2099,4},{1,1,2100,5},{1,1,2101,6},{1,1,2102,0},{1,7,2087,2}, {1,1,1897,5},{1,1,1898,6},{1,1,1899,0},{1,1,1900,1},{1,1,1901,2}, {12,10,2008,0},{0}}; long i; int day,month,year,wday; int resyday,reswday; for(i=0;Tests[i].day>=1;i++) { day=Tests[i].day,month=Tests[i].month; year=Tests[i].year,wday=Tests[i].wday; mday2yday(year,month,day,&resyday); yday2wday(year,resyday,&reswday); printf("%2i/%02i/%04i(%i) -> yday:%i,wday:%i... %s\n",day,month,year,wday,resyday,reswday,(wday!=reswday)?"ERROR":"Ok"); } return(0); } #endif