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 this is not your bug, you can add a comment by following this link.
If this is your bug, but 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

Add a Patch

Pull Requests

Add a Pull Request

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 Apr 19 08:01:28 2024 UTC