Bug #9076 Updated: GregorianToJD function returns incorrect values

From: Date: Thu, 17 May 2001 12:12:25 +0000
Subject: Bug #9076 Updated: GregorianToJD function returns incorrect values
Groups: php.dev 
Request: Send a blank email to php-dev+get-55605@lists.php.net to get a copy of this message
ID: 9076 User Update by: basil.hussain@specialreserve.net Status: Closed Bug Type: Calendar related Operating system: RedHat Linux 6.2 (kernel 2.2.18- PHP Version: 4.0.4pl1 Description: GregorianToJD function returns incorrect values Okay, this gets stranger and stranger... > Gives this output.. > D:\cvs\php4\Release_TSDbg>php -q test.php > 2451943 > 2/2/2001 > 2444427 > 7/6/1980 Oops, you had the month and day the wrong way round for the second case - should be 2444398. But, I noticed you were testing using the Windows version and so I ran exactly the same script (corrected, naturally) on my Windows version of 4.0.4pl1 and got correct results. Weird! It definitely gives incorrect results on Linux. However, as I said in the first place - this *shouldn't* be anything to do with which version of PHP, how it was compiled or on which platform - the maths in the GregorianToSdn function in gregor.c is just *wrong*. To prove this, take your pocket calculator and let's work through the algorithm for the date 7th June 1980. Here we go: y = 1980 m = 6 d = 7 m > 2 therefore m = m - 3 giving m = 3 y >= 0 therefore y = y + 4800 giving y = 6780 jd = ((y / 100) * 146097) / 4 + ((y mod 100) * 1461) / 4 + ((m * 153) + 2) / 5 + d - 32045 jd = ((6780 / 100) * 146097) / 4 + ((6780 mod 100) * 1461) / 4 + ((3 * 153) + 2) / 5 + 7 - 32045 jd = (67.8 * 146097) / 4 + (80 * 1461) / 4 + (459 + 2) / 5 + 7 - 32045 jd = 9905376.6 / 4 + 116880 / 4 + 461 / 5 + 7 - 32045 jd = 2476344.15 + 29220 + 92.2 + 7 - 32045 jd = 2473618.35 I'm no maths expert, but this is nothing more than elementary mathematics and the algorithm is clearly giving the wrong result! I have no idea how it gets the right result on Windows - by rights it shouldn't - unless the Windows version uses a different library for calender functions (i.e. not gregor.c). What I think also needs to be investigated now is why the Windows version gives the results it gives, because the algorithm is wrong. Previous Comments: --------------------------------------------------------------------------- [2001-05-13 07:35:24] jmoore@php.net I cant reproduce this at all.. The following script: <?php $jd = GregorianToJD (02,02,2001); echo "$jdn"; $gregorian = JDToGregorian ($jd); echo "$gregoriann"; $jd = GregorianToJD (7,6,1980); echo "$jdn"; $gregorian = JDToGregorian ($jd); echo "$gregoriann"; ?> Gives this output.. D:cvsphp4Release_TSDbg>php -q test.php 2451943 2/2/2001 2444427 7/6/1980 which is what I would expect. Please reopen bug report if I am wrong (and point out why I am wrong). Also if your system still displays incorrect dates with latest cvs or 4.0.6RC1 please reopen too giveing more information about your system. - James --------------------------------------------------------------------------- [2001-04-29 05:50:00] jmoore@php.net Ill look at these patches at some point soon. - James --------------------------------------------------------------------------- [2001-02-09 07:15:34] basil.hussain@specialreserve.net I found more thoroughly-researched algorithms for calculating to and from Gregorian/Julian calender dates to Julian Day Count values: http://www.capecod.net/~pbaum/date/date0.htm I suggest that the PHP Calender functions be based upon the algorithms here, as meticulous care seems to have been taken to formulate and proof them. In the meantime, I have written my own implementations of the GregorianToJD and JDToGregorian functions in PHP. I have tested them using the examples in Table 2 of Chapter 1 of Baum's work and they pass. function php_gregoriantojd($input_year, $input_month, $input_day) { // Make sure supplied arguments are of the correct form. Day may be a fractional value, // but month and year must be integers. $input_year = intval($input_year); $input_month = intval($input_month); $input_day = doubleval($input_day); // Adjust the start of the year so that it is in March. if($input_month < 3) { $input_month += 12; $input_year -= 1; } // Calculate and return the Julian Day Count. return $input_day + floor((153 * $input_month - 457) / 5) + 365 * $input_year + floor($input_year / 4) - floor($input_year / 100) + floor($input_year / 400) + 1721118.5; } function php_jdtogregorian($jdc) { // Make sure that the Julian Day Count value is proper. $jdc = doubleval($jdc); $z = floor($jdc - 1721118.5); $r = $jdc - 1721118.5 - $z; $g = $z - 0.25; $a = floor($g / 36524.25); $b = $a - floor($a / 4); $gregorian["year"] = floor(($b + $g) / 365.25); $c = $b + $z - floor(365.25 * $gregorian["year"]); $gregorian["month"] = floor((5 * $c + 456) / 153); $gregorian["day"] = $c - floor((153 * $gregorian["month"] - 457) / 5) + $r; if($gregorian["month"] > 12) { $gregorian["year"] += 1; $gregorian["month"] -= 12; } return $gregorian; } The line breaks on all of that will probably be all mangled when I post, but it should make sense when straightened out... --------------------------------------------------------------------------- [2001-02-02 11:05:26] basil.hussain@specialreserve.net The GregorianToJD Calender function returns incorrect results. As far as I can tell, this applies to the GregorianToSdn internal function in the PHP source. There's not really any point putting a sample PHP script here, as it's the algorithm that seems to be at fault. I took two specific cases and worked through the algorithm by hand (i.e. pen and paper). Here are the results: 2nd February 2001 (2/2/2001) = 2451943 7th June 1980 (7/6/1980) = 2473618 As I understand it, the Julian Day Count is a uniform count of days from some time around 4714 BC. Now, how can 2/2/01 be a lesser number of days than 7/6/80? I have no idea what the correct results for these test cases are, nor any idea what particular part of the algorithm is wrong. It's just wrong somewhere! --------------------------------------------------------------------------- Full Bug description available at: http://bugs.php.net/?id=9076

« previous php.dev (#55605) next »