php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #52744 cal_days_in_month incorrect for December 1 BCE
Submitted: 2010-08-30 18:16 UTC Modified: 2010-09-09 08:41 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: gpap at internet dot gr Assigned: aharvey
Status: Closed Package: Calendar related
PHP Version: 5.3SVN-2010-08-30 (snap) OS: all
Private report: No CVE-ID:
 [2010-08-30 18:16 UTC] gpap at internet dot gr
Description:
------------
Function cal_days_in_month returns wrong result for December 1 BCE:

echo cal_days_in_month(CAL_GREGORIAN, 12, -1) returns -1721395
echo cal_days_in_month(CAL_JULIAN, 12, -1) returns -1721393

The function uses julian day count internally to calculate the day count 
difference between the 1st day of the supplied month and the 1st day of the next 
month. The next month of December 1 BCE (year -1) is January 1 CE (year 1, there 
is no year zero).

But when cal_days_in_month calculates the next year as year+1, it does not check 
for year zero, so it tries to calculate the julian day for 1st January 0, which 
returns 0 and consequently the wrong result of days in December 1 BCE is 
returned.

actual function code taken from latest svn snapshot php5.3-201008301230 
(/ext/calendar.c):

-----------------------
PHP_FUNCTION(cal_days_in_month)
{
        long cal, month, year;
        struct cal_entry_t *calendar;
        long sdn_start, sdn_next;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &cal, 
&month, &year) == FAILURE) {
                RETURN_FALSE;
        }

        if (cal < 0 || cal >= CAL_NUM_CALS) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID 
%ld.", cal);
                RETURN_FALSE;
        }

        calendar = &cal_conversion_table[cal];

        sdn_start = calendar->to_jd(year, month, 1);

        if (sdn_start == 0) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid date.");
                RETURN_FALSE;
        }

        sdn_next = calendar->to_jd(year, 1 + month, 1);

        if (sdn_next == 0) {
/* if invalid, try first month of the next year... */
                sdn_next = calendar->to_jd(year + 1, 1, 1);
        }

        RETURN_LONG(sdn_next - sdn_start);
}
-----------------------

The following correction is proposed:

-----------------------
 	if (sdn_next == 0) {
 /* if invalid, try first month of the next year... */
-		sdn_next = calendar->to_jd(year + 1, 1, 1);
+		if (year == -1) {
+			sdn_next = calendar->to_jd(1, 1, 1);
+		} else {
+			sdn_next = calendar->to_jd(year + 1, 1, 1);
+		}
 	}
-----------------------

Test script:
---------------
<?php
// returns -1721395 instead of 31
echo cal_days_in_month(CAL_GREGORIAN, 12, -1);

// returns -1721393 instead of 31
echo cal_days_in_month(CAL_JULIAN, 12, -1);
?>

Expected result:
----------------
31
31

Actual result:
--------------
-1721395
-1721393

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-09-09 08:02 UTC] aharvey@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: aharvey
 [2010-09-09 08:41 UTC] aharvey@php.net
Automatic comment from SVN on behalf of aharvey
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=303203
Log: Fixed bug #52744 (cal_days_in_month incorrect for December 1 BCE). Original
patch by gpap at internet dot gr.
 [2010-09-09 08:41 UTC] aharvey@php.net
-Summary: cal_days_in_month +Summary: cal_days_in_month incorrect for December 1 BCE -Status: Assigned +Status: Closed
 [2010-09-09 08:41 UTC] aharvey@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Thank you very much for the patch!
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Thu Apr 24 19:01:53 2014 UTC