Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!cs.utexas.edu!sun-barr!olivea!mintaka!bloom-beacon!eru!hagbard!sunic!mcsun!ukc!ox-prg!msc7.comlab!imc From: imc@prg.ox.ac.uk (Ian Collier) Newsgroups: comp.lang.c Subject: Re: Request for simple date routines. Message-ID: <718.imc@uk.ac.ox.prg> Date: 19 Apr 91 16:52:34 GMT References: <1991Apr9.234255.143@mprgate.mpr.ca> Sender: news@prg.ox.ac.uk Reply-To: imc@prg.ox.ac.uk (Ian Collier) Organization: Oxford University Computing Laboratory, UK Lines: 67 I don't know whether you've had an answer or not (I haven't read one in this newsgroup), so... In article <1991Apr9.234255.143@mprgate.mpr.ca>, stone@mars.mpr.ca (Darren Stone) wrote: >Hi. Just a simple request I hope somebody can >easily pull out of their toolbox... Well,... I've written date routines before (in REXX & BASIC, of all languages!), and most of them have turned out to be wrong. But I just fixed one of them, so it should be OK now. With any luck :-) >I'd like a function which, given a date, returns >0..6 representing the day of the week of the date. >I'd also like a function which, given 2 dates, >returns the number of days between them. >I really don't care at all about efficiency, but >they must work absolutely reliably for +/- several >hundred years. They should work for any date since the invention of the modern calendar. However, since I have no real way of telling whether May 21st 1832 was actually a Monday, I can't guarantee it :-) I solved both problems by assigning a number to each date (essentially the number of days since Jan 1, 1 A.D., although of course that date is meaningless in practice). So if you have dates d1 and d2, which give rise to numbers n1 and n2, then there are n2-n1 days between them, and moreover n1 mod 7 gives you the day of the week of d1. You don't need to store the dates really, just the numbers. First, define a couple of functions. let leap(y) = (y%4==0) && (y%100!=0) || (y%400==0) let days(y) = ((y-1)*1461)/4 - (3+3*((y-1)/100))/4 /*long integer arithmetic*/ which is (I hope) equivalent to int(365.25*(y-1)) + int(-.75*int((y-1)/100)) where int(x) is the greatest integer which is no more than x, so that days(y) is the number of days before year y (the right-hand half accounts for the leap year rule for multiples of 100). This is the really-important-function :-) Let an array m indexed from 0 to 11 hold the number of days in each month. To turn a date (day,month,year) into a number n, do: if(year<100) year+=1900; n=days(year)+day-1; m(1)=28+leap(year); for(x=0;x Monday - Sunday */ year=(n*4)/1461 +1; day=n-days(year); while(d>=365+leap(year)) day-= 365=leap(year++); m(1)=28+leap(year); day++; for(month=0;day>m(month);day-=m(month++)); month++; The maximum number of times around the while loop is 2, at least within the next few millenia :-) Ian Collier Ian.Collier@prg.ox.ac.uk | imc@ecs.ox.ac.uk