ID: 9076
User Update by: [EMAIL PROTECTED]
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] [EMAIL PROTECTED]
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] [EMAIL PROTECTED]
Ill look at these patches at some point soon.
- James
---------------------------------------------------------------------------
[2001-02-09 07:15:34] [EMAIL PROTECTED]
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] [EMAIL PROTECTED]
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
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]