php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #9076 GregorianToJD function returns incorrect values
Submitted: 2001-02-02 11:05 UTC Modified: 2001-05-17 08:12 UTC
From: basil dot hussain at specialreserve dot net Assigned:
Status: Closed Package: Calendar related
PHP Version: 4.0.4pl1 OS: RedHat Linux 6.2 (kernel 2.2.18-
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: basil dot hussain at specialreserve dot net
New email:
PHP Version: OS:

 

 [2001-02-02 11:05 UTC] basil dot hussain at specialreserve dot 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!

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-02-09 07:15 UTC] basil dot hussain at specialreserve dot 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-04-29 05:50 UTC] jmoore@php.net
Ill look at these patches at some point soon.

- James
 [2001-05-13 07:35 UTC] jmoore@php.net
I cant reproduce this at all.. 

The following script:
<?php

$jd = GregorianToJD (02,02,2001);
echo "$jd\n";
$gregorian = JDToGregorian ($jd);
echo "$gregorian\n";
      
$jd = GregorianToJD (7,6,1980);
echo "$jd\n";
$gregorian = JDToGregorian ($jd);
echo "$gregorian\n";

?>

Gives this output..
D:\cvs\php4\Release_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-05-17 08:12 UTC] basil dot hussain at specialreserve dot net
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.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 27 12:01:29 2024 UTC