Movatterモバイル変換


[0]ホーム

URL:


 
 

craig-date

[ Originally pubished in Datafile, Vol 10 No 8, December 1991, page16. ]     DAY NUMBER ROUTINES USING INTEGER ARITHMETIC Craig A. Finseth (member number ???)I have seen numerous articles on routines for converting dates to daycount (typically Julian) and back again.  These articles have coveredvarious HP calculators and all used the usual HP arithmetic.  However,I recently had to solve this problem in a program for the 95LX in aslightly different way: using 32-bit integer arithmetic.  The resultsare interesting.  The problem has six parts which cover conversion ineach direction for 360 day, 365 day, and actual calendars.GENERALI chose the day range to be from 1 January 1583 through 31 December9999.  This carefully avoides the Gregorian / Julian calendar questionfor most of the world, anyways.I also chose to count days starting from 1 January 1 in the Gregoriancalendar.  This is not a Julian day number, but differs by a constant.The examples are written in mostly-Basic, assuming integer arithmetic.CONVERTING FROM A DAY / MONTH / YEAR TO A DAY NUMBERInput: year (1583 - 9999), month (0 - 11), day (1 - 31)Output: daynmdays is an array of cumulative days.  mdays(0) = 0, mdays(1) = 31,mdays(2) = 31 + 28, etc.  This array has thirteen entries, somdays(12) = 365.360 day calendar.  This is easy.dayn = 360 * year + 30 * month + day - 1365 day calendar.  This is easy, too.dayn = 365 * year + mdays(month) + day - 1Actual calendar.  This starts like 365 day calendar:;dayn = 365 * year + mdays(month) + day - 1Then Jan and Feb get previous year's leap year counts.if month <= 1 then year = year - 1dayn = dayn + year / 4! add leap yearsdayn = dayn - year / 100! subtract non-leap centuriesdayn = dayn + year / 400! add back 400 yearsCONVERTING FROM A DAY NUMBER TO A DAY / MONTH / YEAROutput: daynInput: year (1583 - 9999), month (0 - 11), day (1 - 31)mdays is as above.360 day calendar.  This is easy.year =  dayn / 360month = mod(dayn, 360) / 30day =   mod(dayn, 30) + 1365 day calendar.  This starts to get tricky.year = dayn / 365dayn = mod(dayn, 365)for month = 0 to 12 step 1if dayn < mdays(month + 1) then goto outnext monthout:day = dayn - mdays(month) + 1Actually, the loop will never get month to 12.  At some point beforethen, the cumulative days of the next month will be greater than theday number.  Remember that dayn must be in the range 0 to 364 due tothe mod and that mdays(12) = 365.Actual calendar.  This gets REALLY tricky and is to a large extent theentire reason for the article.We have a day number in the range 0 to 3 600 000 (= 365 * 10 000).What we want to do is to divide this number by 365,2422 to get veryclose to the correct year (+/- 1).  We must do this with integerarithmetic, so we multiply by 10 000 and divide by 3 652 422.But multiplying a day number by 10 000 exceeds a 32-bit integer(roughly 36 000 000 000 vs. about 2 100 000 000).  We have to reducethe 10 000 by a factor of 20 or so in order not to overflow.If we call the orgininal number 365,2425 and so get 10 000 and 3 652425 as the numerator and denominator, we can remove a factor of 25 andobain 400 and 146 097.  We thus no longer overflow our integer.This works but is incorrect to the tune of 3 parts in (roughly) 3 000000 or 1 in 1 000 000.  As there are only about 2 500 leap year daysthat can foul things up, we are still close enough.  Later steps willcorrect any error.temp = dayn * 400temp = temp / 146097Now the corrections start.  First, make sure that we are before thecorrect year.  In theory, we can be off by up to one year, so let'ssubtract two to be on the safe side.year = temp - 2Now, we count up until we get to the correct year.month = 0;day = 1;for i = 0 to dayn step 0i = ToDayNumber(year, month, day, "actual")if i = dayn then return! we are doneyear = year + 1next idone:year = year - 2This loop calculates the day number for 1 January of each year untilit surpasses our day number.  At that point, we have to subtract one>from the year because we have, in fact, passed the correct year andanother one because we incremented the year before we tested.Of course, if the day number matches exactly, the date is for 1January and we can stop here.We now have the correct year. On to the month and day.  Subtract offthe day number of 1 January so that we have a number in the range 0 to365 (if leap year).dayn = dayn - ToDayNumber(year, month, day, "actual")Check for January.if dayn < mdays(1) thenday = dayn + 1return! doneendif! I said this was mostly-BasicCheck for up to Febuary 28.if dayn < mdays(2) thenmonth = 1day = dayn - mdays(1) + 1returnendifSo, our date must either be 29 Febuary (if we have a leap year) orsome day after that.  See if we are a leap year.if year / 4 = 0 and(year / 100 <> 0 or year / 400 = 0) then ! we have a leap yearif dayn = mdays(2) thenmonth = 1day = 29returnendifdayn = dayn - 1! not 29 Feb, so convert it toendif! a non-leap year dayfor month = 2 to 12 step 1if dayn < mdays(month + 1) then goto outnext monthout:day = dayn - mdays(month) + 1And that's it.  I hope that you found this as interesting to read as Idid to write (both the program and the article).

Areas

General

Craig's Articles

 

Google

 
 

I amCraig A. Finseth.

Back to Home.

Back to top.

Last modified Saturday, 2012-02-25T23:29:03-06:00.


[8]ページ先頭

©2009-2026 Movatter.jp